I don’t think the problem in the above example is the trait part, but instead that you require that the translation be performed at runtime.
More specifically, Curried as I have understood it, like Dynamic, is structural in it’s behavior (you only implement the parts you want to support, instead of overriding methods from the Curried trait).
If so, then it becomes clear that none of the bad examples you provided would compile, as it can’t find the method to execute.
The trait Operation has no applyEnd or applyNext method, so the curried calls become compile time errors.
You could probably do something like you want above if we had Dotty’s inline defs.
Until line 2, the compiler knows the exact type which will be returned, but from line 2 on, the return value is just Operation, which extends Curried.
On line 3, either the compiler looks and sees that Operation doesn’t implement these directly, and fails to compile, or trusts that one of it’s subtypes will implement it (though it doesn’t know which one) and the code triggers a NoSuchMethodError at runtime.
So, I guess the problem isn’t that Operation extends Curried, it’s that the return type is dependent on the value passed. Overloading applyNext should work, because the compiler can trace the types, but I don’t know if there’s a way to do this for runtime values (or a good way to prevent this from happening).
If named-parameter arguments are to be supported, I think it makes a lot more sense to translate e.g. f(x = 1, y = "q") to f.applyBegin.applyNamed.x(1).applyNamed.y("q").applyEnd than it does to translate it to f.applyBegin.applyNamed("x", 1).applyNamed("y", "q").applyEnd. Making named parameters into selections allows you to have different types for different named arguments (otherwise you are right back to all the problems with the existing varargs). If you wanted the stringish behavior, you could easily recover it by making your applyNamed extend Dynamic.
But it’s subsumed by @clhodapp’s proposal, right? If you want literal types, you can always use Dynamic with a def applyDynamic[S <: String with Singleton](name: S)(...) or something like that, no?
I just realized that special treatment for named arguments or repeated arguments in this proposal is unnecessary. We can just pass through those arguments like this.
Then the library author is able to handle the parameter name k at runtime with help of a Dynamic, and handle s with the help of ordinary sequence arguments.
I think that, for named arguments, this is a good idea. It’s low-effort, and provides maximum flexibility as the author is able to either restrict the permissible named arguments by explicitly defining applyNext (which would appear to be the default), or accepting anything by mixing Dynamic with Curried.
I don’t think we can do this when splatting a collection, because the default behavior would be to not support s:_* syntax, which breaks the conceptual equivalence between Curried and regular varargs work.
The last SIP meeting ended up being private-only, but we did discuss this SIP. We will discuss again in public on November 27th, but here is nevertheless the gist of the feedback from the SIP committee.
There seem to be two main aspects for the motivation of the proposal: type safety and performance.
For type safety, we’re basically not very convinced that the use cases cannot be implemented using appropriate usage of implicit evidences and/or union types and/or HLists.
For performance, we believe that it should be possible to implement a forced expansion using macros, perhaps even just with inline in Scala 3.
Therefore, the feedback of the committee is that we think you should try and implement this using existing tools in the language.
A third-party library. Anything that can be outside of the stdlib should prove its value as a third-party library before it can apply for inclusion in the stdlib.
This is rather disappointing, as it severely curtails the ability of those of us who are in favor of these proposals to rebut these concerns.
While the next meeting will be public, the situation has become asymmetric. We’ll be working against a formed position (whatever you may claim to the contrary, the SIP is made up of humans, and that’s how the human brain works), rather than participating in the formation of that opinion.
A reason why this proposal might not be suitable in a 3rd party library is that it could be a dependency of other core features, including HList, collection initializers, string interpolations.
The string interpolators of the stdlib are already intrinsified by the compiler, and HLists (aka tuples in Scala 3) already eliminate all the overhead based on inline and IIRC match types. So both are already as efficient as possible.
In order for tuples to stand in for varargs, there needs to be some form of auto-tupling (ideally, opt-in at the definition site), else you need to write double parentheses at the call site. I brought this use case up on the auto-tupling removal thread (Let's drop auto-tupling). Unfortunately, unless something has changed, the frontrunner solution for opting in was removed as “not pulling its own weight” (https://github.com/lampepfl/dotty/pull/4311#issuecomment-381112023), which I feel like might have been due to confusion between present usefulness and potential future usefulness.