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.

2 comments:

  1. I think maybe what I'm realizing here is that scala doesn't really have 'properties' support. It's a shame, because it is oh-so-close. From the scala language reference, Example 4.2.1 (emphasis mine):

    "The following example shows how properties can be simulated in
    Scala. It defines a class TimeOfDayVar of time values with updatable integer fields representing hours, minutes, and seconds. Its implementation contains tests that allow only legal values to be assigned to these fields. The user code, on the other hand, accesses these fields just like normal variables.
    "

    It goes on to show a code example where there are private variables named h, m, and s, with public accessor methods named "hours", "minutes" and "seconds". In other words, they are acknowledging that there is no way to do properties without running in to the naming conflict issue.

    ReplyDelete
  2. Some relevant links:
    http://www.scala-lang.org/node/29
    http://www.scala-lang.org/node/3896

    ReplyDelete