Dotty: implicit(ly) versus given/summon

Do we? Maybe context bounds solve 99% of the give given cases?

1 Like

I agree with @julienrf. A given parameter both demands and provides a given instance, so we need a single keyword to express both. Why given and not implicit? The principal reason is that we need to distinguish new from old syntax since the method application rules have changed. implicit parameters can be passed using plain arguments whereas given parameters can only be passed using arguments of the form (given E). Besides, given is a better name than implicit precisely because it expresses
both “provide” and “require”. The previous syntax

implicit object ord extends Ord[Int] { ... }

is weird since there is nothing “implcit” about ord. It’s just as explicit as the next object. The new syntax

given ord: Ord[Int] { ... }

works much better in this regard.

Thank you Martin. I still think that

given [T](given peer: Ordering[T]): Ordering[List[T]] = ???

is “weird” (it was weird before when it was implicit), so I liked the suggestion to distinguish definition site from argument site, such as give [T](given peer ...).

1 Like

Tough I get this reasoning, I think that it provides both roles is actually one of the more confusing things about implicits, which still isn’t solved. If I recall correctly, differentiating call and usage site was one of the requirements of the new implicit system.

Personally I think that two keywords, even though it might be less semantically correct, would actually make more sense.

2 Likes

Given X means “supposing that X exists.” I don’t see how that makes sense for the definition.

3 Likes

I get that. Which is the original reasoning behind choosing only one keyword.

However give x: X (given y: Y) makes it visually much easier to parse what means what, especially when working with real code that is usually longer and more complex. I am not saying this is the best solution. However I think using the same keyword is still more confusing than using two, even if it is semantically correct.

I think this problem is disregarded a little bit too easily.

Edit: to expand on the previous. In the original motivation behind changing implicits (Principles for Implicits in Scala 3) it questions why implicits are not the run-away success as in Rust or Haskell. For me, one of these reasons is clearly because type classes make a clear distinction between providing a one and requiring one.

Compare using one in Haskell versus Scala:

class (Eq a) => Ord a where ... and given ord: Ord[A](given eq: Eq[A]) = ...

5 Likes

At definition site, given X can be read as "X is a given"; just like class X can be read as "X is a class" (and object, trait, val, def). “A given” is something that is established; not something that needs to be established.

I understand the reason why given has been chosen as a keyword, especially since in English it means both:

  • “Be ec an ExecutionContext” and
  • “Given that ec is an ExecutionContext”

Choosing given makes total sense in that regard. No argument.

I don’t want to “fight” or advocate against using a single keyword if people have their opinion set already (and discussed about it before). But I really want to emphasize (a last time) on what @bmeesters is writing.

I really think having a single keyword expressing:

Is really confusing.

If someone is asking me: “What does given mean in Scala?” I’m not sure I’d be able to explain it in a sentence not containing “either, or, or, or” which sounds a bit weird to me.

Thanks a lot for your explanations and the time spent to go over the questions.

6 Likes

Good point.

However val x = 1 also establishes x.

Clearly given x doesn’t mean x is a given, it means x is a Given. Meaning, you can’t just read it as English and understand it without knowing that Scala has a concept called Givens.

And that same logic works equally well for implicit. implicit val x doesn’t mean x is implicit, it means x is an Implicit.

[I admit there’s a difference: “x is implicit” (lowercase) is factually untrue (of course it is an Implicit, capital), while “x is a given” is true but uninteresting, so it might be somewhat less confusing, but I doubt meaningfully less. Besides the same holds for anything. In the case of class you don’t read it as x is class or x is a class in the common vernacular, you read it as x is a Class where Class is some concept defined by the language (in this case shared with many other languages, at least roughly).]

2 Likes

Not sure if you meant to reply for someone else, but I’m arguing against using one keyword. Given makes sense for implicit parameters, a lot more than for implicit definitions.

If that’s the only reason then I’d much rather a breaking change with a rewrite rule (since we will have such things anyway).

Dotty is supposed to have fewer ways to do things, this is a gigantic exception to that, and I’m really not seeing the justification.

4 Likes

I am not sure that works. Is

given intOrd: Ord[Int] ...

meant to say Ord[Int] is a given? Something is a given when it’s a fact, widely known or understood.
All object definitions are given in that sense. Often there are different ways to order structures, and it’s not a given to order them that way or not, but one can make one of them a default.

On the other hand when we have a use in an argument position given works very well, especially I think in the previous notation without parenthesis

def (t: T) sort[T] given Ord[T]

which states that the definition sort works only if given an extra argument (from the default environment).

What seems to be needed is a way to say “make this object a potential default” in 4 or 5 letters.

Btw other suggestions were made on issue 7151 were assume/assumed, provide/provided .

(give/given does have the very big advantage of being short.)

I like “assume” and it would make a lot of sense to import implicits with

assume order.intOrd

What is a bit odd is the declaration that something is assumable, makeable implicit, since in a way anything can be made implicit…

Could one redyce the use of implicits to an import statement such as assume? Then at least the implicits would be clearly visible. It seems that definining objects as potentially implicit is the weird thing.

1 Like

What about an “import scala.lang.version 2”?

Could that allow “implicit/implicitly” to be used for Scala 3?

Personally, I think that I would prefer a few keywords with well defined meanings that than one keyword that can be used in lots of ways.

E.g. defining an extension method using an extension keyword would likely make code easier to read. Similarly defining a typeclass using a “typeclass” keyword would generally seem to be easier (at least for me) to understand.

Otherwise my fear is that “given” is just turning into different version of “implicit” and perhaps they are both closer to “magic”.

Slightly off topic, but I wonder whether extension method definitions might be a bit more readable with a dot in the definition to make the binding more obvious?

E.g.

extension {
   def (xs: List[T]).second[T] = xs.tail.head
}

rather than:

given {
  def (xs: List[T]) second[T] = xs.tail.head
}

Just a few thoughts,
Rob

2 Likes

If that’s the only reason then I’d much rather a breaking change with a rewrite rule (since we will have such things anyway).

That would not work. The problem is that a call f(x) means something different if f has an implicit parameter or a given parameter. Example:

val ctx: Context
def f1(implicit c: Context): Map[String, Int]
f1(ctx)     // OK
f1("abc")   // Type Error

versus:

def f2(given c: Context): Map[String, Int]
f2(ctx)       // Type Error
f2(given ctx) // OK
f2("abc")     // OK

So this means you cannot independently rewrite f without also rewriting all its callers. But such a “rewrite the whole world all at once” approach is simply impractical.

Martin - I meant a rewrite rule for call sites only, to insert the implicit keyword in function application that would previously correspond to an implicit parameter, to make that expect. Is that unfeasible?

That’s feasible, but only if the new and old definition syntax is different. How otherwise would we know whether to rewrite the caller?

Yes, sorry, I made a mistake. Just ignore the part that was specifically replying to you.

No one has mentioned that English “gift” is both a verb and a noun. It means both to give and the thing that is given, the present. Everyone likes presents!

It also means a talent, as when one is gifted, so that a special capability has been conferred by an unseen power.

In the current idiom, one could even speak of implicit chaining as re-gifting. And if an implicit requires adaptation, that would be gift wrapping.

And for those who take a dim view of implicits and their black artistry, “Gift” in German means poison. So anyone preferring a visual marker for what they might prefer not to take, need only capitalise to capitalise and profit.

So I propose “gift/Gift” as the succinct and multivalent keyword that satisfies all the use cases yet satisfies none.

Please ignore the part that was specifically replying to you.

7 Likes

Here, have a Monoid:birthday:

gift is a great choice … it even has its own unicode character: :gift:

5 Likes