8
votes

Trying to define an accessor method for default constructor parameter, i.e.:

class Person (age: Int) {
    def age: Int = this.age
}

Which obviously results in a compiler error: ambiguous reference to overloaded definition, both method age in class Person of type => Int and value age in class Person of type Int match expected type Int

Is there a way in this context to distinguish between the member method name and auto-generated member value name?

Of course it's possible to change the name of either identifier, but is there a way in this scenario of actually specifying which identifier is referred to?

4

4 Answers

16
votes

Just put "val" in front of constructor parameters that you want to expose as instance properties.

6
votes

Use

class Person (val age: Int)

if you just want a getter or

class Person (var age: Int)

if you also want a setter.

3
votes

The answers above are great wrt the uniform access principle. If you have or need Java style getters and setters you can also use the BeanProperty annotation.

class Person(@scala.reflect.BeanProperty var age: Int)

This will result in the following methods being created:

def getAge: Int = age
def setAge(age: Int) = this.age = age

If you instead use the BeanProperty for a val instead of a var, the setter won't be created, only the getter.

One other caveat, the setter method cannot be called from inside Scala. Instead, you should use the standard Scala convention of uniform access to set the value.

1
votes

Just for completeness and to expand on the previous answers, there is also the technique covered here.

To summarize, I would always begin with an immutable value:

class Person (val age: Int)

Then, if you figure out you need to mutate the value (or you know it in advance), switch to:

class Person (var age: Int)

Then, if you need to validate or do some other computation on get or set, rename your variable and build accessors that mimic your original naming, no need to refactor the rest of the code:

class Person(var _age: Int)
{
   def age =
   {
      println("age requested")
      _age
   }
   def age_=(newAge: Int) =
   {
      assert(newAge > 0)
      println(s"age changed from ${_age} to $newAge")
      _age = newAge
   }
}

Of course, you can simplify either setter or getter if you don't need operations there.

Kudos to all other answers, which are indeed correct and came much sooner.