Thursday, October 29, 2009

Scala: accessor/mutator access control

I spent a few minutes this evening digging in to Scala (http://scala-lang.org). What follows is the results of my initial investigation into the world of accessor/mutator methods and how to control access to them at compile time. WARNING: I'm just a scala noob!

Declaring a variable in scala implicitly creates accessor/mutator methods for that data. If I'm understanding things correctly, all variable references (i.e. assigns, accesses) are actually implicit calls to those methods. For example, in the following snippet, the last line is implicitly calling the implicit name() accessor method in the 'Dude' class.


class Dude (firstname: String, lastname: String){
var name: String = firstname + " " + lastname;
}

var joe = new Dude("Joe", "Brown")
print(joe.name)



I like this, in as much as it seems on the surface to eliminate the need for boilerplate getter/setter methods. However, I am a huge fan of access modifiers, mainly because they make code more readable in that they communicate design intent. For example, I rarely code java classes these days with knee-jerk 'setter' methods: I only add setters if I have made a conscious decision to allow other classes to write to the property in question. Additionally, I disdain the knee-jerk use of the 'get/set' convention for accessor/mutator names. So my java code tends to look like this a lot:


class Dude {
private String name;

public Dude(String firstname, String lastname){
this.name = firstname + " " + lastname;
}

public String name(){
return name;
}
}


So, naturally, I would not find implicit accessor/mutator creation to be of much benefit in the "eliminates boilerplate code" departement, unless the syntax enables you to succinctly specify different access modifiers for the implicit accessor vs the implicit mutator for a given variable. In other words, I would like to be able to expose an internal variable as a read-only property using syntax something like:


class Dude (firstname: String, lastname: String){
private(public read) var name: String = firstname + " " + lastname;
}


As it turns out, it appears that this is not possible. You can only specify one access modifier on a variable, and that modifier applies to both the accessor and the mutator. So, making a variable 'private' implies a private accessor method, so the only way to make it read only is to add the boilerplate accessor:


class Dude (firstname: String, lastname: String){
private var name: String = firstname + " " + lastname;

def name() : String = name

}


Unfortunately, the compiler will reject that code, complaining that "Method name is defined twice". This is because the name of my special accessor method clashes with the name of the implicit accessor. Thus, I have to resort to using "special" names for my private variables, like so:


class Dude (firstname: String, lastname: String){
private var myName: String = firstname + " " + lastname;

def name() : String = myName

}


It seems to me that this restriction would tend to push one toward adopting coding conventions for naming private variables in such cases. This would almost surely consist of adding superfluous characters to the variable name. For example, naming all private variables with a leading underscore (yuk!). It just seems needless and confusing.

So, I'm faced with the prospect of both A) still having to code the accessor explicitly (albeit with a more finger-friendly syntax than java) AND B) having to come up with separate names for the 'internal' variable and the 'public' accessor. A is acceptable, but B is really crappy. It seems to me that they could solve B by having the compiler use any explicitly defined acessors instead of the implicit one (thereby avoiding the name conflict). If it made things easier on the compiler, I would be fine with some sort of 'implicit accessor override' syntax, like so:


class Dude (firstname: String, lastname: String){
private var name: String = firstname + " " + lastname;

public def-read name: String = name;
}


However, I prefer my "private(public read)" idea better, as it is more concise.