Generic return type in Scala structural type method [duplicate] - scala

I have the following snippet that (I think) defines a method addNumber1(x:T):T on a generic type T which is a subtype of AnyVal and has a method +(s:Int):T.
def addNumber1[T <: AnyVal {def +(s:Int):T}](x:T):T = {x + 1}
addNumber1(31) // compiles but throws exception
java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)
at java.lang.Class.getMethod(Class.java:1786)
at .reflMethod$Method1(<console>:8)
at .addNumber1(<console>:8)
... 33 elided
I tried adding import scala.language.reflectiveCalls to suppress a feature warning but still get the error.
I am able to use this when working with AnyRef or Any as below:
def addNumber1[T <: Any {def +(s:Int):T}](x:T):T = {x + 1}
class Foo(s:String) {def +(i:Int) = new Foo((s+1).toString)} // random code
class Bar(s:Foo) {def +(i:Int) = new Bar(new Foo(i.toString))} // random code
addNumber1(new Foo("1")) // works
addNumber1(new Bar(new Foo("1"))) // works
addNumber1(1) // compiles but gives exception

You run into an intersection of quite a few features:
So far as the initial stages of Scala compiler are concerned (including typechecking), Int does have an (overloaded) + method. But this "method" is treated specially by the later stages (as are all methods on Int, because it isn't really a class).
Methods called + and defined in Scala are translated to methods called $plus in bytecode, since + is not a legal identifier there. Since + on Int is special, as mentioned above, this doesn't apply to it. Since the structural types are implemented using Java reflection, your addNumber1 looks somewhat like
def addNumber1(x: Object) = x.getClass.getMethod("$plus").invoke(x, 1)
To call addNumber1 on an int, it has to be boxed to Integer first, because int is not an object. Integer, not being a Scala type, doesn't have a $plus method. In Scala you can write something like val x: Integer = ...; x + 1, but this uses an implicit conversion which Java reflection has no idea about.

I think the problem has nothing to do with AnyVal, AnyRef Or Any.
addNumber1(new Foo("1"))
This works because you indeed defined a Foo class that provides an implementation of def +(s:Int):T.
addNumber1(1)
This doesn't work because Integer class doesn't provide it, as is mentioned in the exception:
java.lang.NoSuchMethodException: java.lang.Integer.$plus(int)

Related

In scala, how to make type class working for Aux pattern?

Here is a simple example:
trait Base {
type Out
def v: Out
}
object Base {
type Aux[T] = Base { type Out = T }
class ForH() extends Base {
type Out = HNil
override def v: Out = HNil
}
object ForH extends ForH
}
class TypeClass[B]
trait TypeClassLevel1 {
def summon[B](b: B)(implicit ev: TypeClass[B]): TypeClass[B] = ev
}
object TypeClass extends TypeClassLevel1 {
implicit def t1: TypeClass[Base.Aux[HNil]] = new TypeClass[Base.Aux[HNil]]
implicit def t2: TypeClass[Int] = new TypeClass[Int]
}
it("No Aux") {
val v = 2
TypeClass.summon(v) // works
}
it("Aux") {
val v = new Base.ForH()
TypeClass.summon(v) // oops
TypeClass.summon(Base.ForH) // oops
val v2 = new Base.ForH(): Base.Aux[HNil]
TypeClass.summon(v2) // works!
}
The object Base/ForH clearly has a stable path, this eliminate the possibility of the compiler not being able to resolve type ForH.Out.
What bothers me is not how incapable the compiler is to figure out the fact that ForH <:< Aux[HNil], but how easy it is to patch it up, just by a simple type upcast (last 2 lines). IMHO both features (type lambda & type classes) are important aspect of functional programming, why they can't work together at the same time?
If you are familiar with the compiler design I'll have an extra question: what does it take to improve the type class search algorithm to make it happen? Thanks a lot for your opinion.
UPDATE 1: a specific fix has been proposed but I have another problem trying to generalise it, please see In scala, how to make type class working for Aux pattern? - Part 2 for detail
So the compiler is able to infer ForH <:< Aux[HNil], but (tbh I don't know exactly why) when resolving an implicit when the return type uses a type lambda, it gets confused if you don't use a type bound.
Anyway that's probably not a great explanation, but at least I can make your code compile. Just change t1 to:
implicit def t1[T <: Base.Aux[HNil] ]: TypeClass[T] = new TypeClass[T]
this works for me in scastie using Scala 2.13.4.
What bothers me is not how incapable the compiler is to figure out the fact that ForH <:< Aux[HNil]
Surely the compiler does see that Base.ForH <:< Base.Aux[HNil]. You can check that
implicitly[Base.ForH <:< Base.Aux[HNil]]
compiles.
IMHO both features (type lambda & type classes) are important aspect of functional programming, why they can't work together at the same time?
Why are you talking about type lambdas? I can't see type lambdas in your question.
By the way, type lambdas is not a part of Scala 2 and ({ type λ[X] = ...F[X]... })#λ for a type lambda is more or less a hack. Actual type lambdas are added to Scala 3.
val v = new Base.ForH() has type Base.ForH (not Base.Aux[HNil] without upcasting via type ascription val v = new Base.ForH(): Base.Aux[HNil] or manual type specification val v: Base.Aux[HNil] = new Base.ForH()). TypeClass.summon(v) shouldn't compile since there is no implicit TypeClass[Base.ForH]. What implicit would you consider as a candidate? TypeClass.t1? But it's not a candidate, you can check that explicitly resolved
TypeClass.summon(v)(TypeClass.t1)
can't compile.
what does it take to improve the type class search algorithm to make it happen?
Implicit search algorithm shouldn't be improved in this specific place. It works properly, as intended.
You can make the type class contravariant
class TypeClass[-B]
Then TypeClass.t1 will be a candidate for TypeClass[Base.ForH] and TypeClass.summon(v) will compile.
In scala 2.13, how to use implicitly[value singleton type]?

Why does a + operation on two members of a template class cause a type mismatch error?

lately I've decided to port my project's codebase to Scala for performance reasons but just as I was getting started, I was stopped by an error I did not understand. This is the minimal amount of code that causes the error:
class Foo[A](var x: A) {
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
}
And the error itself:
test.scala:2: error: type mismatch;
found : A
required: String
def +(other: Foo[A]) = new Foo[A](this.x + other.x)
^
After looking around, I found some forum posts about similar errors which were apparently caused by Scala implicitly converting the template type to a string(?).
As mentioned in the comments, the compiler doesn't have enough information about type A to know how to + two of them.
The reason for the confusing error message is that the compiler "knows" that everything has a toString() method and that type String has a + method. So why doesn't it convert both to type String and + them together? It's because the A-to-String transition is an implicit conversion and the compiler won't do more than one implicit conversion in order to resolve an expression.
Thus the found:A, required:String error. The compiler is saying, "I've already converted the first A to String in order to resolve the + method but, now that I've done that, I can't do it again on the 2nd A element."
There are a few different ways around this. Here's one.
class Foo[A:Numeric](var x: A) {
def +(other: Foo[A]) =
new Foo[A](implicitly[Numeric[A]].plus(this.x, other.x))
}
A is restricted to types found in the Numeric type class. To add two As together, pull the implementation for Numeric[A] out of the implicit scope and invoke its plus() method.
The problem here is that the plus method in this.x + other.x is not the plus method defined in Foo[A]. It comes from A. And as A is still undefined, can be Any. The compiler, as always, will look a way to make things compile and in this case will find a conversion that will allow this.x call to + method. It will find this in Predef.scala that is in scope and has
implicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
Therefore if this.x is a String to be able to concatenate that.x, it should also be a String. Which is not the case.
You can check it in https://github.com/scala/scala/blob/706ef1b291134a5e5bce2275df2c222261f73451/src/library/scala/Predef.scala#L381

Function [with generic data types]? in Scala. How do I get this right?

I am trying to pick some Scala and among the interesting features I found the function with
generic (input types)? particularly useful. However trying the following code,
def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)
I get the annoying error written below:
<console>:8: error: type mismatch;
found : List[A]
required: List[String]
def recFunc[A](xs: List[A], base : () => A) : A = if (xs.isEmpty) base() else xs.head + recFunc(xs.tail.asInstanceOf[List[A]], base)
How on earth, the type inference system came up with A == String and throws this exception. Can it be that I got completely wrong the use of this construction?
Thx
The Problem is that you invoke + for a generic type A. The compiler tries to infer something that uses + (like String) and you get the error. I also don't understand what you want to achieve with the +.
You don't guarantee that the method + is available for type A. So, the compiler convert A into String.
One solution consist of using typeclasses.
trait Addable[A] {
def plus(x: A, y: A): A
}
recFunc[A:Addable]…
You may take a look at spire, short intro here : http://typelevel.org/blog/2013/07/07/generic-numeric-programming.html
You are calling the + method on A, but there's no guarantee that A has such a method. There are two ways to get around this: inheritance or type classes.
With inheritance, it would be a simple matter of finding a common ancestor to all desired classes that includes the methods you want, then you'd write [A <: CommonAncestor]. Unfortunately, as a result of the effort to make Scala interoperable with Java and general JVM restrictions, the numeric primitives share no such ancestor.
We are left, then, with type classes. The expression "type class" comes from Haskell, and the idea is that you can group different types into a class that share some common properties. The main difference between that and inheritance is that a type class is open to extension: you can easily add any type to such a class.
Scala does not have direct type class support. Instead, we use a "type class pattern" to simulate it. Basically, we create a class -- the type class -- that contains the methods we desire. Next, we create instances of that class for each type we desire to support. Finally, we pass those instances implicitly, which makes it the compiler's job to find the instance required.
In your example, we could do this:
// Our type class
class Addable[T] {
def plus(a: T, b: T): T
}
// Or Int instance
object AddableInt {
class AddableInt extends Addable[Int] {
def plus(a: Int, b: Int): Int = a + b
}
implicit val addableInt = new AddableInt
}
// Make the implicit available
import AddableInt._
// Make recFunc use it
def recFunc[A](xs: List[A], base : () => A)(implicit addable: Addable[A]): A =
if (xs.isEmpty) base() else addable.plus(xs.head, recFunc(xs.tail, base))
// call recFunc
recFunc(List(1, 2, 3), () => 0)
There are many ways to improve this, such as using implicit class and context bounds. Please, see the Scala wiki on Stack Overflow for more information on implicits and context bounds (sessions 23 and 19, respectively).
Now, it happens that Scala already has context bounds for basic arithmetic, and even some extra tricks using view bounds to make it usage seamless. Here's how you can make it work with the standard library alone:
import scala.math.Numeric.Implicits._
def recFunc[A : Numeric](xs: List[A], base : ()=>A) : A =
if (xs.isEmpty) base() else xs.head + recFunc(xs.tail, base)
See also the Numeric scaladoc, though it's really low on examples.

Scala - how to go resolve "Value is not a member of Nothing" error

This example code is based on Atmosphere classes, but if someone could give me some insights into what the error means in general, I think I can figure out any Atmosphere-specific solution...
val bc = BroadcasterFactory.getDefault().lookup(_broadcasterId)
bc.broadcast(message)
After the first line, bc should contain a handle to an object whose class definition includes the method broadcast() -- in fact, it contains several overloaded variations. However, the compiler chokes on the second line of code with the following: "value broadcast is not a member of Nothing"
Any ideas/suggestions on what would be causing this?
Thanks.
EDIT: signature for [BroadcasterFactor].lookup :
abstract Broadcaster lookup(Object id)
Note: 1) that is the signature version that I've used in the example, 2) it is the java Inteface signature - whereas the getDefault() hands back an instantiated object that implements that interface.
Solution: force type cast on value:
val bc: Broadcaster = BroadcasterFactory.getDefault().lookup(_broadcasterId)
Nothing is the type name. It's the subtype of all other types. You can't call methods from Nothing itself, you have to specify exact type ((bc: ExactType).broadcast(message)). Nothing has no instances. Method, that returns Nothing will, actually, never return value. It will throw an exception eventually.
Type inference
Definition of lookup:
abstract public <T extends Broadcaster> T lookup(Object id);
in scala this definition looks this way:
def lookup[T <: Broadcaster](Object id): T
There is not specified type parameter in lookup method. In this case compiler will infer this type parameter as the most specific type - Nothing:
scala> def test[T](i: Int): T = ???
test: [T](i: Int)T
scala> lazy val x = test(1)
x: Nothing = <lazy>
scala> lazy val x = test[String](1)
x: String = <lazy>
You could specify type parameter like this:
val bc = BroadcasterFactory.getDefault().lookup[Broadcaster](_broadcasterId)
Draft implementation
In development process lookup can be "implemented" like this:
def lookup(...) = ???
??? returns Nothing.
You should specify either result type of lookup method like this: def lookup(...): <TypeHere> = ... or type of bc: val bc: <TypeHere> =.

List of String implicit conversions like +=

Consider the following snippet. += is not a member of java.lang.String, so I guess there is some sort of Implicit conversion going on. How do I find a list of such predefined implicit conversions acting on String?
scala> var x = "asdf"
x: java.lang.String = asdf
scala> x += x
scala> x
res2: java.lang.String = asdfasdf
You picked a particularly bad example. += is, in a sense, part of String. See this comment on the Javadoc for java.lang.String:
The Java language provides special support for the string
concatenation operator ( + ), and for conversion of other objects to
strings.
You'll have to look up Java language specification to find more information about it (15.18.1). But, then again, Scala is not Java, so + is also part of the Scala language specification (12.3.1).
So far I have spoken of +, not +=. However, Scala has a special syntactic sugar for assignment. As described in section 6.12.4, except for <=, >=, != and operators starting with an =, any operator symbol (see "operator characters" in chapter 1) that ends in an equal sign will be reinterpreted if it does not exist as a method. Specifically,
x += 1
will be reinterpreted as
x = x + 1
That will happen regardless of whether x is a var, so one might occasionally see an error message "reassignment to val".
So, as you can see, += is really part of String, through an exception in Java specification that was replicated in Scala specification, plus a bit of syntactic sugar.
Which doesn't mean there aren't methods not in java.lang.String that can be used with it through implicit conversions. I'll leave that to the other answers, however. If I were you, I'd change the method in the question, to make it correct. Besides, += is unsearchable in Stack Overflow.
You need to look in scala.Predef - all implicits that are defined there would be always in scope (so you don't need to import them).
If you look in it's source code, you will find this section:
// Strings and CharSequences ------------
...
implicit def augmentString(x: String): StringOps = new StringOps(x)
implicit def unaugmentString(x: StringOps): String = x.repr
...
StringOps defines implicit conversions for String. It gets imported into the scope in scala.Predef along with other useful things.
Not specific to String, but the Scala REPL has a neat feature to see all the implicits in scope:
scala> :implicits
No implicits have been imported other than those in Predef.
scala> :implicits -v
/* 96 implicit members imported from scala.Predef */
/* 66 inherited from scala.Predef */
implicit def Double2double(x: jl.Double): Double
implicit def byte2double(x: Byte): Double
implicit def char2double(x: Char): Double
...
/* 30 inherited from scala.LowPriorityImplicits */
implicit def genericWrapArray[T](xs: Array[T]): mutable.WrappedArray[T]
implicit def wrapBooleanArray(xs: Array[Boolean]): mutable.WrappedArray[Boolean]
implicit def wrapByteArray(xs: Array[Byte]): mutable.WrappedArray[Byte]
...
It's also worth noting that implicits don't have to be in scope to be applied. For example, we can define an implicit conversion in a companion object,
case class Foo(s: String)
object Foo { implicit def string2Foo(s: String) = Foo(s.reverse) }
and then apply it, even though its not in scope,
scala> val f: Foo = "hello"
f: Foo = Foo(olleh)
The Foo companion object is searched for implicits because the target type is Foo. For more info, see Daniel Sobral's answer to: Where does Scala look for implicits?