views:

140

answers:

3

What is the difference between declaring a field as val, lazy val and object inside a scala class, as in the following snippet:

class A

class B {
  val a1 = new A      { def foo = 1 }
  object a2 extends A { def foo = 1 }
  lazy val a3 = new A { def foo = 1 }
}
+3  A: 

I suppose one difference is that a1 will be of one subtype of A while a2 will be of another subtype of A namely a2.type.

scala> class A
defined class A

scala> val a1 = new A {def foo = 1}
a1: A{def foo: Int} = $anon$1@a9db0e2

scala> object a2 extends A {def foo = 1}
defined module a2

scala> a1
res0: A{def foo: Int} = $anon$1@a9db0e2

scala> a2
res1: a2.type = a2$@5b25d568

scala> 
aioobe
Not exactly. Both will be subclasses of `A`.
PeWu
Sure, but they will not be of the same type.
aioobe
To be more precise a2 will have a type a2.type.
venechka
Notice that your example Scala output contradicts what you say in the first sentence of your answer: the type of `a1` is *not* `A`; the type is the type of the anonymous subclass you created. You can make it an `A` by explicitly specifying the type: `val a1: A = new A {def foo=1}`
Jesper
@Jesper: in this specific example, yes. He did raise a valid point, however. Using an `object` *always* creates a new type, whereas using a `val` does not (unless you add behavior as in this case).
Aaron Novstrup
+7  A: 

In the former, any code included is executed as soon as class B is created. In the latter, however, until you actually use the object, it won't be instantiated.

You can see the difference here:

class A { println("Creating a new A") }
class B {
  val a1 = new A { println("a1"); def foo = 1 }
  object a2 extends A { println("a2"); def foo = 1 }
}

scala> val b = new B
Creating a new A
a1
b: B = B@1176e8a

scala> b.a2.foo
Creating a new A
a2
res0: Int = 1

There are also hidden differences in what the created .class files are named and such; and of course the two have different types.

Rex Kerr
So `object` works like `lazy val`. Are there any _practical_ differences between the two?
PeWu
Inherently, no, not as far as I know. The bytecode for `object` is a bit more compact. I'm not sure whether that means that `lazy val` is written inefficiently, or whether `object` might be unsafe under certain threading conditions, or both.
Rex Kerr
Or not as far as I remembered at that moment. See Alex Boisvert's comment for a critical difference!
Rex Kerr
Ouch! These two differences remind me the C++ gotchas (an object is just like a val, except that it is lazy, and except that when it is the field of a class and it is inherited, it cannot be overriden. Ouch. Maybe we should just use `lazy val`s instead of objects!
Elazar Leibovich
For what it's worth, lazy vals do seem to be preferred to object members in the Scala code I've read. If you see an object member in the wild, it's probably from pre-2.6 Scala, when lazy vals were introduced.
Dave Griffith
+9  A: 

One major difference is that val's can be overriden while objects can't.

class C extends B {                           
  override val a1 = new A { def foo = 2 }     
  override object a2 extends A { def foo = 2 }
}

leads to:

<console>:9: error: overriding object a2 in class B of type object C.this.a2;
object a2 cannot be used here - classes and objects cannot be overridden
override object a2 extends A { def foo = 2 }
Alex Boisvert