I noticed a problem with the verb/adjective syntax. It does not work at all for anonymous aliases.
imply ExecutionContext = ForkJoinContext()
is wrong, since it equates a type with a term. With an adjective, it’s acceptable:
given ExcecutionContext = ForkJoinContext()
This can be read as "the given ExecutionContext
is a ForkJoinContext
". The adjective form “given T” or “implied T” brings the type T
to the term level, so the equality makes sense.
Now, before we start to unravel everything again, here are some corner-stones that I feel we have pretty much settled on.
- The basic given syntax, without
val
, def
, or object
.
- The optional
x:
labels, which can be left out to make instances and parameters anonymous
I am not convinced that the distinction between verbs for instances and adjectives for parameters is needed for clarity. I believe the fact that parameters are enclosed in parens is enough of a clue. Compare it with the following hypthetical syntax for by name-parameters:
def f(def x: T): U = ...
I don’t think people would have a problem distinguishing the function from the parameter, since the parameter is enclosed in parens. Likewise for
given listOrd[T](given x: Ord[T]): Ord[T]
If you leave out the names listOrd
, and x
, it becomes slightly more awkward:
given [T](given Ord[T]): Ord[T]
But I believe one will get used to this style quickly. If not, it has two possible remedies: Use a context bound, or define a name for the parameterized instance.
That leaves the choice of adjective(s). I really like given
for instances. It’s short, easy to understand, with the right connotations. Using it for parameters does bring up the issue that @eyalroth noted: given T
is a common form to talk about any parameter of a function. We did experiment with two different adjectives (I believe it was given
for parameters and implied
for instances), but early users found that confusing. They were not sure when to use what adjective since their meaning was too similar. So I would advise against that.
Using implied
everywhere for given
has advantages as well a disadvantages. It works best for formal parameters and implicit function types.
def f[T](implied Ord[T]) = ...
type Ctx[T] = (implied Context) => T
vs
def f[T](given Ord[T]) = ...
type Ctx[T] = (given Context) => T
The main advantage is that it’s less ambiguous to talk about an “implied” parameter than about a “given” parameter. So I would assume that even if we keep the “given” syntax, the parameters would still be called “implicit”. That’s what the current docs do.
On the other hand, I believe given
works better for instances and for explicit arguments to implicit parameters. implied
is too convoluted for my taste, and it’s also too close to implicit
.
In the end I think given
still has the edge. The awkwardness about parameters concerns not so much the code itself but the ways we talk and document the code, and that can be managed.