When to useval or def in Scala traits?

后端 未结 3 743
你的背包
你的背包 2020-11-27 13:03

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

3条回答
  •  無奈伤痛
    2020-11-27 13:34

    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.

提交回复
热议问题