July 18, 2007

Obscurantism

I may have mentioned before that I have started to use the C# language. Overall it isn't bad - it uses static typing, which I have always found irksome, but the language is reasinably expressive and compact compared with something like Java or C++. Because it is heavily promoted by Microsoft there are any number of tutorial and example web sites, not all of them by programming experts.

Somehow the Java message that it's bad to allow direct access to instance and class attributes appears to have permeated the C# world, I have no idea why. I have just been reading one of the better-written tutorials, which offers the following code as an example if instance creation and manipulation.
static void Main(string[] args)
{
Person Michael = new Person();
Person Mary = new Person();
// Specify some values for the instance variables
Michael.Age = 20;
Michael.HairColor = "Brown";
Mary.Age = 25;
Mary.HairColor = "Black";
// print the console's screen some of the variable's values
Console.WriteLine("Michael's age = {0}, and Mary's age = {1}",
Michael.Age, Mary.Age);
Console.ReadLine();
}
As code goes that isn't bad, and apart from the different comment styles and the declarations it could almost be Python. Unfortnately the author has tasted the Java Kool-Aid, and shortly after this example writes
So each object now contains different data. Note that we directly accessed the variables and we put any values we wanted, right? But wait there is a solution to this problem. We will use properties.

There is no attempt to explain what the "problem" is, and you will probably not be surprised to learn that the "solution" involves making the attributes private to the class and then providing public getter and setter methods for instance users. This turns a five-line class declaration into a 32-line one (though to be fair to the author, he does at least include checking code that demonstrates the value of properties in applying class-based logic during assignment).

I have now read any number of texts where instead of something like
class Person
{
public int Age;
public string HairColor;
}
that allows direct access to the instance variables by client code, readers are encouraged to write horrendous code like
class Person
{
private int age;
private string hairColor;
public int Age
{
get
{
return age;
}
set
{
age = value;
}
}
public string HairColor
{
get
{
return hairColor;
}
set
{
hairColor = value;
}
}
}
which actually offers no benefit over the short version at all. Python users are used to accessing attributes directly in their code, which clearly has performance benefits, and then implementing properties if and when they are required to add logic to the setting or retrieval of attribute values. I just wish that C# users could see that empty getters and setters offer no measurable benefit over direct access to attributes.

10 comments:

Bill Mill said...

Ah, the beauty of C#. What you haven't yet discovered is that the accessors do have an important reason for existance. The reason?

At the assembly level, "employee.Name" the property is not the same as "employee.Name" the public attribute.

If you link and build against an assembly A, then version 2 of that assembly changes a public string into a property, you will have to recompile your code to work with the new assembly, even though your source doesn't change at all.

Isn't that a lovely decision?

Anonymous said...

you could always declare instance variables as public to get direct access (though every C# programmer would scream at you).

Michael Watkins said...

What I hate more than getters and setters are camelCaseVariables and camelCaseFunctions.

I do agree that *empty* getters and setters are pointless, but what if they were (mostly) not empty? In that case, standardizing on their use would be a good thing, in order to establish consistency within an API / toolkit. Would you agree with that?

Anonymous said...

Ironically, C#'s Property syntax was originally supoused to address this problem. Because the getters and setters, in short, the accesors, use direct access syntax, the clients of that class could use its properties regardless of how they are implemented, an explicit accessor would only be written if needed.

But this being Microsoft, many frameworks including ASP and the applications created using Visual Studio, do not treat properties and public fields the same, leaving us writing empty accessors.

So this is not a flaw of C# but of the Visual Studio IDE and the C# developer culture surrounding it. In the end the blame is to Microsoft, as usual.

Now if you want to see a language that Really Does Not Get It(tm), look at Ruby, where access to instance attributes is impossible by design.

Since it is even more restricted than C#, the need for a quick way of writting accessors was strong, and since Ruby's designer isn't stupid he provided a way to write (one or more) accessor(s) in a single line. It is still a kludge.

The flaw in Ruby actually runs deeper than that. Ruby does not allows access to instance variables because it doesn't has syntax for accessing the inner namespace of an object, period.

The '.' operator in Ruby, what we call the getattr operator is actually the "send message" operator, it only works on methods and it always __call__ them (in python parlance).

Ruby has an operator to get an object from inside another object, it is the '::' operator, but it only works on classes.

Unlike Python, in Ruby classes are classes, methods are methods and variables are variables, in Python, everything is an object.

But Everybody(tm) knows Ruby is more object oriented than Python, of course.

But I wish C# had a shortcut to write properties like in Ruby does.

Stanley Seibert said...

Is it possible to convert a direct-access attribute over to a getter/setter implementation in C# without having to recompile/link code which uses the class?

I was sold on direct access in Python once I saw that I could switch to a property that caused a function to be called when the attribute was accessed. Then there was no penalty for using direct access now, since a getter/setter could always be implemented later.

Stanley Seibert said...

Oop, looks like previous commenter answered my question. Too bad that switching between properties and public attributes in C# requires relinking...

Steve said...

I have in fact created a class whose attributes are public, precisely because it seems the most straightforward way to allow attribute access. And I don't care who screams at me for it.

The idea that changing a plain attribute to a property requires recompilation of the client code despite there being no change in its source strikes me as, well, shall we say bizarre. But it does, I suppose, explain part of the urge to use getters and setters, and I can appreciate the underlying implementation reasons for it (without praising the decisions that led to it).

I don't actually think C# is by any means the most horrible language I have come across, and they all have warts. It's giving me a new appreciation for some of Python's good design decisions.

Kent said...

In Java, changing from direct attribute access to getter/setter access requires changing client code from foo.bar to foo.bar(). IIRC this is the reason recommended Java practice is to always use getters and setters - there is no easy upgrade path.

Scott Meyer's classic (1992) book "Effective C++" strongly recommends using functions to access data members because it allows you to change the implementation without changing the interface. This is essentially the same argument used for Java, so it has been around for a long time.

Steve said...

Thanks, Kent. It seems strange that programmers would prefer to go to the trouble of using redundant getters and setters rather than being prepared to refactor their clients when a change from attribute to property takes place. The argument also has less force in C# where the syntax, as in Python, remains the same (though see Bill Mill's remarks about the need to recompile the clients after such a change).

Anonymous said...

I think you have hit the nail about the enterprisey programmers and... whatever you call us.

Remember, enterprisey desing is ruled by the CYA principle.