Proposal to Add Implied Instances to the Language

My only other suggestion would be archetype as a noun

Ooh i like this one also.

I’m not a big fan of abbreviations, especially highly nonstandard ones like repr or others that involve just dropping arbitrary letters mid-word. It’s ok to require a couple extra keypresses (or an editor/ide macro or automated expansion) to improve clarity. Storage space is cheap; mental computation tax to expand nonobvious abbreviations is not.

2 Likes

archetype is nice, except that it looks like it defines a type, where in reality it defines a term. Could be especially confusing for non english speakers who don’t know already what an archetype is.

We’re a week further and still throwing around keywords, so may I express my surprise that the permutation implicit foo of Bar given Baz has not come up yet? I’m not really a traditionalist, but I think that for historic reasons it would be nice to keep implicit in Scala. And given the opposition to, among others, instance and for, I think that implicit ... of ... given ... has a lot going for it and little cons.

2 Likes

Though I think that proposal actually has come up, we’re indeed mostly bike-shedding keywords here. I agree that using implicit ... of ... given ... is closest to what we already have (and therefore likely has the least resistance) while still achieving the proposed principles.

It appears that you’re right. 7 days and more than 100 posts ago it came up briefly. I still think given recent developments it deserves some renewed attention :stuck_out_tongue:

Thank you all who have contributed suggestions and critique.

Here’s what I took back from the discussion so far (on all three threads covering revised implicits).

  • Many people feel that the changes are too radical for the benefits they bring. I continue to believe that the benefits justify the proposed changes.

  • Various improvements to the proposal were suggested. I’d like to comment on some of them further:

    • I think we have reached consensus that given should come last in an instance definition.
    • We have also reached consensus that tooling should be improved so that suggestions for
      missing imports can be made when an implicit is not found.
    • There was a proposal by @tarsa to change the application syntax from (a given b) to a.given(b). I like that, but in the end decided to not pursue this, since we don’t have precedence for a keyword being used as a method. By contrast we do have precedence for keywords used in infix position, such as match.
    • I am still on the fence whether we want to restrict given in method definitions so that given parameters cannot be followed by normal parameters. The restriction is technically unnecessary, and the idiom has some use cases. The use cases can be worked around at the price of some more complication, and possibly some run-time cost. The only reason to restrict is that the syntax of given followed by normal parameters looks weird. One argument in favor of leaving it in is that weird looking syntax is its own regulative. People would hopefully use it only if it’s strictly necessary, which means almost never. Overall, I could live with either leaving it in or removing it.

The most widely debated point was (again!) what keywords to use for instance definitions. I believe it is very important to get this right. And it’s frustrating that this seems so hard. There are three choices that I want to comment on.

  • The current proposal: implied ... for. Received quite a lot of criticsm including from people who have used it intensively.
  • The smallest change: implicit ... for. Since it’s closest to current usage it would probably have the least resistance from existing users. I still think it’s a possibility, in the sense that it is better than the status quo. But it’s not as good as it could be. First, implicit ... for is a weird formulation, only tolerable because we are already used to contorsions of the word implicit (and implicit ... of would make even less sense). But it would look strange to a newcomer. Second, it risks confusing people further by not clearly distinguishing between old and new style syntax for implicits.
  • The “correct” word: repr ... of. We got some support that representative is a good word for the term that’s inferred for a type. And representative of … is correct English. repr as an abbreviation works OK, except that it’s a bit hard to pronounce.

My conclusion from these discussions is that I propose to switch to the repr ... of syntax for instance definitions. Since this thread has already gotten 140+ replies, I propose to close it, and replace it with the new proposal.

3 Likes

Lack of method notation for match prevents from chaining it. I can do:

Some(makeNumber)
  .map {
    case 4 => "8"
    case x => x.toString
  }
  .map {
    case "8" => "x"
    case x => x
  }

but I can’t do:

makeNumber
  .match {
    case 4 => "8"
    case x => x.toString
  }
  .match {
    case "8" => "x"
    case x => x
  }

There were proposals to allow method notation for match. I don’t remember the reason they were rejected.

I believe those are independent choices. If match would be a method, it would not be a keyword anymore. One reason for not making that change is that we now have special forms of matches such as inline match.

I’d like propose to shorten the repr to rep, that way it’ll be as long as val var and def and won’t be confused with the Repr as @tarsa had pointed out.

5 Likes

Even Wikipedia states that rep is a “clipping of representative”: https://en.wiktionary.org/wiki/rep

Googling “house of reps” gives this: https://en.wikipedia.org/wiki/United_States_House_of_Representatives

Could be a fancy name for typeclasses aggregate:

abstract class HouseOfReps {
  rep abc: Xyz[Int]
  rep mno: Ijk[String]
}

:wink:

6 Likes

Unfortunately, it’s confused with “repeat” then, and I have rather a lot of variables named rep meaning repeat in my codebases. I doubt I’m the only one.

I would just like keywords as well as methods to be able to be used with method notation. That is, foo.bar.baz is always a valid alternative to (foo bar baz) regardless of whether bar is a method or is technically not but performs the same goal of producing a result based on a pair of inputs. (So if/else would be out, as it has a more complex form, but match and given would both be in.)

You can’t use keywords as method names anyway, so parsing wouldn’t change.

I completely agree that this is orthogonal. However, if it were adopted, it would strengthen my preference for using given to denote specified constraints.

1 Like

OK, I promise, my absolutely final bikeshedding on this topic. Honest guv. I’ll go with whatever people decode, but …

derive [T] Monoid[Option[T]] given Monoid[T] named OptionMonoid = ...
derive [T] Ordered[List[T]] given Ordered[T] = ...
derive Ordered[Complex] = ...

Not saying I love this, but it’s the remaining variant that I’ve come up with and not seen discussed.

bikeshedding++; How about singular? It could read “the only instance for given type”.
Reads nicely in my head… xD

singular ListOrd[T] given (ord: Ord[T]) of Ord[List[T]]

singular IntOrd of Ord[Int]

singular of Ord[Int]

I know we’re trying to wind this thread down but I’ve been struck by that bikeshedding impulse, so I’ll throw my hat in with typeclass-instance ... providing ... given ....

It’s long, yes, but in my opinion that’s somewhere on spectrum between “acceptable” and “good”. Here are some of the reasons for me thinking:

  • It’s very clear for the reader: one of the things that I feel is sorely lacking from all of the proposals here here and in the thread on given is any appearance of the word “typeclass”. Given (yes it’s a pun) that we are effectively defining dedicated language primitives for typeclasses, I find it to be really strange for the actual term “typeclass” to be a sort of term-that-shall-not-be-named. I think that we have to accept that most users will be coming from languages that don’t have typeclasses. I think it’s very important to make those users feel comfortable and get subtly guided to a real understanding of the thought processes behind the pattern (which I think having keywords that are Google-able, that read well as English, and that reinforce the proper terminology accomplishes).
  • It’s not that bad for the writer: You don’t define new typeclass instances all that often when writing code. When you do, I think that forcing you to think in the “proper” terms can only be a good thing. There is a certain clarity of thought gained from the mantra of “define an instance providing X given Y”. I will say, too, that this stuff is so cool and useful that I think authors will be more impressed (and later satisfied) with what they can do than annoyed at the exact number of characters that they have to type.
1 Like

How about known as the complement to given:

known ListOrd[A] for Ord[List[A]] given (a: Ord[A]) {  }
2 Likes

Interesting suggestions, but I believe that repr/representative is still the one:

  • derive is a bit off in its meaning. A derivation produces a piece of information from something else according to a fixed set of rules. But the instance of a type class is not the derivation of the type class. Given a type, we do not have the necessary information to derive its instance; there has to be an extra input by the programmer. If we talk about typeclass derivation a la shapeless, that’s different: Given a typeclass and an ADT, we can produce the instance given a fixed set of rules.
    Besides, I really think we should have a noun so that we can talk about the defined things without having to invent yet another term.
  • singular, known both work to some degree, but are less clear and precise than “representative”. singular is too narrow - there might be more than one implicit of a type depending on context, and known is too broad - we might know about several instances, but only one of them is the representative.
  • typeclass-instance is again too narrow since there are traits with implicit instances that are not typeclasses, e.g. contexts, or capabilities. (A typeclass is a family of types, so it must have at least one type parameter).
1 Like

I am not sure, if it was discussed before, but inject can also be considered as a new syntax.

given as a noun fits well for the required constraints and by inject as a verb, we are telling compiler to have this variant of constraint applicable in this scope.

inject ListOrd[A] for Ord[List[A]] given (a: Ord[A]) = { }

Anonymised form:

inject for Order[List[A]] given (a: Order[A]) = {}

1 Like

alt … for … given …

(alternative X for TYPE given INSTANCE)

Although the threads are separate, what will be become of implied import? repr import?