Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bug or Feature: Kotlin allows to change 'val' to 'var' in inheritance

I just started to explore the language Kotlin. I'm struggling with inheritance, var&val and side-effects.

If I declare a trait A with a val x and override x in AImpl it is possible to override it as var (see code below). Surprisingly the print() method in A is affected by the reassignment of x even though x is a value in A. Is this a bug or a feature?

Code:

trait A {
  fun print() {
    println("A.x = $x")
  }

  val x : Int;
}

class AImpl(x : Int) : A {
  override var x = x; // seems like x can be overriden as `var`
}

fun main(args: Array<String>) {

  val a = AImpl(2)

  a.print() // A.x = 2

  a.x = 3; // x can be changed

  // even though print() is defined in trait A
  // where x is val it prints x = 3
  a.print() // A.x = 3

}

I'm aware of the fact that if I define a with type A explicitly it is not allowed to change x:

val a = AImpl(2) : A
a.x = 3 // ERROR: value x cannot be reassigned

But as the first case shows, inheritance can cause side effects which are clearly not intended in A. How do I protect values from being changed by inheritance?

like image 565
miho Avatar asked Apr 02 '14 18:04

miho


People also ask

Can Val be changed in Kotlin?

VAL(Value) The object stored using val cannot be changed, it cannot be reassigned, it is just like the final keyword in java. val is immutable.

How do you override a method in Kotlin?

To override a method of the base class in the derived class, we use the override keyword followed by the fun keyword and the method name to be overridden.

Why do we use override in Kotlin?

In any object-oriented programming language, Overriding is a feature that allows a subclass or child class to provide a specific implementation of a method that is already provided by one of its super-classes or parent classes.


1 Answers

You can make your val final, i.e. forbid overriding it at all. If you define a val in a class, it is final by default.

Also, if you need to override a val with a var, but do not want the setter to be public, you can say so:

override var x = 1
    private set

Overriding a val with a var is a feature. It is equivalent to adding a set-method while in the superclass there was only a get-method. And this is rather important in implementing some patterns, such as read-only interfaces.

There's no way to "protect" your val from being overridden in a way that allows changing mutation other than making it final, because val does not mean "immutable reference", but merely "read-only property". In other words, when your trait A declares a val, it means that through a reference of type A the client can not write this val, no other guarantees intended, or indeed possible.

P.S. Semicolons are optional in Kotlin, feel free to omit them altogether

like image 63
Andrey Breslav Avatar answered Nov 15 '22 11:11

Andrey Breslav