11

I have seen the ?=> symbol appear in Scala code and in some discussion posts about Scala 3, so I am assuming that it is a Scala 3+ symbol. Nothing appears when searching through documentation or Google, but it looks like the syntactic sugar for the Function types, so maybe it relates to types and functions. What does it mean?

Ian
  • 5,704
  • 6
  • 40
  • 72
  • 8
    https://docs.scala-lang.org/scala3/reference/contextual/context-functions.html – Luis Miguel Mejía Suárez Aug 23 '21 at 19:20
  • 3
    Another upvote from me. Scala 3 documentation is still not fully in place and somewhat difficult to navigate between the initial dotty proposals vs. what actually made it into the language. This is definitely a very reasonable question at this time. – sinanspd Aug 23 '21 at 22:08
  • 2
    At some point, someone needs to write up a good blog post about the different functions in Scala 3. There's ordinary function types, context function types, dependent function types, and polymorphic function types. And while they're all super cool from a type theory perspective (and it's truly amazing that a general-purpose not-purely-academic language managed to implement them all), I would love to see a well-written post about a practical application of each of these types. – Silvio Mayolo Aug 23 '21 at 22:54

1 Answers1

5

The type (a: A, b: B, ..., z: Z) ?=> R basically means (using a: A, b: B, ..., z: Z) => R (I believe the latter syntax was valid at one point, but not anymore). All of those parameters become implicit parameters when you use ?=>. Similarly, a function literal (a, b, ..., z) ?=> ... makes all of the parameters to that function implicit, and they can be passed implicitly to other methods later.

Here's an example (Scastie):

case class Foo(s: String)
case class Bar(i: Int)

def baz(xyzzy: (Foo, Bar) ?=> String): Unit =
  val foo = Foo("waldo")
  val bar = Bar(2)
  println(xyzzy(using foo, bar))

baz takes a context function. Note how xyzzy is called with the same syntax as a normal method taking a Foo and a Bar as implicit parameters (in Scala 3, blah(using bleh, bluh) is used to explicitly pass implicit arguments bleh and bluh instead of simply blah(bleh, bluh) like in Scala 2).

Here's one way we can call baz, by defining a method with implicit parameters:

def foobar(using Foo, Bar) =
  val foo = summon[Foo]
  val bar = summon[Bar]
  s"Method - foo: $foo, bar: $bar"

baz(foobar)

We can also pass in a function literal. There are no regular parameters, so it looks a little like a by-name parameter. There are implicit instances of Foo and Bar available because of the (Foo, Bar) ?=> type of the literal.

baz {
  val foo = summon[Foo]
  val bar = summon[Bar]
  s"Function literal - foo: $foo, bar: $bar"
}

You can also use ?=> in the function literal itself to name the implicit parameters without having to summon them and assign them to values. Since they're implicit, you can also call foobar from above because an implicit Foo and Bar are available (you can also do this in the second example despite not having named the parameters explicitly).

baz { (foo: Foo, bar: Bar) ?=>
  val fromMethod = foobar
  s"Explicit context function literal - foo: $foo, bar: $bar; $fromMethod"
}

user
  • 7,435
  • 3
  • 14
  • 44
  • How would this have been represented in Scala 2? Would `Foo => Bar` be the same thing as `Foo ?=> Bar` in the Scala 2 type system? – Ian Aug 24 '21 at 23:40
  • 3
    I don't think there's an easy way to do it in Scala 2 without making a trait `ContextFunction2[A, B]` with a method taking two implicit parameters. – user Aug 24 '21 at 23:43