I was going through the effective scala slides and it mentions on slide 10 to never use val in a trait for abstract members and use def instead. The slide does not mention in detail why using abstract val in a trait is an anti-pattern. I would appreciate it if someone can explain best practice around using val vs def in a trait for abstract methods
A def can be implemented by either of a def, a val, a lazy val or an object. So it's the most abstract form of defining a member. Since traits are usually abstract interfaces, saying you want a val is saying how the implementation should do. If you ask for a val, an implementing class cannot use a def.
A val is needed only if you need a stable identifier, e.g. for a path-dependent type. That's something you usually don't need.
Compare:
trait Foo { def bar: Int }
object F1 extends Foo { def bar = util.Random.nextInt(33) } // ok
class F2(val bar: Int) extends Foo // ok
object F3 extends Foo {
lazy val bar = { // ok
Thread.sleep(5000) // really heavy number crunching
42
}
}
If you had
trait Foo { val bar: Int }
you wouldn't be able to define F1 or F3.
Ok, and to confuse you and answer #om-nom-nom—using abstract vals can cause initialisation problems:
trait Foo {
val bar: Int
val schoko = bar + bar
}
object Fail extends Foo {
val bar = 33
}
Fail.schoko // zero!!
This is an ugly problem which in my personal opinion should go away in future Scala versions by fixing it in the compiler, but yes, currently this is also a reason why one should not use abstract vals.
Edit (Jan 2016): You are allowed to override an abstract val declaration with a lazy val implementation, so that would also prevent the initialisation failure.
I prefer not use val in traits because the val declaration has unclear and non-intuitive order of initialization. You may add a trait to already working hierarchy and it would break all things that worked before, see my topic: why using plain val in non-final classes
You should keep all things about using this val declarations in mind which eventually road you to an error.
Update with more complicated example
But there are times when you could not avoid using val. As #0__ had mentioned sometimes you need a stable identifier and def is not one.
I would provide an example to show what he was talking about:
trait Holder {
type Inner
val init : Inner
}
class Access(val holder : Holder) {
val access : holder.Inner =
holder.init
}
trait Access2 {
def holder : Holder
def access : holder.Inner =
holder.init
}
This code produces the error:
StableIdentifier.scala:14: error: stable identifier required, but Access2.this.holder found.
def access : holder.Inner =
If you take a minute to think you would understand that compiler has a reason to complain. In the Access2.access case it could not derive return type by any means. def holder means that it could be implemented in broad way. It could return different holders for each call and that holders would incorporate different Inner types. But Java virtual machine expects the same type to be returned.
I agree with the other answers about avoiding abstract vals for the reason that it provides more options to implementations.
There are cases where you might need them:
For a path-dependent type (as mentioned by #0__).
Where implementations might be expensive and it is used in a concrete def.
(Are there others? If so please comment and I'll add them in).
The more important things to know is when it is safe to override something with a val and to have a lazy val that does not override something.
Rule 1: Never override a val or def with a non-lazy val unless it is a constructor parameter:
trait TraitWithVal {
// It makes no difference if this is concrete or abstract.
val a: String
val b: String = a
}
class OverrideValWithVal extends TraitWithVal {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideValWithLazyVal extends TraitWithVal {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideValWithConstructorVal(override val a: String = "a") extends TraitWithVal
//class OverrideValWithDef extends TraitWithVal {
// // Compilation error: method a needs to be a stable, immutable value.
// override def a: String = "a"
//}
println((new OverrideValWithVal).b) // null
println((new OverrideValWithLazyVal).b) // a
println((new OverrideValWithConstructorVal).b) // a
The same rule applies to a def:
trait TraitWithDef {
// It makes no difference if this is concrete or abstract.
def a: String
val b: String = a
}
class OverrideDefWithVal extends TraitWithDef {
// Bad: b will be null.
override val a: String = "a"
}
class OverrideDefWithLazyVal extends TraitWithDef {
// Ok: b will be "a".
override lazy val a: String = "a"
}
// Ok: b will be "a".
class OverrideDefWithConstructorVal(override val a: String = "a") extends TraitWithDef
class OverrideDefWithDef extends TraitWithDef {
// Ok: b will be "a".
override def a: String = "a"
}
println((new OverrideDefWithVal).b) // null
println((new OverrideDefWithLazyVal).b) // a
println((new OverrideDefWithConstructorVal).b) // a
println((new OverrideDefWithDef).b) // a
You might be wondering whether it would be ok to override a val with another val so long as it isn't used during initialisation. There is at least one edge cases which break this:
trait TraitWithValAndLazyVal {
val a: String = "A"
def b: String = a
}
class OverrideLazyValWithVal extends TraitWithValAndLazyVal {
// Bad: This on its own is ok but not if it is indirectly referenced during initialisation and overridden.
override val a = "a"
val c = b
}
class OverrideValWithVal extends OverrideLazyValWithVal {
override val a = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // a
println((new OverrideValWithVal).c) // null
Given that we already apply this rule to overriding defs then this makes using vals a little more acceptable in my opinion.
If you use a linter to enforce the override keyword and make sure your code never has any override val definitions then you are good.
You might be able to allow final override val but it's possible there are other edge cases that I haven't thought of.
Rule 2: Never use a lazy val that is not overriding another lazy val or def.
As far as I can tell there also is no good reason to have a lazy val that isn't overriding something. All the examples that I can come up with where it is needed, it is needed only because it violates Rule 1 and exposes the edge case I described earlier.
For example:
trait NormalLookingTrait {
def a: String
val b: String = a
}
trait TraitWithAbstractVal extends NormalLookingTrait {
val c: String
}
class OverrideValWithVal extends TraitWithAbstractVal {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal).a) // a
println((new OverrideValWithVal).b) // null
println((new OverrideValWithVal).c) // a
So we make b a lazy val:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
}
println((new OverrideValWithVal2).a) // a
println((new OverrideValWithVal2).b) // a
println((new OverrideValWithVal2).c) // a
Looks ok, except when we go one step further:
trait SuspiciousLookingTrait2 {
def a: String
lazy val b: String = a
}
trait TraitWithAbstractVal2 extends SuspiciousLookingTrait2 {
val c: String
}
class OverrideValWithVal2 extends TraitWithAbstractVal2 {
override def a: String = c
override val c = "a"
val d = b
}
class OverrideValWithVal3 extends OverrideValWithVal2 {
override val c = "a"
}
println((new OverrideValWithVal3).a) // a
println((new OverrideValWithVal3).b) // null
println((new OverrideValWithVal3).c) // a
println((new OverrideValWithVal3).d) // null
I now get what people mean when they say to only use lazy when it is absolutely necessary and never for delayed initialisation.
It's probably safe to break this rule if the trait / class is final but even that smells fishy.
Always using def seems a bit awkward since something like this won't work:
trait Entity { def id:Int}
object Table {
def create(e:Entity) = {e.id = 1 }
}
You will get the following error:
error: value id_= is not a member of Entity
Related
As I understand the semantics of a custom constructor may be typically added to a class via a companion object. Is there then, any way to inherit a custom constructor while inheriting a class?
On the one hand I have found that companion objects are not synthetically inherited along a case class, and on the other, I am not aware of a way of creating custom constructors inside a class itself, so that they are inherited. And yet inheriting custom constructors seems to be a perfectly valid use case to me. So is it supported in some (straightforward) way in Scala?
A naive demonstration of intent:
class A {}
object A {
def apply(n: Int) = {
println(n)
new A
}
}
class B extends A {}
object Test {
val a1 = A
val a2 = A(3)
val b1 = B // compile error
val b2 = B(3) // compile error
P.S. I have even found the arcane/deviant technique of defining this custom constructors result in a custom constructor that does not in actuality get inherited (it does work for just creating custom constructors, but quite oddly and unfortunately those do not get inherited). Demonstrating code:
class A {
def this(n: Int) = {
this
println(n)
}
}
class B extends A {}
object Test {
val a1: A = new A
val a2: A = new A(3)
val b1 = new B
val b2 = new B(3) // compile error
}
Clarification of Intent Edit:
consider "constructor" and "companion factory methods" interchangeable for the sake of this question.
You can't inherit constructors directly, and because you can't you also can't inherit things that use them without a little bit of work. But you can abstract away anything beyond the constructor call.
Let's suppose we have
class Foo(text: String) {
override def toString = "Foo: " + text
}
object Foo {
def apply(text: String) = new Foo(text) // Auto-generated for case class
def apply(i: Int) = new Foo(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
and we then decide to
class Bar(text: String) extends Foo(text) {
override def toString = "Bar: " + text
}
Now, what do we do about object Bar? Instead of writing all the logic over again, we create a trait to separate and abstract the object creation from the computation of the constructor parameter(s):
trait FooCompanionLike[A <: Foo] {
def apply(text: String): A // I am abstract!
def apply(i: Int): A = apply(
if (i > 0) i.toString
else if (i == 0) ""
else s"negative ${0L - i}"
)
}
Now we can
object Foo extends FooCompanionLike[Foo] {
def apply(text: String) = new Foo(text)
}
object Bar extends FooCompanionLike[Bar] {
def apply(text: String) = new Bar(text)
}
So you can't completely escape boilerplate, but you can reduce it to extending from a trait and a single method call.
If you do it this way (where the abstract apply perfectly matches the constructor), you can even get case classes to work without manually defining the abstract apply method in the companion:
case class Baz(text: String) extends Foo(text) {
override def toString = "Baz: " + text
}
object Baz extends FooCompanionLike[Baz] {
// Nothing here! Auto-generated apply works!
}
Short answer: no straightforward way; try to workaround and resist the desire.
Constructors in Scala are defined in the body of the class and take parameters after the class name e.g.
class A(i: Int) {
println(i)
}
The println(i) in this case is the constructor logic. If you now extend A, like this:
class B(i: Int) extends A(i)
and instantiate B, val b1 = new B(2) you'll see that the constructor is indeed inherited.
As you've already found out, Scala allows you to define alternative constructors by defining functions called this. But these alternative constructors must call the primary constructor.
The way I understand it is that there is really only one constructor for any Scala class, the alternative constructors just filter into it. For example:
class A(x: Int, y: Int) {
// do some constructing!
def this(x: Int) = {
this(x, 1) // provide a default value for y
}
}
Suppose I have next traits:
trait A {
val a: String = "a"
}
trait B {
def a: String = "b"
}
And I want to mix both of these traits into some class C
class C extends B with A
Compiler doesn't allow me to create such class because I have to override method a
I want to override it using for example only A's implementaion. How can I do this?
EDIT
scala> class C extends B with A {
| override val a = super.a
| }
<console>:10: error: super may be not be used on value a
override val a = super.a
^
The compiler can't possibly know which one you intend to use, therefore you must specify it like:
class C extends B with A {
override def a = super[A].a
}
This approach allows you to choose the parent directly, regardless the trait order.
However, the traits define a differently (val and def) thus you must choose only one. You should use either def or val in both traits (not mix them).
Provided you make a a def in the A trait, you can do
class C extends B with A {
override val a = super.a
}
val c = new C
c.a // "a"
This will work because A is extended after B, so super will be its implementation.
In Scala, it's possible to specify whether a function or class is covarient or contravarient in the following manner
class Foo[+arg] // covarient
class Bar[-arg] // contravarient
What are the real world uses of this feature?
I know the compiler runs checks to make sure that the stated entity is actually covarient or otherwise, but what is the benefit of even adding such annotations?
The simplest case where your probably already using it without knowing it is the scala collections.
class A()
class B() extends A
case class Container[T](elem : T)
val listOfA:List[A] = List[B](new B(),new B())
val containerOfA:Container[A] = Container[B](new B()) // fails
Imagine you have the following hierarchy:
class A
class B extends A
Covariance. Covariant type can be used as return type:
class Foo[+arg] { // Covariant
def getArg(): arg = ???
}
def testCovariant(): Unit = {
val fooB = new Foo[B]
val foo: Foo[A] = fooB
// returns only objects of class derived from A
// so it is safe
val a: A = foo.getArg()
}
So you can use any of Foo[DerivedClass]where Foo[BaseClass] is used, because anywhere Foo[BaseClass].getArg is called BaseClass is expected as result and any DerivedClass can be returned and assigned to it.
Contravariance. Contravariant type can be used as method parameter type:
class Bar[-arg] { // Contravariant
def setArg(p: arg): Unit = ???
}
def testContravariant(): Unit = {
val barA = new Bar[A]
val bar: Bar[B] = barA
// can set B to bar which is actually Bar[A]
// but Bar[A].setArg(p: A) can accept any object
// of type derived from A
// so it is safe
bar.setArg(new B)
}
Again. You can use any of Bar[DerivedClass] where Bar[BaseClass] is used, because anywhere Bar[DerivedClass].setArg(p: DerivedClass) is called DerivedClass is expected as argument and any Bar[BaseClass] can be used in this context, because you can always pass DerivedClass to Bar[BaseClass].setArg(p: BaseClass).
I have a class that takes an implicit parameter which is used by functions called inside class methods. I want to be able to either override that implicit parameter, or alternatively, have the implicit argument be copied from its source. As an example:
def someMethod()(implicit p: List[Int]) {
// uses p
}
class A()(implicit x: List[Int]) {
implicit val other = List(3) // doesn't compile
def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
someMethod()
}
}
The behavior I want is that someMethod() gets an implicit parameter that is some changed version of x, which was the class's implicit parameter. I want to be able to either mutate x without changing it for whatever passed it into A's constructor, or otherwise override it to a new value of my choosing. Both approaches don't seem to work. That is, it doesn't copy the list in the former case, and the compiler finds an ambiguous implicit value for the latter case. Is there a way to do this?
I realize that I can redefine the implicit value within go(), but this is not a good choice in my case because this class is subclassed numerous times, and I'd like to handle this implicit change in the base class only. So it doesn't necessarily need to go in the constructor, but it must be in a method other than go().
Introduce another wrapper type, simply to disambiguate:
// badly named, choose something domain-specific
case class ListHolder(theList: List[Int])
def someMethod()(implicit holder: ListHolder) {
val xs = holder.theList
// uses xs ...
}
class A()(implicit xs: List[Int]) {
implicit val other = ListHolder(42 :: xs) // compiles
def go() {
// xs is never considered for the implicit param to someMethod()
// because it's now the wrong type
}
}
This also makes the code more self-documenting, as it becomes blindingly obvious that the two implicits are not one and the same.
If you want to have zillions of implicits floating around that don't collide with each other, you can create a wrapper class that you can tag with marker traits for implicit usage. There are a variety of syntaxes you could use; here's one example:
object Example {
class Implication[A,B](val value: A) {
def apply[C](c: C) = new Implication[C,B](c)
}
object Implication {
def mark[B] = new Implication[Unit,B](())
implicit def implication_to_value[A,B](i: Implication[A,B]) = i.value
}
trait One {}
trait Two {}
implicit val x = Implication.mark[One]("Hello")
implicit val y = Implication.mark[Two]("Hi")
def testOne(implicit s: Implication[String,One]) = println(s: String)
def testTwo(implicit s: Implication[String,Two]) = println(s: String)
def testThree(s: String) = println("String is " + s)
def main(args: Array[String]) {
testOne
testTwo
testThree(x)
testThree(y)
}
}
Which works as you would hope:
scala> Example.main(Array())
Hello
Hi
String is Hello
String is Hi
Since you have to use a wrapper object, it's not super-efficient, but it can be very effective. (Or very confusing, given how much happens implicitly.)
This modification compiles. I changed x into a var:
class A()(implicit var x: List[Int]) {
def someMethod()(implicit p: List[Int]) {
// uses p
}
x = List(3)
def go() { // don't want to put implicit inside here since subclasses that override go() have to duplicate that
someMethod()
}
}
I might be approaching this the wrong way, but I'd like to have an object like this:
class MyDataStructure {
def myClone = {
val clone = new MyDataStructure
// do stuff to make clone the same as this
...
clone
}
}
class MyDataStructureExtended(val foo: String) extends MyDataStructure
Then:
val data = MyDataStructureExtended
val dataClone = data.clone
println(dataClone.foo)
So, the problem is that dataClone is of type MyDataStructure, not MyDataStructureExtended as I'd hoped.
I thought about adding a type T to the super class, that the subclass can specify (e.g. itself), but that didn't seem very promising.
As you have suggested, abstract types, or generic parameters, are what you need. Do you require that MyDataStructure not be a trait or abstract class? The following defines MyDataStructure to be an abstract class, but you can make it a trait as well.
abstract class MyDataStructure {
type T
def myClone: T
}
class MyDataStructureExtended(foo: String) extends MyDataStructure {
type T = MyDataStructureExtended
def myClone = new MyDataStructureExtended(foo)
}
The results from the Scala interpreter show that the myClone method defined in MyDataStructureExtended is the correct type.
scala> val mde = new MyDataStructureExtended("foo")
val mde = new MyDataStructureExtended("foo")
mde: MyDataStructureExtended = MyDataStructureExtended#3ff5d699
scala> val cloned = mde.myClone
val cloned = mde.myClone
cloned: MyDataStructureExtended = MyDataStructureExtended#2e1ed620
You might want to restrict T so that its type can only be that of MyDataStructure subclasses
abstract class MyDataStructure {
type T <: MyDataStructure
def myClone: T
}
I don't know your requirements, but I believe that Scala 2.8 will have some nice functionality with case classes and named arguments that allow one to clone case classes with a copy method.
Assuming you want to minimize amount of ceremony in the subclasses, here is my suggestion:
class A extends Cloneable {
protected[this] def myCloneImpl[T] = {
val justLikeMe = this.clone
// copy values and such.
// Note that the Object.clone method already made a shallow copy, but you may want
// to deepen the copy or do other operations.
justLikeMe.asInstanceOf[T]
}
def myClone = myCloneImpl[A]
}
class B extends A {
override def myClone = myCloneImpl[B]
}
By extending java.lang.Cloneable and calling the Object.clone method, you ensure that your runtime type is the same as the object being cloned. The static type is coerced with a type-cast (asInstanceOf[T]). You will need to override the myClone method in each subclass and specify the type, but it should be a one-liner.
Hard to say whether you're doing it right with such a vague problem description, but it's actually pretty straightforward to do this. You can simply override myclone in MyDataStructureExtended such that it returns the more specific type. When you have a variable of the more specific type, you'll be able to use the more specific clone method as well.
Example code in case that description was unclear:
class A {
def getMe = this
}
class B extends A {
override def getMe = this
def isAnInstanceOfB = true
}
And a corresponding REPL session:
scala> val a = new A
a: A = A#1a6eeab
scala> val b = new B
b: B = B#a36771
scala> a.getMe
res0: A = A#1a6eeab
scala> a.getMe.isAnInstanceOfB
<console>:7: error: value isAnInstanceOfB is not a member of A
a.getMe.isAnInstanceOfB
^
scala> b.isAnInstanceOfB
res2: Boolean = true
scala> b.getMe.isAnInstanceOfB
res3: Boolean = true
I think this could be the solution. This is not inherited and you can do some modification to achieve your thing. Good Luck.
class CloneableClass extends scala.Cloneable {
def myMethod: Unit = println("Inside "+this.getClass)
override def clone(): CloneableClass =super.clone().asInstanceOf[this.type]
}
class CloneableDemo {
val cc = new CloneableClass
val cc1 = cc.clone()
cc1.myMethod
}
object CloneObject extends App {
val cd = new CloneableDemo
}