2

I'd like to define a val in a trait that gets computed once by sub-class that gets instantiated.

For instance :

trait Example
{
    val p : Int
    val after : Int = p + 1
}

class Ex(x : Int) extends Example
{
    val p = x
}

I want after to be computed for each instance of Ex, but no matter which parameter x I give, after is always 1. As if, p was 0 for the computation.

Of course, it works with def, but then it is no longer computed only once.

2 Answers 2

3

after in Example is instantiated right away, before your Ex actually is instantiated - and then before even looking at your x.

To fix it you can turn after into a lazy val, it will be evaluated the first time you use it.

Sign up to request clarification or add additional context in comments.

1 Comment

The non-lazy syntax in the other answer is more obvious.
2

First of all a val variable is immutable, so it can only be assigned once. So it would not be possible to do p = x. But when you do val p = x in the Ex class you are assigning other variable that you just defined, so after would not change.

You have to define the abstract variable var p in your Ex class, so it will be able to set the val p defined in Example. For example, define the var p in the constructor as below.

trait Example
{
    val p : Int
    val after : Int = p + 1
}

class Ex(val p : Int) extends Example

Demo

scala> val ex = new Ex(5)
ex: Ex = Ex@1f7ebc89

scala> ex.p
res4: Int = 5

scala> ex.after
res5: Int = 6

1 Comment

I don't understand the first part about "when you do val p = x". Member Ex.p is overriding p in both the OP and your example. The difference is that the field is initialized early (before super ctors) for the class param.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.