I'm trying to write a Scala function that returns the default value of a type (0, 0.0, false, '\0', etc. for value types and null for reference types). I came up with this:
def defaultValue[U]: U = {
class Default[U] { var default: U = _ }
new Default[U].default
}
and while this works well if called directly, it returns null even for value types when called through a function that itself is generic, as shown in this REPL session:
Welcome to Scala version 2.8.1.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_24).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def defaultValue[U]: U = { class Default[U] {var default: U = _ }; new Default[U].default }
defaultValue: [U]U
scala> defaultValue[Boolean] // direct call works
res0: Boolean = false
scala> var res: Any = 0
res: Any = 0
scala> def setRes[U] = { res = defaultValue[U]; defaultValue[U] }
setRes: [U]U
scala> setRes[Boolean] // returns a Boolean, but...
res1: Boolean = false
scala> res
res2: Any = null // ... sets the res variable to null.
Can someone explain to me:
Objects. Variables of any "Object" type (which includes all the classes you will write) have a default value of null. All member variables of a Newed object should be assigned a value by the objects constructor function.
You can assign a default value for a parameter using an equal to symbol. I gave a default value for the first parameter. If the caller doesn't pass any value for the first parameter, Scala will take the default value as println. That's it.
The object and string types have a default value of null, representing a null reference that literally is one that does not refer to any object.
Here is a more condensed version of your issue:
scala> defaultValue[Boolean]: Any
res0: Any = null
scala> defaultValue[Boolean]: Boolean
res1: Boolean = false
The first version is what applies when you call res = defaultValue[U]
because even though U
is of type Boolean, res
is of type Any
If you compile this little program using the -Xprint:all
option
object Test {
def defaultValue[U]: U = { class Default[U] {var default: U = _ }; new Default[U].default }
def main(args:Array[String]) {
val any = defaultValue[Boolean]: Any
println(any)
val bool = defaultValue[Boolean]: Boolean
println(bool)
}
}
You'll see that right before the erasure phase, you have:
val any: Any = (Test.this.defaultValue[Boolean](): Any);
scala.this.Predef.println(any);
val bool: Boolean = (Test.this.defaultValue[Boolean](): Boolean);
scala.this.Predef.println(bool)
Then at the end of the erasure phase:
val any: java.lang.Object = (Test.this.defaultValue(): java.lang.Object);
scala.this.Predef.println(any);
val bool: Boolean = (scala.Boolean.unbox(Test.this.defaultValue()): Boolean);
scala.this.Predef.println(scala.Boolean.box(bool))
So what happens is that under the hood defaultValue[Boolean]
returns null in both cases, but then null is unboxed into false when the return type is a Boolean. You can verify that in the REPL:
scala> Boolean.unbox(null)
res0: Boolean = false
scala> null.asInstanceOf[Boolean]
res1: Boolean = false
Edit: I had an idea - not that I'm recommending it. Not sure what your use case is (res = false
seems easier to me..)
scala> def f[@specialized U] = { class X { var x: U = _ }; (new X).x }
f: [U]U
scala> var res: Any = _
res: Any = null
scala> def g[@specialized U] = { res = f[U]; f[U] }
g: [U]U
scala> g[Boolean]
res0: Boolean = false
scala> res
res1: Any = false
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With