While object
declarations have a different semantic than a new
expression, a local object
declaration is for all intents and purpose the same thing as a lazy val
of the same name. Consider:
class Foo( name: String ) {
println(name+".new")
def doSomething( arg: Int ) {
println(name+".doSomething("+arg+")")
}
}
def bar( x: => Foo ) {
x.doSomething(1)
x.doSomething(2)
}
def test1() {
lazy val a = new Foo("a")
bar( a )
}
def test2() {
object b extends Foo("b")
bar( b )
}
test1
defines a
as a lazy val initialized with a new instance of Foo
, while test2
defines b
as an object
extending Foo
.
In essence, both lazily create a new instance of Foo
and give it a name (a
/b
).
You can try it in the REPL and verify that they both behave the same:
scala> test1()
a.new
a.doSomething(1)
a.doSomething(2)
scala> test2()
b.new
b.doSomething(1)
b.doSomething(2)
So despite the semantic differences between object
and a lazy val
(in particular the special treatment of object
's by the language, as outlined by Daniel C. Sobral),
a lazy val
can always be substituted with a corresponding object
(not that it's a very good practice), and the same goes for a lazy val
/object
that is a member of a class/trait.
The main practical difference I can think of will be that the object has a more specific static type: b
is of type b.type
(which extends Foo
) while a
has exactly the type Foo
.