What does "<:" mean in Scala?
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"
}