I noticed there is a type mismatch caused in the line else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}. Because there is no else clause to my if ... else if ...
def euclidianDivision(dividend:Int,divisor:Int):(Int,Int)={
val quotient = dividend/divisor
val remainder = dividend%divisor
(quotient,remainder)
}
def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
val div1:Int = divisors.head
val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
if (divisors.tail.contains(r1)){
firstExpansionIter(r1,divisors.tail,newAcc)
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
}
firstExpansionIter(dividend,divisors,List((0,0))).tail
}
Here's the error code:
Error:(32, 15) type mismatch; found : Unit required: List[(Int,
Int)]
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?
N.B : Corrected code :
def firstExpansion(dividend:Int,divisors:List[Int]):List[(Int,Int)]={
def firstExpansionIter(dividend:Int,divisors:List[Int], acc:List[(Int,Int)]):List[(Int,Int)]= {
val div1:Int = divisors.head
val (q1,r1):(Int,Int) = euclidianDivision(dividend,div1)
val newAcc:List[(Int,Int)] = acc:::List((div1,q1))
if (divisors.tail.contains(r1)){
firstExpansionIter(r1,divisors.tail,newAcc)
}else if(r1 == 0 || divisors.tail.isEmpty || !divisors.tail.contains(r1)){newAcc}
else throw new RuntimeException("Something unexpected happened.")
}
firstExpansionIter(dividend,divisors,List((0,0))).tail
}
I can correct this by adding the else clause, but how come if there is no outcome handled by default, the function tries to return a Unit?
In Scala, unlike more "imperative" languages, (almost) everything is an expression (there are very few statements), and every expression evaluates to a value (which also means that every method returns a value).
This means that, for example, the conditional expression if (condition) consequence else differentConsequence is an expression that evaluates to a value.
For example, in this piece of code:
val foo = if (someRandomCondition) 42 else "Hello"
the then part of the expression will evaluate to 42, the else part of the expression will evaluate to "Hello", which means the if expression as a whole will evaluate to either 42 or "Hello".
So, what is the type of foo going to be? Well, in the then case, the value is of type Int and in the else case, the value is of type String. But, this depends on the runtime value of someRandomCondition, which is unknown at compile time. So, the only choice we have as the type for the whole if expression is the lowest common ancestor (technically, the weak least upper bound) of Int and String, which is Any.
In a language with union types, we could give it a more precise type, namely the union type Int | String. (Scala 3 has union types, so we could give the expression this exact type, although Scala 3 will not infer union types.) In Scala 3, we could even annotate it with the even more precise type 42 | "Hello", which is actually the type that TypeScript is going to infer for the equivalent conditional expression:
const foo = someRandomCondition ? 42 : "Hello"
Now, let's move forward towards the code in the question:
val bar = if (someRandomCondition) 42
What is the type of bar going to be? We said above that it is the lowest common ancestor of the types of the then and else branch, but … what is the type of the else branch? What does the else branch evaluate to?
Remember, we said that every expression evaluates to a value, so the else branch must evaluate to some value. It can't just evaluate to "nothing".
This is solved by a so-called unit value of a unit type. The unit value and type are called the "unit" value and type, because the type is designed in such a way that it can only possibly be inhabited by a single value. The unit type has no members, no properties, no fields, no semantics, no nothing. As such, it is impossible to distinguish two values of the unit type from one another, or put another way: there can only be one value of the unit type, because very other value of the unit type must be identical.
In many programming languages, the unit value and type use the same notation as a tuple value and type, and are simply identified with the empty tuple (). An empty tuple and a unit value are the same thing: they have no content, no meaning. In Haskell, for example, both the type and the value are written ().
Scala also has a unit value, and it is also written (). The unit type, however, is scala.Unit.
So, the unit value, which is a useless value, is used to signify a meaningless return value.
A related, but different concept in some imperative languages is the void type (or in some languages, it is more a "pseudo-type").
Note that "returns nothing" is different from "doesn't return", which will become important in the second part of this answer.
So the first half of the puzzle is: the Scala Language Specification says that
if (condition) expression
is equivalent to
if (condition) expression else ()
Which means that in the (implicit) else case, the return type is Unit, which is not compatible with List[(Int, Int)], and therefore, you get a type error.
But why does throwing an exception fix this?
This brings us to the second special type: Nothing. Nothing is a so-called bottom type, which means that it is a subtype of every type. Nothing does not have any value. So, what then, would a return type of Nothing signify?
It signifies an expression that doesn't return. And I repeat what I said above: this is different from returning nothing.
A method that has only a side-effect returns nothing, but it does return. Its return type is Unit and its return value is (). It doesn't have a meaningful return value.
A method that has an infinite loop or throws an exception doesn't return at all. Its return type is Nothing and it doesn't have a return value.
And that is why throwing an exception in the else clause fixes the problem: this means that the type of the else clause is Nothing, and since Nothing is a subtype of every type, it doesn't even matter what the type of the then clause is, the lowest common supertype of the type of the then clause and Nothing will always be the type of the then clause. (Think about it: the lowest common ancestor of a father and any of his children, grandchildren, great-grandchildren, etc. will always be the father himself. The lowest common ancestor of T and any subtype of T will always be T. Since Nothing is a subtype of all types, the lowest common ancestor of T and Nothing will always be T because Nothing is always a subtype of T, no matter what T is.)
Why I cannot check whether a type is Null?
scala> val s:String = null
s: String = null
scala> s.isInstanceOf[Null]
<console>:13: error: type Null cannot be used in a type pattern or isInstanceOf test
s.isInstanceOf[Null]
^
The general contract of x.isInstanceOf[C] is to return true if and only if x is an instance of C. Being "an instance of" anything implies that x is not null.
According to that specification, x.isInstanceOf[Null] must always return false, since x would not be an instance of Null even if it happens to be null. The compiler protects you from that confusion by refusing to compile that test instead.
The idiomatic way to test whether x is null is to simply use
x == null
A more correct way to check for equality with null, since you want to look for reference equality explicity.
x eq null
From the API doc I found that Null is a trait, but it says its sole instance is null.
abstract final class Null extends AnyRef
Null is - together with scala.Nothing - at the bottom of the Scala type hierarchy.
Null is a subtype of all reference types; its only instance is the null reference. Since Null is not a subtype of value types, null is not a member of any such type. For instance, it is not possible to assign null to a variable of type scala.Int.
How is it possible to instantiate a trait? Any simple example to realize this concept would really helpful.
You cannot instantiate an instance of the class Null, as it is abstract and final. Null is a figment of the compiler similar Nothing, used as a bottom-type for all reference types. That is, Null is a sub-type of any other type that inherits from AnyRef. Its only value is the null reference, but there is no way to instantiate the Null class and magically get a null reference. It differs from Nothing in that it is inhabited by a single value: null.
Therefore, if you assign null to an identifier, Null will be inferred as its type if you don't hint otherwise.
scala> val a = null
a: Null = null
According to the scala docs:
Null is a subtype of all reference types;
So in theory, in this example we can assume Null is a subtype of Foo (a reference type) and that we should be able to attempt to call the bar method on an instance of type Null. In practice we can't and the code snippet fails at compile time with the error value bar is not a member of Null.
case class Foo(bar: String)
val n: Null = null
n.bar
Try it
I think it makes sense that we catch this at compile time because as the scala docs also say [Null's] only instance is the null reference, however I think a better error message would be Calling bar on type Null can only result in a NullPointerException.
My question is regarding the following code snippet, which doesn't fail at compile time and instead fails at runtime with a NullPointerException
val n: Null = null
n.toString
Try it
I am assuming this is because the Null type doesn't truly subclass every other reference type and only subclasses AnyRef, but is there any reason why this shouldn't throw a compile time error (or at least warning) that this code can only result in a NullPointerException? Is it deliberate that calling null.bar and null.toString behave differently?
Null is a subtype of all reference types; - this means something like that:
val n: Foo = null
n.bar //throws NPE
val a: String = null
a.charAt(0) //NPE again
So you can say Null is a subtype of all reference types.
edit: The
val n: Null = null
n.bar
part is incorrect. According to Scala docs:
abstract final class Null extends AnyRef
AnyRef doesnt' have a bar. You cannot say like this, right?
val n: AnyRef = ""
n.charAt(0) //won't compile
I just read this question and stumbled upon the following quote:
Scala treats == as if it were defined as follows in class Any:
final def == (that: Any): Boolean =
if (null eq this) (null eq that) else (this equals that)
The (null eq this) part made me wonder: Is it actually possible to call methods on null pointers? Can this be null in Scala?
Check out the Scala language specification, namely 6.3 The Null Value chapter:
The null value is of type scala.Null, and is thus compatible with every reference
type. It denotes a reference value which refers to a special “null” object. This object
implements methods in class scala.AnyRef as follows:
• eq(x) and ==(x) return true if the argument x is also the “null” object.
• ne(x) and !=(x) return true if the argument x is not also the “null” object.
This means that semantically when you compare something with null literal or null literal with something you are actually referring to method of a special scala.Null class. Treat null literal as a shorthand for that class.
Of course at the implementation level it is optimized and ordinary null is used.
null is the only instance of Null class and it's a valid object. Null is a subtype of all reference types.
I'm pretty new to Scala, but the only way I see that as being possible is due to the fact that "null" itself is an instance of Null, and not exactly a special value like "null" in Java.
http://blog.sanaulla.info/2009/07/12/nothingness/
This article helped me understand this a bit better.