Switch order of type and term in `as` definitions?

The more I look at it, the more I think the former syntax is better. It is visually more distinct what part of the definition is what - name, parameters (by using using), return type - compared to arrows to arrows to arrows. I also expect all these arrows won’t be appreciated by the large part of the Scala community that are not active on forums like these. More symbolic operators make it look more arcane and I expect also harder to explain.

Since we also don’t have much time to get to use this syntax and tweak it further based on experience I am not in favor of introducing this change.

2 Likes

In my very humble opinion the new proposed syntax does a better job at setting givens apart as a distinct feature. The current syntax looks a bit like a word salad that wants to be different from a regular def but doesn’t quite manage it yet. You have given, then something method-like with a redundant using that seems to be inherited from implicit def when it was still possible to have both implicit and explicit parameters. Then instead of being consistent and going with the method-like thing and writing the type ascription with a : there’s the out-of place as—which apparently only exists because : conflicts with the optional “optional braces” thing.

I’m being a bit hyperbolic for the sake of the argument here.

4 Likes

I understand the reasoning and I agree that it’s good to have givens be distinct from normal functions/methods. I just think that all these arrows will make it hard for new developers / scala 2 developers to see what’s exactly going on.

given [T] => Ord[T] => Ord[List[T]] as listOrd = ...

Intuitively I think this looks more like a curried function from some generic T to a Ord[T] to a List[Ord[T]] instead of: I have some generic T, I expect an Ord for that T, and I will give you a Ord[List[T]].

I wouldn’t mind toying with some more ideas, but there is very little time for feedback/experimenting with these ideas. And I think what we have now is good enough (even if there are always things to improve).

4 Likes

Well you don’t have a T. The arrow-based syntax says precisely what it should: give me a T, give me an Ord[T], and I’ll give you an Ord[List[T]]. This can be understood following the usual Curry-Howard isomorphism: the given declaration is a constructive proof that if you have some T and some Ord[T], then there exists a corresponding Ord[List[T]] value. This is in line with how implicits have been used for automatically synthesizing type-level proofs. Fittingly, the fat arrow looks like mathematical implication.

1 Like

What if the as keyword is replaced by something else, without changing the syntax structure?

given foo is Foo[A]
given foo(using Context) is Foo = ???
case foo is Foo() =>
// or
given foo naming Foo[A]
given foo(using Context) naming Foo = ???
case foo naming Foo() =>
// or
given foo for Foo[A]
given foo(using Context) for Foo = ???
case foo for Foo() =>

So my poll was almost a draw. 12 votes for existing syntax vs 14 for new. Which tells me that neither syntax is fully convincing.

One interesting question is whether the given syntax should be consistent with the rest or intentionally different. My tendency would be to say it should be consistent as long as it does not give up any benefits.

With that in mind, I have explored a different way of doing things that is even more consistent than the current syntax. In particular, it drops as in favor of :.

I won’t copy the very long PR message here but comments are welcome on this thread.

21 Likes

I really like this. Best proposal I’ve seen so far, IMO. Much more consistent.

8 Likes

Yes!!! Although I like to lurk and skim, I often don’t devote much mental power. For I think the last 2 years or so, I’ve been looking at the various given syntax proposals but in my low-mental-power mode I found nearly all of it unclear and confusing. “I’ll pay attention when it’s finalised” I’d think. I just now read the new proposal and immediately found it very clear and very comprehensible, even in my 6am brain-dead state. I find it’s so much more consistent with all the other types of definitions that I’m used to in Scala, I love that term: Type is back in use here, and I love that the cost of changing definitions from implicit or not, is nice and small just like it is an Scala 2. So an emphatic :+1: from me.

16 Likes

100% agree with @japgolly. All in favour of this latest given syntax.

5 Likes

I love it! This is the best scheme I’ve seen so far. It should be easy to migrate to by Scala 2 developers and to teach to newcomers to Scala at large. Thank you Martin :clap:

7 Likes

Thank you Martin for reconsidering, this new syntax looks very good to me. I find it very readable, and also I didn’t like the double meaning of colon as line separator for indentation. :sunny:

3 Likes

Even with this proposal, colon is still used to mark indentation when defining a class/trait/object with the indentation syntax.

1 Like

What about marking these indentation separations using with as well? @odersky

4 Likes

Yay for consistency :slight_smile:

1 Like

Also, if we try to take this further and have colon only as a type separator, we also need a separator replacement for -Yindent-colons. I propose do. So:

locally do 
  println("this looks")
  println("much better")

I also think that with do, a single-line block could be supported so:

locally do println("this also should work")

(I also believe that using do, this will be less contended and we can get rid of the extra flag)

1 Like

We tested indentation markers at length with our courses last year. We tried: Nothing at all, with, and :. Colon was the clear winner. So we’ll stick with that.

5 Likes

Maybe, but that’s for untrained eyes only. Scala is not just the future, but also the past. Without tending to its past users, it has no future. Colon has always served as a clear type position indication.

1 Like

This latest iteration gets much more support than the previous ones. So I’ll go ahead with the PR with the aim to merge.

One open question is the status of as in patterns. Prefix or postfix? Or drop it entirely? Since we don’t see a clear preference, the prudent thing would be to drop them for now. Stick with @. We can always add them back later.

12 Likes

I vote for sticking with @.

12 Likes

In my opinion, one of the pattern options is much worse than the others: prefix as. With @ we share syntax with rust and Haskell. With postfix as we share syntax with python or ocaml.

With prefix we seem to be in less familiar territory.

I’d say stick with @ just to bias to no change when there is not a compelling reason.

3 Likes