In the following code:
trait Base {
val foo: String = {
println("Hi, I'm initializing foo in trait Base")
"foo"
}
}
class Overrider extends Base {
override val foo = "bar!"
}
object Runner extends App {
println(new Overrider().foo)
println((new {override val foo = "baz"} with Base).foo)
}
Base trait's foo value initialisation is called regardless of whether I override the val by extending the trait or using an early initialiser:
Hi, I'm initializing foo in trait Base
bar!
Hi, I'm initializing foo in trait Base
baz
Is there a way to use vals and avoid that happening or should I just stick with lazy vals?
Either use lazy val as you mentioned or def. AFAIK there is no other way to avoid the initialization of vals in base classes. This is because everything outside class member definitions goes into the constructor. Therefore vals will be initialized on construction time.
Another approach would be to define an interface which you extend from:
trait Base {
def foo: String
}
class Foo extends Base {
override val foo = "foo"
}
class Bar extends Base {
override val foo = "bar"
}
As other users answered to your question, you have to define foo as a def if you do not want the Base trait method being valuated.
You told to me in the comments of your question that you were trying to implement a wiring module, as the one described in this link. Then, you're basically trying to implement the thin cake pattern.
In this case, it is not logically correct to declare foo as a val. foo represents a dependency that cannot be eagerly resolved . If you use a val, the two components will be tight coupled. You've to define foo as a def to let to your main application (or test) to wire foo to the correct type, i.e. a concrete class or a mock.
Let me know if you want some more explanations.
Related
Say I have a case class like this:
final case class Foo(a : String)
and I want to have a method that operates on Foo. Then I can do:
final case class Foo(a : String){
def m : Int = a.toInt
}
or I could do
object Foo{
def m (f : Foo) : Int = f.a.toInt
}
Which one is best or what are advantages and disadvantages of each?
Actually you're asking what is the difference between x.m() and m(x). The difference is how method is resolved. There can be different methods with the same name m.
In the case x.m() method is resolved dynamically, at runtime (overriding, late binding, subtype polymorphism)
class Foo {
def m(): Unit = println("Foo")
}
class Bar extends Foo {
override def m(): Unit = println("Bar")
}
val x: Foo = new Bar
x.m() // Bar
In the case m(x) method is resolved statically, at compile time (overloading, early binding, ad hoc polymorphism)
class Foo
class Bar extends Foo
def m(x: Foo): Unit = println("Foo")
def m(x: Bar): Unit = println("Bar")
val x: Foo = new Bar
m(x) // Foo
One of classes Foo, Bar can be a case class.
The latter approach ("statical") can be implemented also with type classes rather than overloading
trait DoM[T] {
def m(t: T): Unit
}
def m[T](t: T)(implicit dm: DoM[T]): Unit = dm.m(t)
class Foo
class Bar extends Foo
implicit val fooDoesM: DoM[Foo] = _ => println("Foo")
implicit val barDoesM: DoM[Bar] = _ => println("Bar")
val x: Foo = new Bar
m(x) // Foo
Conceptually at least, a method on a class is usually an operation that transforms an instance.
You can picture the lifecycle of an object like this:
A -----> MyType -----> Mytype ----> B
\___/ \___/ \___/
| | |
construct transform eliminate/consume/fold
It is customary to put constructors in the companion object and transformations in the class definition.
In Scala 3 I found the following pattern useful:
Put core / small methods in the class itself
Put bigger / less common methods in an extension section.
These two are meant for very different use-cases, so there should not be any comparision between them.
Anything which can be thought of as the "behaviour" of an object instance and is kind of intrinsic to the object is better to be implemented as class / case class methods.
This point is also related to shared behaviours and inheritance. It will be very cumbersome to manage behaviour overrides in inheritance hierarchies using companion objects. This will be pretty much impossible (and very ugly) to manage for anything which not sealed.
It will also allow you to easily refactor your code, in-case you need to abstract out this case class as a trait in future.
Anything which feels like an utility on top of the object instance can go to companion object, factory manager object or some util object.
Given:
class Foo(x: Int) {}
object Foo {
def apply(x: Int) = new Foo(x)
}
Besides marking Foo's constructor as private, how can I present a warning or compile-time failure when calling new Foo(...)?
In other words, I'd like to restrict (either by compile-time warning or error) construction of Foo to Foo.apply.
Is this possible?
In scala there are two idiomatic ways how to achieve that.
Constructor private to the class and companion object.
Factory has access to constructor, while anyone else doesn't:
class Foo private[Foo](val x: Int)
object Foo {
def apply(x:Int) = new Foo(x)
}
val foo = new Foo(1) // cannot compile
val foo1 = Foo(1) //compiles fine
Sealed abstract class.
In scala sealed class can be extended only in the same source file it is defined.
I suggest to make Foo sealed abstract class and return anonymous child of Foo in object's apply method.
sealed abstract class Foo(val x:Int)
object Foo {
def apply(x:Int):Foo = new Foo(x) {}
}
In this case Foo can be created nowhere except the file where it is defined.
UPD: Actually, this question was already discussed on stackoverflow.
UPD2: Added brief overview of both methods.
If a class inherits from a trait, and they both share a parent, it seems as if overriding an attribute of the parent will make it inaccessible from the trait. Namely
class TestClass(arg: String) extends Parent(arg) with TestTrait {
override val foo = "hey"
}
trait TestTrait extends Parent {
val bar = foo
}
abstract class Parent(arg: String) {
val foo = arg
}
Then running
val c = new TestClass("hello")
c.bar
will return null. This seems like counterintuitive behavior for me. Could anyone explain what the general inheritance rules and rationale behind them are to me?
EDIT: Thanks for the responses. However, I'm still confused as to why this works then:
class TestClass(arg: String) extends Parent(arg) with TestTrait {
// override val foo = "hey"
}
trait TestTrait extends Parent {
val bar = foo
}
abstract class Parent(arg: String) {
val foo = arg
}
Running the same as before will successfully produce "hello". Based on the explanations provided, I would've have expected null again. Sorry for not provided this context in the original phrasing.
Normally, val s are evaluated in sequence, meaning both in-type declaration sequence, and inheritance declaration sequence.
If there would be no override, bar would be evaluated based on the definition from the Parent constructor, since it is executed before the TestTrait constructor (because TestTrait is a subtype of Parent). So, bar would have whatever value it has in Parent.
However, since you override foo in TestClass, the evaluation takes place only once TestClass's constructor gets invoked, and this is after TestTrait.
The best rationale I could find for this in the SLS is within 5.3.1:
The signature and the self constructor invocation of a constructor
definition are type-checked and evaluated in the scope which is in
effect at the point of the enclosing class definition, augmented by
any type parameters of the enclosing class and by any early
definitions of the enclosing template. The rest of the constructor
expression is type-checked and evaluated as a function body in the
current class.
(emph. mine)
Implying the following pseudocode:
class TestClass(arg: String) extends Parent(arg) with TestTrait {
Parent(arg) //arg is ignored, since TestClass overrides foo.
TestTrait() //foo is still null at this point
override val foo = "hey"
}
Essentially boiling down to the same case as:
class A {
val a: String = b //a will be null, since b is not yet evaled
val b = "A"
}
(only without the luxury of a compiler warning)
In hindsight, this quirk is in fact hinted by Scala's language feature of early definitions. With your code, its use would look like the following:
class TestClass(arg: String) extends {
override val foo = "hey"
} with Parent(arg) with TestTrait
trait TestTrait extends Parent {
val bar = foo
}
abstract class Parent(arg: String) {
val foo = arg
}
scala> new TestClass("hello").bar
res0: String = hey
That's because constructors are executed top to bottom (from less derived type to most derived type).
Which means TestTrait is constructed before TestClass -> which means foo is null while TestTrait is being constructed.
Parent (arg = null, foo = null)
\
\
TestTrait (bar = null) Parent(arg = "hello", foo = "hello")
\ /
\ /
TestClass(arg = "hello", foo = "hey")
This may seem surprising, because dynamic dispatch works the other way around - methods are called on the most derived type first, and then on less derived types (if super.method() is invoked).
But there's a good reason for this: the initialization of a type often depends on the correct initialization of its base type.
Is there any way to do anything like this:
scala> trait Foo { def f:Int=0 }
defined trait Foo
scala> class FooImpl extends Foo { override val f = 1 }
defined class FooImpl
scala> class Bar(foo:Foo) extends Foo{ import foo._ }
defined class Bar
scala> (new Bar(new FooImpl)).f
res2: Int = 0
scala> trait Foo { def f:Int }
defined trait Foo
scala> class Bar(foo:Foo) extends Foo{ import foo._ }
<console>:8: error: class Bar needs to be abstract, since method f in trait Foo of type => Int is not defined
class Bar(foo:Foo) extends Foo{ import foo._ }
^
scala>
...in a way that would result in a subclass overriding a parent method via import? Basically I think it would be interesting to be able to use composition without all the typing. Just curious if anything like this is possible.
What you are really asking for is a way to delegate method implementations to a member.
That issue has already been addressed here: Proxies / delegates in Scala
Basically, there is a way to do it using macros. An implementation can be found here: https://github.com/adamw/scala-macro-aop
The above provides a #delegate macro annotation that can be applied to a data member to cause the compiler to generate code to delegate method calls to that member. Note that macro annotations are an experimental feature planned for Scala 2.11, but you can use them with Scala 2.10 using the Macro Paradise compiler plugin.
Self-typing can help here (depending on exactly how you will be working with these classes - this isn't composition of instances, more composition of types):
trait Foo { def f:Int }
trait FooImpl extends Foo { override val f = 1 } // Needs to be a trait to be mixed in.
class Bar {
this: Foo => // This requires that any Bar instance must mix in a Foo (must 'be' a Foo)
}
Then you can instantiate and use your Bar instance similar to the following:
scala> (new Bar with FooImpl).f
res1: Int = 1
If I understand correctly, traits are the closest thing to Java interfaces and class constructors automatically set the variables.
But what if I have a class that extends a trait and has a constructor which sets a variable from the trait, so something like:
trait Foo {
var foo: String
}
class Bar (foo: String) extends Foo { /* ... */ }
Where I want the foo string of the trait been set when I make a Bar object.
The compiler seems to give me errors about this. What is the correct way to achieve this?
trait Foo { var foo: String = _ }
class Bar(foo0: String) extends Foo { foo = foo0 }
The trait declares an uninitialized var; the class then sets it equal to the input parameter.
Alternatively,
trait Foo {
def foo: String
def foo_=(s: String): Unit
}
class Bar(var foo: String) extends Foo {}
declares the getter/setter pair corresponding to a foo, which are set by the class.
Bar must define the abstract var foo in Foo (would be the same for a val). This can be done in the constructor
class Bar(var foo: String) extends Foo{...}
(of course, it could be done in the body of Bar too). By default, constructor parameters will be turned to private val if need be, that is if they are used outside the initiailization code, in methods. But you can force the behavior by marking them val or var, and possibly control the visibility as in
class X(protected val s: String, private var i: Int)
Here you need a public var to implement Foo.