What does ?=> mean in Scala? - scala

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?

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"
}

Related

What is the effect of explicitly specifying a generic apply method's type?

It's not very clear to me how adding a a Type parameter to a generic object can influence the call of its apply method. If that didn't make much sense, I have tried to formulate a simple example to express my trivial confusion.
scala> object Foo {def apply[T] = "Hello from foo"}
object Foo
scala> Foo
val res0: Foo.type = Foo$#709d6de5
scala> Foo[Int]
val res1: String = Hello from foo
Why is it only that when I specify [Int], the apply method is called, and returns "Hello from foo"
On the other hand, when I use an apply method that takes a parameter, I don't need to specify the type anymore.
scala> object Bar {def apply[T](useless: T) = "Hello from bar"}
object Bar
scala> Bar
val res2: Bar.type = Bar$#33089426
scala> Bar("Something useless")
val res3: String = Hello from bar
Why in the first case (when there were no parameters) I had to specify the type, while in the second case (when there was one useless parameter) I did not have to specify the type, for the apply to be called?
The compiler needs to know when you're referring to the object and when you're invoking the apply() method. It uses [] and/or () as the clue.
If you add an empty value parameter list to the Foo.apply then you can drop the [Int] specification.
scala> object Foo {def apply[T]() = "Hello from foo"}
defined object Foo
scala> Foo
res25: Foo.type = Foo$#332d4c4f
scala> Foo[Int]
res26: String = Hello from foo
scala> Foo()
res27: String = Hello from foo
If your apply takes no parameters, type or value, then the only way to invoke it is to specify it completely.
cala> object Baz {def apply = "Hello from Baz"}
defined object Baz
scala> Baz
res14: Baz.type = Baz$#5bd4ecec
scala> Baz()
<console>:13: error: Baz.type does not take parameters
Baz()
^
scala> Baz.apply
res16: String = Hello from Baz

Using FunctionX#curried

I define foo:
scala> def foo(x: Int, y:Int): Int = x + y
foo: (x: Int, y: Int)Int
Then I failed to set bar equal to the curried function of foo.
scala> def bar = foo.curried
<console>:8: error: missing arguments for method foo;
follow this method with `_' if you want to treat it as a partially applied
function
def bar = foo.curried
^
What am I doing wrong?
foo is not a function, it's a method. It's not an object, it has no own methods. curried is a method on object of type FunctionN.
You have to convert it to function:
(foo _).curried
With foo _ you are creating a new object of type Function2.

Why does Scala's type inferencer fail with this set of implicit arguments involving parameterized types?

I would like to define a method parameterized with type T that has behavior dependent on what implicit argument can be found of type Box[T]. The following code has this method defined as foo. When called with foo[Int] or foo[String] it will without issue return 1 or "two" as expected.
Where things get weird is with the method bar. It is defined as returning an Int, but instead of foo[Int] I have just foo. My hope was that the compiler would infer that T must be of type Int. It does not do that and instead fails:
bash $ scalac Code.scala
Types.scala:15: error: ambiguous implicit values:
both value one in object Main of type => Main.Box[Int]
and value two in object Main of type => Main.Box[java.lang.String]
match expected type Main.Box[T]
def bar: Int = foo
^
one error found
What is causing this error? Replacing foo with foo[Int] compiles fine. The simpler situation where there is no Box[T] type also compiles fine. That example is also below and uses argle and bargle instead of foo and bar.
object Main extends Application {
case class Box[T](value: T)
implicit val one = Box(1)
implicit val two = Box("two")
def foo[T](implicit x: Box[T]): T = {
x.value
}
// does not compile:
// def bar: Int = foo
// does compile
def bar: Int = foo[Int]
println(bar)
// prints 1
// the simpler situation where there is no Box type
implicit val three = 3
implicit val four = "four"
def argle[T](implicit x: T): T = x
def bargle: String = argle
println(bargle)
// prints "four"
}
What is going on in this snippet that causes this behavior? What about this interaction of implicit arguments, type inference, and erasure is causing problems? Is there a way to modify this code such that the line def foo: Int = bar works?
Someone else will have to explain why the type inference mechanism cannot handle that case, but if you are looking to cleanup your code you could probably do this:
object Test extends App {
case class Box[T](value: T)
implicit val one: Box[Int] = Box(1)
implicit val two: Box[String] = Box("two")
def foo[T : Box]: T = implicitly[Box[T]].value
val bar = foo[Int]
}
Note that:
I removed the type annotation from bar so you are really just indicating the type once (just in a different spot than you wanted)
I am using App instead of deprecated Application
Using a context bound in the type signature of foo
This might be related to SI-3346, though there it is implicit arguments to implicit conversions, and here you have a single implicit.

Intersection of multiple implicit conversions: reinventing the wheel?

Okay, fair warning: this is a follow-up to my ridiculous question from last week. Although I think this question isn't as ridiculous. Anyway, here goes:
Previous ridiculous question:
Assume I have some base trait T with subclasses A, B and C, I can declare a collection Seq[T] for example, that can contain values of type A, B and C. Making the subtyping more explicit, let's use the Seq[_ <: T] type bound syntax.
Now instead assume I have a typeclass TC[_] with members A, B and C (where "member" means the compiler can find some TC[A], etc. in implicit scope). Similar to above, I want to declare a collection of type Seq[_ : TC], using context bound syntax.
This isn't legal Scala, and attempting to emulate may make you feel like a bad person. Remember that context bound syntax (when used correctly!) desugars into an implicit parameter list for the class or method being defined, which doesn't make any sense here.
New premise:
So let's assume that typeclass instances (i.e. implicit values) are out of the question, and instead we need to use implicit conversions in this case. I have some type V (the "v" is supposed to stand for "view," fwiw), and implicit conversions in scope A => V, B => V and C => V. Now I can populate a Seq[V], despite A, B and C being otherwise unrelated.
But what if I want a collection of things that are implicitly convertible both to views V1 and V2? I can't say Seq[V1 with V2] because my implicit conversions don't magically aggregate that way.
Intersection of implicit conversions?
I solved my problem like this:
// a sort of product or intersection, basically identical to Tuple2
final class &[A, B](val a: A, val b: B)
// implicit conversions from the product to its member types
implicit def productToA[A, B](ab: A & B): A = ab.a
implicit def productToB[A, B](ab: A & B): B = ab.b
// implicit conversion from A to (V1 & V2)
implicit def viewsToProduct[A, V1, V2](a: A)(implicit v1: A => V1, v2: A => V2) =
new &(v1(a), v2(a))
Now I can write Seq[V1 & V2] like a boss. For example:
trait Foo { def foo: String }
trait Bar { def bar: String }
implicit def stringFoo(a: String) = new Foo { def foo = a + " sf" }
implicit def stringBar(a: String) = new Bar { def bar = a + " sb" }
implicit def intFoo(a: Int) = new Foo { def foo = a.toString + " if" }
implicit def intBar(a: Int) = new Bar { def bar = a.toString + " ib" }
val s1 = Seq[Foo & Bar]("hoho", 1)
val s2 = s1 flatMap (ab => Seq(ab.foo, ab.bar))
// equal to Seq("hoho sf", "hoho sb", "1 if", "1 ib")
The implicit conversions from String and Int to type Foo & Bar occur when the sequence is populated, and then the implicit conversions from Foo & Bar to Foo and Bar occur when calling foobar.foo and foobar.bar.
The current ridiculous question(s):
Has anybody implemented this pattern anywhere before, or am I the first idiot to do it?
Is there a much simpler way of doing this that I've blindly missed?
If not, then how would I implement more general plumbing, such that I can write Seq[Foo & Bar & Baz]? This seems like a job for HList...
Extra mega combo bonus: in implementing the more general plumbing, can I constrain the types to be unique? For example, I'd like to prohibit Seq[Foo & Foo].
The appendix of fails:
My latest attempt (gist). Not terrible, but there are two things I dislike there:
The Seq[All[A :: B :: C :: HNil]] syntax (I want the HList stuff to be opaque, and prefer Seq[A & B & C])
The explicit type annotation (abc[A].a) required for conversion. It seems like you can either have type inference or implicit conversions, but not both... I couldn't figure out how to avoid it, anyhow.
I can give a partial answer for the point 4. This can be obtained by applying a technique such as :
http://vpatryshev.blogspot.com/2012/03/miles-sabins-type-negation-in-practice.html

Class constructor declaration... Two ways of declaring the same thing?

I would like an explanation of difference for example between this declaration:
class Clazz(param1: String, param2: Integer)
and this one:
class Clazz(param1: String)(param2: Integer)
Does second declaration affect just the way of instantiating the objects or is there any deeper reason I don't know about.
One reason I thought about would be multiple variable length of parameters for example:
class Clazz(param1: String*)(param2: Integer*)
So are there any others?
#1 Type inference. It goes from left to right and is done per parameter list.
scala> class Foo[A](x: A, y: A => Unit)
defined class Foo
scala> new Foo(2, x => println(x))
<console>:24: error: missing parameter type
new Foo(2, x => println(x))
^
scala> class Foo[A](x: A)(y: A => Unit)
defined class Foo
scala> new Foo(2)(x => println(x))
res22: Foo[Int] = Foo#4dc1e4
#2 Implicit parameter list.
scala> class Foo[A](x: A)(implicit ord: scala.Ordering[A]) {
| def compare(y: A) = ord.compare(x, y)
| }
defined class Foo
scala> new Foo(3)
res23: Foo[Int] = Foo#965701
scala> res23 compare 7
res24: Int = -1
scala> new Foo(new {})
<console>:24: error: No implicit Ordering defined for java.lang.Object.
new Foo(new {})
^
In the second version you are declaring a curried primary constructor for Clazz. So the difference between the two versions is the same as difference between "normal" and curried functions in Scala, i.e.
def foo(param1: String, param2: Int)
def foo(param1: String)(param2: Int)
Most of the time both declarations can be used interchangeably but if you often need to curry function then it makes more sense to declare it in curried form. Note you can also convert a normal function or even constructor into a curried form, for e.g you could transform your normal Clazz constructor into curried form using this:
(new Clazz(_, _)).curried
You also need multiple parameter lists if you are passing an implicit value (as the keyword implicit applies to the complete parameter list)