Updated Proposal: Revisiting Implicits

Well, it’s a reserved word now, so we have to find something else for partial functions. Maybe

partial_=>

?

Huh. I’ve always been partial to =?>. (please don’t reserve that, too!)

2 Likes

he he: It seams that =?> is used in scalalib in:
scala.sys.process.processInternal.=?>[T,E] == PartialFunction[T,E]

1 Like

Just to explore all the options or be the Tenth Man

val x: Int = given 4
def t3[T, U, V](using st: Show[T], su: Show[U], sv: Show[V]): Show[(T, U, V)] = given Show(...) { }

and another alternative

val x: given Int = 4
def t3[T, U, V](using st: Show[T], su: Show[U], sv: Show[V]): given Show[(T, U, V)] = Show(...) { }

second alternative also has a nice has a nice construction/deconstruction symmetry

val (ctx: given Context, n: given Int) = (ForkJoinContext(), 42)

The syntax for both of these probably would probably require no explanation to a scala beginner

To be honest, I find the difference between

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

and

def f(using x: A => B)

clearer than

def f(x: A ?=> B)

Though that might be because I am not yet very familiar with the new syntax. In any case, the regularity seems to help readability (IMO).

8 Likes

Yeah, I picked it up from Paul, and he switched from =?> to ?=> because ?=> better mirrors isDefinedAt then apply. I guess I’ll just switch back.

1 Like

I’m skeptical that the A ?=> B syntax is a good idea, for two reasons, which I think have kind of been stated, but I want to state them directly:

  1. (using A) => B perfectly mirrors the method declaration, while A ?=> B adds an extra nonstandard symbol to learn.
  2. ?=> intuitively makes more sense as PartialFunction (meaning “maybe I can A => B”) than it does as a context function type (“I’ll produce B, just let me know A from context”).

If we wanted to do it symbolically, =?> or ?=> would be for PartialFunction (and the other wouldn’t be used, to avoid confusion), and some other weird arrow would be used for context functions, like ~~>. (Tilde suggests a wiggly indirect path, which is kinda true if it’s context-dependent.)

But I’m not sure that we ought to do it symbolically. (using A) => B is really clear.

Of course we then have the problem of def foo(using A => B) being confusing (because it looks like (using A) => B, even though it’s not valid to just stick a type as an argument with nothing else). If we want this, we can warn on using A => B and require using (A => B).

Anyway, although I normally adore symbolic methods, I think ?=> is not a great choice here.

Edit: some IMO better choices include

  1. ~> “indirect arrow”: upside – looks like a not-utterly-straight path to get the result; downside – already used in Akka (edges), Graph for Scala (directed edges), Cats (mapping), etc.
  2. ~~> “long indirect arrow” upside – same as ~> and it doesn’t conflict with much; downside – long! Why so long?!
  3. *=> “take all stuff and map”: upside – * is used as a kind of gathering option already; downside – * only falls in the middle in some fonts, making it look arrowlike
  4. !=> “wow! then map”: upside – ! indicates something extraordinary is going on (in this case, using givens); downside – doesn’t look that much like an arrow because ! is both wide and asymmetric; also suggests “not” as well as “wow”
15 Likes

I was thinking a plus sign might make some sense (it’s a function plus some hidden arguments), so =+> or +=>. But better no special arrow. We could always add one later as a shortcut if there is enough demand.

2 Likes

I see a few problems with A ?=> B:

  • val f: A ?=> B is the same as def f(using A): B. But there is no self-explanatory link between using and ?=> here.
  • For anyone new to the language, who might have to look up the symbol, it’s a mess because searching for symbolic operators on the internet is close to impossible due to such symbols not being indexed by most search engines. Because of this, symbolic operators should be avoided as long as it’s not a very self-explanatory operator that is obvious also to newcomers.

As suggested by others, val f: (using A) => B is more self-explantory, and I believe it can more easily be understood to mean the same as def f(using A): B.

7 Likes

I feel the same kind of discomfort here

I’m just adding to the general crowd a voice here, I can imagine, thinking of a notation that could somehow suggest the meaning.

My proposal is a choice between

def f(x: A |- B) // proposal 1

def f(x: A |-> B) // proposal 2

def f(x: A |=> B) // proposal 3

with the idea of recalling the typing environment in type theoretic notation: we have a context that provides values of a given type…

MIght not be too wide-spread a notion.
I can’t say if any of those operators could conflict with existing codebases or libraries.

I had considered all of these before, and propsed |=> in an earlier iteration. I see where you are coming from. But in the end, I believe ?=> is easiest to grok for non-type-theorists. Also, it happens to be essentially the same notation as in the POPL paper.

Thanks for the answer, I admit it’s quite hard to keep track of all that happened since the original proposal

Regular text cannot be a part of an operator symbol because spaces do not matter

The topic of implicit conversions has come up repeatedly in this thread.

I’ve now started a new thread devoted only to conversions: Proposal: Changes to Implicit Conversions . It includes summaries and links to what has already been said here.

Although all aspects of implicits are related, the subject of conversions is at least somewhat independent, so I hope we can centralize further talk about conversions on the new thread.

3 Likes