Updated Proposal: Revisiting Implicits

Oh, yes, that is pretty unreadable. I agree; we’d better stick with as. If aliases were limited to simple values, it would be different. But aliases to methods do seem inordinately hard to parse.

Too bad! It had seemed quite promising.

given Context {
  ...
}

At first glance I would like that ‘as’ were mandatory.

given  as Context {
  ...
}

It is easy for cursory reading.
But it is not very convenient if the most “given” are anonymous.

So may be it will be better if naming-conventions require that names must be in lower camel case

Yes, I think that’s a useful convention that can help here.

What would the

given t3[T, U, V](using st: Show[T], su: Show[U], sv: Show[V]): Show[(T, U, V)] {}

example look like in this notation?

I guess it’d look somewhat like this.

given t3 as [T, U, V] => (Show[T], Show[U], Show[V]) ?=>  Show[(T, U, V)] {}

given t3 as [T, U, V] => (Show[T], Show[U], Show[V]) => Show[(T, U, V)] {}

Yep, as could still be used there if the given is not anonymous, if we don’t like : from 0.21, would actually prefer as with named givens.

My opinion is that the => syntax is by itself quite appealing, but the overall loss of regularity is not worth it. Right now type parameters and context parameters look the same no matter whether they are in methods or given instances. That’s a big advantage that must be weighed against more specialized solutions.

3 Likes

What if we add using?

given t3 as [T, U, V] => (using Show[T], Show[U], Show[V]) => Show[(T, U, V)] {}

now type parameters and context parameters look the same no matter whether they are in polymorphic functions or given instances [1][2]

Methods have about as much to do with givens as polymorfic functions do, isn’t the updated version equivalent then in terms of regularity?


[1] kinda feels like context functions might be getting into the scope of discussion and I’m not sure how that affects any of the arguments

[2] took a brief look at context functions, ?=> is now apparently a thing. @Jasper-M I thought you made a typo :slight_smile:

in light of my discovery of another piece of new syntax, maybe ?=> instead of using? Does my above argument still hold? Feels like it does, but not sure.

given t3 as [T, U, V] => (Show[T], Show[U], Show[V]) ?=> Show[(T, U, V)] {}

edit: tentative updated argument:

Methods have less to do with givens then context functions, isn’t the updated version more regular then?

edit2: I guess this has more of a chance to be garbage than my first message :slight_smile: Well, not a language designer, just trying to express my intuition about the options in hopes to get closer to a possible ideal state if there’s one out there

All of it is more obscure than what we have. I believe we have the best combination of clarity and regularity already.

2 Likes

Just throwing an idea… Since the most important part of a given is the type, what about having it before everything else?

given Result as someThing[A, B <: A](using SomeThingElse[A, B]) = ...
1 Like

The ?=> syntax has not been discussed in this thread before, first mentioned in #407, however it’s already made a default: Add Syntax Changes document by odersky · Pull Request #8301 · lampepfl/dotty · GitHub

It looks very obscure to me, especially at the declaration site – this is the first time that a new form of arrow is available for lambda declarations and I don’t think it’s justified. What was wrong with the previous syntax:

(using a: A[T], b: B[T]) => (t: T) => a.x(t)

?

2 Likes

Good point. This should be discussed. I believe the type ?=> has a clear advantage since it makes it easier to distinguish between

def f(x: A ?=> B)

and

def f(using x: A => B)

The previous scheme

def f(x: (using A) => B)

is too close to that for comfort, in particular when things get more complicated. But the syntax for types does not necessarily have to be the same as the syntax for terms. It’s a question which symmetry we choose: should the type/term form of context functions look the same, or should context parameters look the same for methods and lambdas?

So the argument shifts from “more regular” to “less obscure/more familiar”

That’s true. However, these options are not just more obscure, they are not yet existent out there in production code, and the amount of uptake might be surprising.

From your Plain Functional Programming talk:

def readAge: config => Option[Age] = c => ???

but even

val readAge: config => Option[Age] = c => ???

Not the usual way to write Scala but apparently some people already prefer this even in Scala 2, and it will be made easier and more powerful with the upcoming changes. Ones already mentioned here and others, such as “top level everything”.

Maybe the popularity of these features will surprise in which case your argument will end up not being a valid one. I guess what I’m trying to point out is that the obscurity argument is not based on observation, since there isn’t enough code written by a diverse enough set of authors to make such conclusions.

does this syntax extend to multiple arguments and mixing given and plain arguments? Would be nice to have functions/lambdas that are equivalent in power / can express everything that methods can.

1 Like

I feel uneasy about the ?=> syntax, in this case I might prefer more regularity. The only annoying thing is that

def f(x: (using A) => B)

is more noisy than I would prefer, but that on itself doesn’t feel to be enough of a justification.

When the => syntax for givens was introduced you counterargued to this same argument saying that this is a very uncommon use case (if not outright an antipattern), and that simple things should be easy and complex things possible. Something along these lines. Now I don’t necessary like how close these 2 are either, but I think your argument was valid back then and it is still valid now.

1 Like

The aspect that guided almost all recent syntax decisions was the empirical experience. Between compiler, library, tests and community build we usually have many hundreds of occurrences of each construct. That’s a great way to test and adjust our assumptions. In this case, the adjustment was: context function types are not that rare (and should become more common once they are better known) and that writing using (or given at the time) makes them quite hard to read. So I had to revise my earlier assumptions.

The whole process has actually been really interesting. I believe it is quite rare to be able to do this kind of empirical language design.

3 Likes

Sounds like a great source of input and I’m glad that it contributes to the quality of Scala 3!

If the experience with ?=> is positive then great, sounds like that extra noise of givens/usings is more annoying than I thought.

2 things on my mind:

1

Not sure what effect it has on my question wrt. power equivalence of methods and functions. Or if such equivalence is a goal to begin with. Or if it could be made into a goal, if not already. I would find it both useful and logically consistent, or maybe aesthetic.

2

This to me sounds very supportive of…

…of my argument to not base decisions wrt. given syntax on anticipated (subjective) obscurity since the same syntax in other areas (e.g. context functions as confirmed by you, polymorphic functions) might become much more popular than anticipated rendering it less/not (subjectively) obscure.

edit: even if I might have overstated the lack of production code, that argument seems to me to hold and being supported by what you shared

IMHO the current result is much more better.

Could you explain. why is it worse to have:

lower camel case for names of given instances at grammar level?

It is just reduce amount of different styles.

the ability to define a need to create fresh instance on each reference without dummy names

      given laterInit[_] as Context = ....
      given laterInit[] as Context = .... 
      given laterInit() as Context = .... 

I can imagine that there are no differences for the compilator at all. But I am sure dummy names will confuse people at first

Huh. A ?=> B is the symbolic form of PartialFunction[A, B] in my world. :laughing:

2 Likes