I'm confused on how Scala's Any relates to java.lang.Object. I know that in scala, AnyRef corresponds to object, but it seems to make a difference whether the method (which takes java.lang.Object) is defined in a java class or a scala class):
the java class:
public class JavaClass {
public static void method(Object input) {
}
}
the scala application:
object ScalaObject extends App{
def method(input:java.lang.Object) = {}
val a:Any = null
method(a) // does not work
JavaClass.method(a) // does work
}
So if the method is in a java-Class, then the compiler allows me to pass a variable of type Any, why is that?
The compiler tries to "make up" for the difference between Scala's and Java's type systems. In Scala, Object =:= AnyRef (they're aliases) and AnyRef <: Any. Therefore, a Scala method that takes Object or AnyRef cannot take an Any or an AnyVal. If you wanted a method that worked on everything, well, then you would have written Any, right?
However, Java methods that take Object are normally meant to work on all values, whether they be actual Objects or primitives (int, long, etc.), and they work due to the boxing conversion of primitives into Objects. Primitives and Object do not have a common supertype like they do in Scala. The Java type system is not expressive enough to differentiate "I only want actual objects," from "I will take anything, be they object or primitive."
Therefore, the Scala compiler patches this up by turning Java methods of Object into methods of Any. This feature is simply to ease interop between the languages. It won't apply this transformation to Scala code though, because if you wanted that behavior then you would have actually written Any instead of Object.
The reason for that is that Any can be either AnyRef or AnyVal, while method can only accept objects which are AnyRef. If you modify the a type to be AnyRef, it is going to work:
def method(input: java.lang.Object) = {}
val a: AnyRef = new Object
method(a)
In case of calling the static Java method, the Scala compiler will turn Any into Object, which also includes boxing of AnyVal values.
Related
How are primitive types in Scala objects if we do not use the word "new" to instantiate the instances of those primitives? Programming in Scala by Martin Odersky described the reasoning as some enforcing by a "trick" that makes these value classes to be defined abstract and final, which did not quite make sense to me because how are we able to make an instance of these classes if its abstract? If that same primitive literal is to be stored somewhere let's say into a variable will that make the variable an object?
I assume that you use scala 2.13 with implementation of literal types. For this explanation you can think of type and class as synonyms, but in reality they are different concepts.
To put it all together it worth to treat each primitive type as a set of subtypes each of which representing type of one single literal value.
So literal 1 is a value and type at the same time (instance 1 of type 1), and it is subtype of value class Int.
Let's prove that 1 is subtype of Int by using 'implicitly':
implicitly[1 <:< Int] // compiles
The same but using val:
val one:1 = 1
implicitly[one.type <:< Int] // compiles
So one is kind of an instance (object) of type 1 (and instance of type Int at the same time because because Int is supertype of 1). You can use this value the same way as any other objects (pass it to function or assign to other vals etc).
val one:1 = 1
val oneMore: 1 = one
val oneMoreGeneric: Int = one
val oneNew:1 = 1
We can assume that all these vals contain the same instance of one single object because from practical perspective it doesn't actually matter if this is the same object or not.
Technically it's not an object at all, because primitives came form java (JVM) world where primitives are not objects. They are different kind of entities.
Scala language is trying to unify these two concepts into one (everything is classes), so developers don't have to think too much about differences.
But here are still some differences in a backstage. Each value class is a subtype of AnyVal, but the rest of the classes are subtype of AnyRef (regular class).
implicitly[1 <:< AnyVal] //compiles
implicitly[Int <:< AnyVal] // compiles
trait AnyTraint
implicitly[AnyTraint <:< AnyVal] // fails to compail
implicitly[AnyTraint <:< AnyRef] // compiles
And in addition, because of its non-class nature in the JVM, you can't extend value classes as regular class or use new to create an instance (because scala compiler emulates new by itself). That's why from perspective of extending value classes you should think about them as final and from perspective of creating instances manually you should think of them as abstract. But form most of the other perspectives it's like any other regular class.
So scala compiler can kind of extend Int by 1,2,3 .. types and create instances of them for vals, but developers can't do it manually.
I have a Java method which takes in a java.lang.Object.
Now I'm trying to pass a Scala Int to it, but the compiler complains about type mismatch of Int and Object.
This feels quite strange as I suppose a Scala Int inherits from AnyRef and should be the same as java.lang.Object?
Scala Int is not extending AnyRef, though - it extends AnyVal, which is not cast-compatible with java.lang.Object, and is more like Java int. Scala also have Integer class, which is just an alias for java.lang.Integer - use that one if you need to pass it as an object.
There're two braches of Scala classes inherited from the Scala root class - Any:
AnyVal: All value based types, e.g. Int, Byte, Double... etc. This is the counterpart of Java raw value classes, i.e. int, float... etc.
AnyRef: All reference based types, e.g. String, List, including boxed Java types, such as java.lang.Integer... etc.
(See diagram in https://docs.scala-lang.org/tour/unified-types.html)
The AnyRef is equivalent to java.lang.Object. Therefore, when calling Java methods taking Object, a AnyVal cannot be directly transferred before boxing. This can be done through explicit type declaration:
JavaClass.methodWithObject(10: java.lang.Integer)
More discussion refer to:
Result type of an implicit conversion must be more specific than AnyRef
Part I
Suppose I have a type class trait Show[T] { def print(t: T): String } with instances for String and Int. Suppose I have a value whose specific type is known only at runtime:
val x: Any = ...
How do I get the appropriate typeclass instance (at runtime, since we don't know the type statically) and do something with it.
Note that it's inadequate to define a method that literally just gives us the typeclass instance:
def instance(x: Any): Show[_]
Since Show.print requires statically known argument type T we still can't do anything with the result of instance. So really, we need to be able to dynamically dispatch to an already-defined function that uses the instance, such as the following:
def display[T](t: T)(implicit show: Show[T]) = "show: " + show.print(t) + "\n"
So assuming display is defined, how do we invoke display, passing along an appropriate Show instance. I.e. something that invokes display(x) properly.
Miles Sabin accomplishes this here using runtime compilation (Scala eval), as an example of "staging", but with only spare documentation as to what's going on:
https://github.com/milessabin/shapeless/blob/master/examples/src/main/scala/shapeless/examples/staging.scala
Can Miles's approach be put into a library? Also, what are the limitations of this approach e.g. with respect to generic types like Seq[T]?
Part II
Now suppose T is bounded by a sealed type (such that it's possible to enumerate all the sub-types):
trait Show[T <: Foo]
sealed trait Foo
case class Alpha(..) extends Foo
case class Beta(..) extends Foo
In this case, can we do it with a macro instead of runtime compilation? And can this functionality be provided in some library?
I mostly care about Scala 2.12, but it's worth mentioning if a solution works in 2.11 or 2.10.
I'm playing around with value classes (class that extends AnyVal) in Scala 2.10.3 but are running into a strange compiler error when using them as parameter to abstract methods.
As the following example demonstrates:
class ValueClass(val x: Int) extends AnyVal
trait Test {
def foo(v: ValueClass): Int
}
new Test {
override def foo(v: ValueClass): Int = 1
}
The compiler spits out the following error:
error: bridge generated for member method foo: (v: ValueClass)Int in anonymous class $anon
which overrides method foo: (v: ValueClass)Int in trait Test
clashes with definition of the member itself;
both have erased type (v: Int)Int
override def foo(v: ValueClass): Int = 1
Why doesn't this work? And is there a way to pass a value class into an abstract method?
So as others noted, this issue has been fixed in later versions. If you are curious at all as to what was changed, I suggest you take a look into this pull request.
SI-6260 Avoid double-def error with lambdas over value classes Post-erasure of value classs in method signatures to the underlying
type wreaks havoc when the erased signature overlaps with the generic
signature from an overriden method. There just isn't room for both.
But we really need both; callers to the interface method will be
passing boxed values that the bridge needs to unbox and pass to the
specific method that accepts unboxed values.
This most commonly turns up with value classes that erase to Object
that are used as the parameter or the return type of an anonymous
function.
This was thought to have been intractable, unless we chose a different
name for the unboxed, specific method in the subclass. But that sounds
like a big task that would require call-site rewriting, ala
specialization.
But there is an important special case in which we don't need to
rewrite call sites. If the class defining the method is anonymous,
there is actually no need for the unboxed method; it will only ever
be called via the generic method.
I came to this realisation when looking at how Java 8 lambdas are
handled. I was expecting bridge methods, but found none. The lambda
body is placed directly in a method exactly matching the generic
signature.
This commit detects the clash between bridge and target, and recovers
for anonymous classes by mangling the name of the target method's
symbol. This is used as the bytecode name. The generic bridge forward
to that, as before, with the requisite box/unbox operations.
I'm new to scala. I tried this code:
val name = "mike"
println(name.getClass())
It's OK and printed java.lang.String
But, when I try:
val num = 123
println(num.getClass())
There is such a compiler error:
type mismatch; found : Int required: ?{val getClass: ?} Note: primitive types are not implicitly
converted to AnyRef. You can safely force boxing by casting x.asInstanceOf[AnyRef].
I remember scala said "Everything is object in scala", why can't I invoke num.getClass()? And how to fix it?
Yep, everything is an object, but not necessary an instance of a java class/something with a getClass() method :)
Java primitive values (and Unit) are AnyVals in scala (instances of so called value classes), and - whenever it's possible - they are compiled to Java primitives at the end. When it's not possible boxing is done (similar to auto boxing in Java). But - as the error reports - boxing did not happen ("implicitly") in your case. Value classes don't have a getClass() method -> compilation error.
Java classes are AnyRefs (an instance of a reference class = a class instance in Java). getClass will work fine on them: AnyRef is practically the same as java.lang.Object -> it also has a getClass() method that you can call.
As the error recommends you can force the boxing, then getClass() will work on it:
num.asInstanceOf[AnyRef].getClass
will print
class java.lang.Integer
If you want to avoid boxing (e.g. you want to differentiate between primitive and boxed values) have a look at HowTo get the class of _ :Any
The getClass method is only available for reference classes (i.e. scala.AnyRef). 123 is member of a value class (i.e. scala.Any) and thus does not have a getClass method.
See http://www.scala-lang.org/node/128 for the Scala object hierarchy. And www.scala-lang.org/docu/files/api/scala/AnyRef.html for AnyRef.
Everything is object doesn't mean every object has a method getClass.
As the compiler says, 123.asInstanceOf[AnyRef].getClass would work.