class Int is abstract; cannot be instantiated - scala

While going through Programming in Scala, i came across:
While you can define your own value classes (see Section 11.4), there
are nine value classes built into Scala: Byte, Short, Char, Int, Long,
Float, Double, Boolean, and Unit. The first eight of these correspond
to Java's primitive types, and their values are represented at run
time as Java's primitive values. The instances of these classes are
all written as literals in Scala. For example, 42 is an instance of
Int, 'x' is an instance of Char, and false an instance ofBoolean. You
cannot create instances of these classes using new. This is enforced
by the "trick" that value classes are all defined to be both abstract
and final.
Due to which new Int gives the error class Int is abstract; cannot be instantiated
val a: Int = new Int in Scala. Java allows new Integer(23).
Question: What is the trick the author is taking about. Why Scala defines value classes to be abstract and final.

What is the trick the author is taking about ?
The "trick" is that
when a class is abstract, you cannot make instances of it (cannot call new).
when a class is final, you cannot make subclasses
when a class is abstract and you cannot make subclasses, then you also cannot make a concrete subclass that you could instantiate
So as a result, value classes cannot be instantiated by application code.
Why Scala defines value classes to be abstract and final.
The point of value classes is that they are defined by their (immutable) value/contents. The object identity is not relevant.
The Scala compiler also tries to optimize value classes by not creating any objects at all where possible (just using unboxed primitives directly). That only works if we can be sure that you can just box and unbox at will.
In Java new Integer(1) and another new Integer(1) are two different objects, but that is not useful for a pure value class (if you want to use these different instances as lock monitor objects or something else where you need object identity, you are just confusing yourself and others and should not have used Integer).

Related

How are primitives types objects in Scala?

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.

Passing Scala objects as Java Object to Java methods

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

why scala value class#toString contains case class info?

value classes can be used to achieve type safety without the overhead of unboxing.
I had the impression that in runtime such types/classes would "not exist", being seen as simple types (for instance, a value class case class X(i: Int) extends AnyVal would be a simple Int on runtime).
But if you do call a .toString method on a value class instance it would print something like:
scala> val myValueClass = X(3)
myValueClass: X = 3
scala> myValueClass.toString
res5: String = X(3)
so I guess the compiler includes some information after all?
Not really. The compiler creates a static method (in Scala this corresponds to the class's companion object) which is called with your int value as a parameter in order to simulate calling a method on your value class-typed object.
Your value class itself only exists in the source code. In compiled bytecode an actual primitive int is used and static methods are called rather than new object instances with real method calls. You can read more about this mechanism here.
Value classes are designed so that adding or removing extends AnyVal (if legal) shouldn't change the results of calculations (except even non-case value classes have equals and hashCode defined automatically like case classes). This requires that in some circumstances they survive, e.g.
def toString(x: Any) = x.toString
toString(myValueClass)
but the situation in your question isn't one of them.
http://docs.scala-lang.org/sips/completed/value-classes.html#expansion-of-value-classes explains more precisely how value classes are implemented and is useful to see in what cases they survive, though some details may have changed since.

Scala's hierarchy mapped to Java's

As "Programming in Scala: A comprehensive step-by-step Guide" states, in Scala there are not basic types values, just objects: Integers are Int instances and doubles are Double instances. I assume that these classes map to Java's Integer, Double ... classes and, therefore, are mapped as Object subclasses.
In the book, the following type hierarchy (classes as types) is presented:
Few pages after this graph is presented, you can read:
What somehow troubles me is: If Scala´s Double maps to Java's Double which is an specification of java.lang.Object and AnyRef is an alias for java.lang.Object too, should't AnyVal be a subclass of AnyRef?
EDIT
Few pages after that I read that primitive types are not mapped to Java's primitive types wrapper classes unless their "boxed" versions are required; but I am still confused since it seems to me that not all Scala's objects are java.lang.Object sublcasses instances. That is: There are classes in Scala which could be not translated in the JVM as Object subclasses.
Java does not only have types that extend java.lang.Object (aka scala.AnyRef), but primitive types, e.g. int, double, boolean, ... In Scala you find them under scala.Any. So a scala.Int corresponds to a Java int. Not java.lang.Integer; not until boxing occurs, a mechanism on the JVM to be able to pass primitives to generic methods. Both Java and Scala do auto-boxing, that is construct a reference around a primitive type when a reference is needed.
The difference in Scala is, it doesn't treat scala.Int any different from say String, it doesn't matter whether the type corresponds to a JVM primitive or not. You can call methods on scala.Int as if it was any regular object. In the byte-code you will still have primitive types.
This is why Scala is sometimes called a true or more pure object-oriented language than Java.

Why does Int not inherit/extend from Ordered[Int]

I have a question on type design. Why does Int not extend the Ordered trait. Isn't Int ordered by nature?
Instead, the scala library provides implicit 'orderer' methods which convert Int to Ordered[Int]. What are the design choices being made here?
Example taken from the book Programming in Scala
def maxListImpParm[T <% Ordered[T]](elements:List[T]):T= ...
maxListImpParm(List(1,5,10,3)) // works because of implicit methods
Because Int (and some other classes inherited from AnyVal) is ephemeral -- at runtime it usually represented by primitive value which has no notion of class (and thus inheritance) at all. Of course, there are exceptions, like Int boxing to full blown reference class instance when you put item in collection, but typeclass provides one universal solution. Moreover, typeclasses are more flexible than inheritance.