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

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.

Related

Scala: Using reflection to add behavior to setter methods of a variable within a class

I am trying to add behavior to the setters of a variable within a class. To keep things simple let's say that I want to print something to the console whenever a variable is set. Moreover, I want to achieve this using reflection from within a trait that is mixed in the class.
Consider the following code:
class Foo(var bar: String) extends Logger {}
trait Logger { self =>
// create mirrors to reflect on the delegate
private val runtimeMr = runtimeMirror(self.getClass.getClassLoader)
private val instanceMr = runtimeMr.reflect(self)
}
How can I now:
1) get the setter method(s) from the instanceMr and, more importantly
2) add behavior to the execution of the setter (in my case printing bar before setting it)

Scala Class that containing List

I have a very basic and simple Scala question. For example, I have a java class like that
class Dataset{
private List<Record> records;
Dataset(){
records = new ArrayList<Record>()
}
public void addItem(Record r){
records.add(r)
}
}
When I try to write same class in Scala, I encoutered with some error:
class RecordSet() {
private var dataset:List[Record]
def this(){
dataset = new List[Record]
}
def addRecord(rd: Record)={
dataset :+ rd
}
}
I cannot declare a List variable like ( private var dataset:List[Record])
and cannot write a default constructor.
Here is how you will replicate the Java code you mentioned in your question:
// defining Record so the code below compiles
case class Record()
// Here is the Scala implementation
class RecordSet(private var dataset:List[Record]) {
def addRecord(rd: Record)={
dataset :+ rd
}
}
Some explanation:
In Scala, when you define a class, you have the ability to pass parameter to the class definition. eg: class Foo(num:Int, descr:String) Scala would automatically use the given parameter to create a primary constructor for you. So you can now instantiate the Foo, like so new Foo(1, "One"). This is different in Java where you have to explicitly define parameter accepting constructors.
You have to be aware that the parameter passed do not automatically become instance member of the class. Although if you want, you can tell Scala to make them instance member. There are various ways to do this, one way is to prefix the parameter with either var or val. For example class Foo(val num:Int, val descr:String) or class Foo(var num:Int, var descr:String). The difference is that with val, the instance variable are immutable. With var they are mutable.
Also, by default the instance member Scala will generate would be public. That means they can be accessed directly from an instance of the object. For example:
val foo = new Foo(1, "One")
println(foo.num) // prints 1.
If you want them to be private, you add private keyword to the definition. So that would become:
class Foo(private var num:Int, private var desc:String)
The reason why your code fails to compile is you define a method called this() which is used to create multiple constructors. (and not to create a constructor that initiates a private field which is your intention judging from the Java code you shared). You can google for multiple constructors or auxiliary constructors to learn more about this.
As dade told the issue in your code is that with this keyword you are actually creating an auxilary constructor which has some limitations like the first line of your auxilary constructor must be another constructor (auxilary/primary). Hence you cannot use such a way to create a class.
Also you can not write such lines in a scala concrete class private var dataset:List[Record] as it is considered as abstract (no definition provided).
Now with the code. Usually in Scala we don't prefer mutability because it introduces side-effects in our functions (which is not the functional way but as scala is not purely functional you can use mutability too).
In Scala way, the code should be something like this:
class RecordSet(private val dataset:List[Record]) {
def addRecord(rd: Record): RecordSet ={
new RecordSet(dataset :+ rd)
}
}
Now with the above class there is no mutability. Whenever you are adding on an element to the dataset a new instance of RecordSet is being created. Hence no mutability.
However, if you have to use the same class reference in your application use your a mutable collection for your dataset like below:
class RecordSet(private val dataset:ListBuffer[Record]) {
def addRecord(rd: Record): ListBuffer[Record] ={
dataset += rd
}
}
Above code will append the new record in the existing dataset with the same class reference.

Why can't I have a private var / val with the same name as a getter / setter? or how to desugar implicit getters / setters

I'm sure it's a duplicate, but I couldn't find it.
Consider this class
class Test1(var param: Int)
Scala generates a getter and a setter, and makes the param private.
It can be shown using javap for example:
public class Test1 {
private int param;
public int param();
public void param_$eq(int);
public Test(int);
}
I was trying to write the desugared version of it with explicit getters / setters but couldn't do so 100% the same way as the private var had a naming collision with the getter.
class Test2(private[this] var param:Int) {
def param:Int = this.param
def param_= (param:Int) {this.param = param}
}
This is the error:
ambiguous reference to overloaded definition,
both method param in class Test2 of type => Int
and variable param in class Test2 of type Int
match expected type Int
def param:Int = param
^
This of course works (renaming private member to _param)
class Test3(private[this] var _param:Int) {
def param:Int = this._param
def param_= (param:Int) {this._param = param}
}
But generates this slightly different bytecode of course (since we had to rename param to _param):
public class Test3 {
private int _param;
public int param();
public void param_$eq(int);
public Test3(int);
}
Is there any way to reach the same bytecode as the example in Test1 while using explicit getter / setters as in Test2?
In Scala methods and fields share the same name space. This is a little confusing for converts coming from Java or other languages which have separate name space for each.
But it follows the Uniform Access Principle i.e. the user of a class can't tell if he is actually calling a def or a val (or a var) when used without parenthesis. This also means you can switch implementations between val an def without clients being affected. (I'm not sure if they'd have to get recompiled, but the source code can stay as it is.
Actually, you can!
Here is an answer that does exactly that to good effect.
There you will find a private var and an accessor with the same name.
private[this] var state
private final def state()
Note the parens on the definition of the accessor, which are not needed at the use site.
Under the covers, the local field has that LOCAL_SUFFIX_STRING, which is an evil space. See the Test3 members, below, which strips away the covers to bare all.
On the getter side, you can add parens. That breaks the saccharin setter, apparently. Can you live without sugary assignment syntax?
When you reference x.param, the compiler will supply parens, see #alexiv 's comment elsewhere on uniform access or the SO answer mentioned above.
import reflect.runtime.currentMirror
import reflect.runtime.universe._
class Test2(private[this] var param: Int) {
def param(): Int = param
def param_=(param: Int) { this.param = param }
}
val x = new Test2(1)
Console println x.param
x.param_=(2)
Console println x.param
class Test3(var param: Int)
val ps = typeOf[Test3].members filter (m => m.name.toString.startsWith("param")) map (m => s"'${m.name.toString}'")
Console println ps
Console println (typeOf[Test3].members filter (_.name.toString.endsWith(nme.LOCAL_SUFFIX_STRING)))
Note that the other answers suggest that Scala only distinguishes terms and types, neglecting to mention that symbols (obviously) can be overloaded.
You may have read that overloading is evil! That may be so, but whatever you do in the privacy of your own private members is entirely your own affair.
(Updated to suggest that even if the question is somewhat duplicated somewhere, this is still a fun and informative answer.)
I think variable and method are treated the same, the variable param is like a method without parameters, and the method param is the same, so just like the error indicates: ambiguous reference to overloaded definition.

Scala limitation on constructor-defined attributes

In Scala, it's possible to define class attributes in the constructor. But once you declare them there, it's not possible anymore to change the behavior (getters and setters), like you can when declaring in the class body?
Example:
class MyExample(var attribute : String)
{
def attribute() //trying to override getter <- doesn't work
}
class MyExample(theAttribute : String)
{
def attribute = theAttribute //overriding default accessor (was var)
}
If it's not possible, why is it so? It seems confusing when you show people that they can easily create attributes by setting var or val in constructor, and not care about getters and setters (they can change if they need), to ultimately find that, in fact, you should avoid using those kind of facilitations.
Let's for a moment imagine that it was possible to override the generated accessor-method:
class MyExample(var attribute : String)
{
def attribute() = attribute + "abc" // won't compile!
}
Without a further qualification it is impossible to tell whether the name attribute within method body refers to the class field or recursively to the method itself.
By design in Scala methods and fields belong to the same namespace, this, known as Uniform Access Principle, gives the ability to change an internal implementation without breaking the external interface.
An initial implementation could be:
class MyExample(val attribute : String)
Then changed onto:
class MyExample (attr :String) {
def attribute = attr toUpperCase
}
And then
class MyExample(var attribute : String)
Or
class MyExample(attr : String) {
def attribute = attr toUpperCase
def attribute_= (a : String) { attr = a + "abc" }
}
All without breaking any of the dependent code.
When field is defined as part of a constructor the automatically generated accessor-methods are syntactic sugar. The sugar eases quick prototyping and helps to keep the code concise. Nonetheless, whenever you want to add more substance you must use the full syntax.

How to define accessor method for default constructor parameter?

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.