The argument wasn’t about syntax in general, it was about redundant syntax, which doesn’t provide any expressiveness gain.
I very much prefer a language like Scala to say LISP or Haskell exactly for the reason that Scala has rich syntax and is keyword based. This makes scrolling though code so much easier! You don’t need to read carefully all the words on screen just to recognize different functional parts in the code. Especially in S-expression soup it’s really difficult to see anything. Even it has “very simple syntax”.
@Ichoran summarized the imho perfect solution in his previous post.
I still think the apply
proposal is a little bit “too magic” (even I have no issue with magic in Scala in general). But one would achieve the same with the type-class (and likely target typing) approach, just in a more controlled manner. It would add expressiveness to the language: You could “spread” tuples into some target type if you have the proper capability (type class) for that in scope.
Type-classes optionally enable features, and that’s the “usually” way to activate “magic” in Scala.
Having to use the spread operator would prevent the usual gotchas with implicit conversions.
So this would be a very controlled feature. No magic where it’s unexpected! (Which is imho the main issue with the apply
approach: It could trigger anywhere, as it would be always globally enabled; in contrast to the more controlled approach).
But both approaches share the property of adding a kind of powerful new feature to the language. Not just redundant syntax for Seq
and Map
, which is imho plain useless.
(Named)Tuples would become universally usable where some other types are expected, just by bringing a type-class instance into scope. Which would be safer than using implicit conversions, and simpler than using tuple type level programming to achieve the same convenience feature!
I think code like
perlinNoise(
seed = 0,
sideLength = 512,
layers =
(frequency = 2 , persistence = 0.5 )*,
(frequency = 10, persistence = 0.25 )*,
(frequency = 20, persistence = 0.125)*,
(frequency = 40, persistence = 0.125)*
)
looks really well.
For common cases like converting from (named)tuple to case class the compiler could provide the needed type-class instances, so just a simple import or some other one-liner would be sufficient.
But one could still use this feature to represent other types with shorthand syntax, which was core of the original idea. But to activate that magic one would need to write some type-class instance. I think that’s fair, a good balance of safety against surprises and ease of use. (Very similar to implicit conversions, actually!)
Regarding syntax once more: One needs to look at it in context. I think that’s very important. Like @megri said, if you have only List / Array and Map (which are in PHP even the same thing…) having dedicated syntax for that is indeed very natural. I think I said already that this (late!) syntax addition was a big win in PHP. But it simply wouldn’t be in Scala where you have much richer types.
Also any “familiarity” argument makes imho no sense. Beginners don’t know any syntax yet. For a beginner it’s very important that the syntax is logically consistent and unambiguous, but what it is concretely isn’t really important.
For people coming form other languages it also doesn’t matter. Scala is Scala, and not any other language. We have already some different syntax in contrast to some currently more mainstream languages, like […]
instead of <…>
, or value: Type
instead of type value
. But regarding the last example the fashion just changed, since Rust and Kotlin (and maybe Scala). If Scala would have picked up the most “familiar” syntax back than it would look like C++ / Java, right? But now it’s like Python? Or is it Rust?
Again internal consistency is more important here then mimicking any other language just because it’s currently more fashionable! Otherwise you end up like PHP, which is a Frankenstein monster of mixed syntax cobbled together from everywhere, exactly with the argument that it’s already “typical syntax for that feature”!
Especially as such trends come and go, and different languages have anyway different solutions. So for someone coming from Java or C++ using […]
for sequences would be very alien as the mentioned languages use {…}
for that (and I’ve heard rumors quite some people come from this Java thingy, no clue).
So this “familiarity” argument isn’t very strong really. (Except our target audience are JavaScript, Python, PHP, and Perl developers… Oh, and I forgot Swift. Apple developers are an easy target for Scala, sure. )
The situation in Scala would be more like the sequence literal from C++ which can instantiate richer types than Array. But this feature there is regarded more problematic than helpful… Especially as it is also “overloaded” syntax ({}
) so it’s hard to parse without looking at the context. Same would be the case for the confusing misuse of type syntax: Currently one can scroll though large batches of code and instantly recognize type parameters. By “overloading” the syntax this would be gone. (Syntax highlighting would help I guess, but still harder to parse visually).
Going the @Ichoran route instead of just adding some—in the context of Scala—very weird syntax just for Seq
and Map
would also include that other new (and likely exciting) feature @Odersky proposed earlier when discussing the type-class approach.
All in all this would look very good to me:
We get a new feature (“spreading” (named)tuples into other structured types), which would be still quite safe even a little bit “magic”, it would at the same time upgrade (named)tuples to an even more useful and powerful feature (nice and simple interaction with things like case classes and collections), and it would be a user extensible feature (through type classes) where you need the full magic power of “tuples as basic data structure literal for everything” (kind of like in the original proposal from @mberndt—just with a syntax that makes much more sense in the context of Scala, and no automatic like the old implicit conversions).
Also I think tooling would have less issues with a “recycled” “spread” syntax on tuples than changing fundamental things, like that […]
is reserved for types, which I guess was a strong assumption and is somewhere deeply backed in. (Just speculating, don’t know how that for sure)