How to define accessor method for default constructor parameter? - scala

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?

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

Use
class Person (val age: Int)
if you just want a getter or
class Person (var age: Int)
if you also want a setter.

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.

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.

Related

Difference Scala Class Declaration

I want to ask what's the difference between these two Class Declarations below.
class Person(name: String, age: Int)
or
class Person() {
var name: String = ""
var age: Int = 0
}
class Person(name: String, age: Int)
name and age are constructor parameters. As such they are:
required - in order to create a Person instance
immutable - the values cannot be changed
private - (by default) and cannot be accessed via a class instance
class Person() {
var name: String = ""
var age: Int = 0
}
name and age are class data members. They are:
not specified during construction - but are given the same default values for every Person instance
mutable - because they are var variables
public - (by default) and can be accessed and modified via a class instance
So, what's the difference? Almost everything.
The first declaration uses name and age as constructor arguments, but they do not become members of the class, that is you can't write person.name.
For a beginner, the second line can be considered a more complicated way to write class Person(var name: String = " ", var age: Int = 0). It actually doesn't translate to exactly the same thing: your version creates a class that has a single constructor argument and two public variables, while mine has a constructor with 2 arguments that have default values. Unless you have a good reason to declare it your way, it's usually better to write:
val person = new Person("Andrew", 11)
than
val person = new Person()
person.name = "Andrew"
person.age = 11
which is what your second version would force you to do.
Note that in Scala, you will mostly be using values (constants) and not variables, so you'd actually typically use class Person(val name: String = " ", val age: Int = 0). For simple data types like this, people typically use a case class:
case class Person(name: String, age: Int)
In this case, both argument are considered public and immutable. The only way to modify a person's name is to create another instance of Person with the new name:
val andrew = Person("Andrew", 11)
val will = andrew.copy(name="Will") # Will is also 11
Case classes will automatically give you proper equals and hashCode implementation, as well as the copy method I used above. You can easily find more infos about them on the internet.

What's the difference between handling fields throught "accessor" and "copy"

I don't understand the difference between handling a field through accessor and copy method in Kotlin. It is like this:
Accessor example :
class Person(val name: String,
var age: Int)
fun happyBirthday(person: Person) {
person.age++
}
Copy method example :
data class Person(val name: String,
var age: Int)
fun happyBirthday(person: Person) {
person.copy(age = person.age + 1)
}
person.age++
modifies your existing person instance by incrementing its age by 1.
person.copy(age = person.age + 1)
on the other hand returns a new instance of Person that has the same properties as person does, except for the age that you've specified. As your sample code is right now, you're not assigning this new Person instance to anything, you're just throwing it away.
This copy method is useful when your class is immutable (all of its properties are vals) - instead of modifying it, it gives you an easy way to create a new instance that has mostly the same properties as the original.

Transform value on update in Scala case class (e.g. override setter)

Assuming that I have a Scala case class like the following:
case class Item(
roundedValue: Double = 0.00)
I want to perform the following rounding operation on roundedValue every time the variable is updated:
roundedValue = math.round(roundedValue*100)*0.01
In other languages I would just override the setter for roundedValue, but it appears that I cannot override the setter for a case class variable or it won't compile.
One solution I have seen is to rename roundedValue to _roundedValue and make it private, and then add public methods to simulate getter and setter (with rounding logic): Overriding setter on var
However this makes constructor usage pretty awkward for the case class when using named parameters. Is there any other way to do this, or is this a limitation of case classes in Scala?
If you can make it work, I would recommend keeping your case class immutable, but making a "copy" method that does your mutations on a new instance.
case class Item(roundedValue: Double = 0.0) {
def withValue(newValue: Double) = Item(math.round(newValue*100)*0.01)
}
You may also/instead want to have a similar method in the companion object:
object Item {
def withValue(value: Double) = Item(math.round(roundedValue*100)*0.01)
}

How do I use POJO equivalents in Scala?

Suppose I have the following
class SimpleClass (myInt: Int, myString: String) {
}
What is wrong with the following?
val mySimple = new SimpleClass(1, "hi")
println(mySimple.myInt)
If you want the contructor parameters to be available as fields of the class, you have to declare them as vals or vars:
class SimpleClass (val myInt: Int, val myString: String) {
}
The java equivalent of your Scala definition is:
public class SimpleClass {
public SimpleClass( int myInt, String myString ) {
}
}
No wonders it doesn't work...
Hey dude, that's your 17th scala question and you are still troubled by the very basics of the language. Perhaps you should take an afternoon and read some of tutorial on-line (or some book) to consolidate your knowledge. I can suggest:
http://www.codecommit.com/blog/scala/roundup-scala-for-java-refugees
http://www.ibm.com/developerworks/java/library/j-scala02198/index.html (see listings 11-13)
For the full POJO experience™, including equality, hashCodes and sane implementation of toString... You'll want case classes:
case class SimpleClass(myInt: Int, myString: String)
val mySimple = SimpleClass(1, "hi")
println(mySimple.myInt)
Parameters to a case class are automatically made into vals. You can explicitly make them vars if you wish, but this this sort of thing is typically frowned upon in Scala - where immutable objects are favoured.
The problem is that you are calling the SimpleClass.myInt getter method but you didn't define a getter method anywhere. You need to define the SimpleClass.myInt getter method or even better yet, get Scala to automatically define it for you:
class SimpleClass(val myInt: Int, myString: String) {}

How to expose a constructor variable(sic!) as read-only?

I have this rather simple question about Scala. Given that i have to following class definition:
class Foo(var bar: Int)
The code which is able to construct an instance of Foo must be able to pass the initial value for bar. But if I define bar as var the User is also able to change its value at runtime which is not what I want. The User should only be able to read bar. bar itself is modified internally so a val is not an option.
Read-only for a property is easy, just create a getter method without the corresponding setter. It's also easy to make a private modifiable field.
Your biggest challenge here is the shared namespace, you want to be able to use the same name for:
the constructor param
the internal modifiable field
the public getter
the private setter
Sadly, this is not possible, and you need a distinct name for each role... something like this:
class Bippy(bop0: Int) {
private[this] var privatebop = bop0
//privatebop is ONLY EVER used by the following getter and setter:
private def bop_=(x:Int) = privatebop = x
def bar = privatebop
}
If you're not concerned about using named arguments, or with the name of the argument in Scaladoc, then this can be shortened even further:
class Bippy(private[this] var privatebop) {
//privatebop is ONLY EVER used by the following getter and setter:
private def bop_=(x:Int) = privatebop = x
def bop = privatebop
}
UPDATE
The cleanest method, arguably, which gives you back named parameters is to combine a factory with one of the above techniques:
object Bippy{
def apply(bop: Int) = new Bippy(bop)
}
Which can then be called as Bippy(42). Just the same as the regular constructor, but without the new keyword.