Friday, October 28, 2011

Type-Safety in Common Degister 3

Commons Digester is a Java library to parse XML data into Java objects. Calling the parse method on a Digester object with an file containing the XML data as argument returns the object on the top of the object tree corresponding to the XML data. The XML data may be arbitrary, so does the the type of the returned object. For this obvious reason, the parse method return type, in Digester 1 and 2, is Object (java.lang.Object). Clients of the library have to cast the returned objects into whatever types they actually are. This approach lacks type-safety. At compile time, no incorrect casting may be caught. A incorrect casting will throw a ClassCastException at runtime.

After generic was introduced into Java in Java 5, many libraries were improved with generic to increase type-safety. There were such efforts in Commons Digester 3, too. In Digester 3, a parse method of the Digester class is a generic method. Each parse method has a type parameter (<T>) and the return type is the abstract type T instead of Object. When the return is assigned to a variable, Java compiler can infer the type for the return. Class casting is no longer needed in the client code. This may give an impression that the risk of runtime ClassCastException is prevented. That is really a false insurance. In this case, what the generic method provides is just what is called auto-casting, that is, instead of the client code, the service code does the casting, with help of generic. All the benefit here is the convenience that the client does not need casting anymore. No risk of casting is prevented or reduced.

It is worth to point out that the Digester class is a non-generic class while the parse methods are generic methods. If an abstract type is at the same time of the type of more than one parameters and return of a generic method, the compiler can check the arguments and the variable to assign return to infer the concrete type and ensure the arguments and the return are assignable to the concrete type inferred. That increases type-safety comparing with using Object as the type for method parameters and return. It is not the case for the parse methods of the Digester class. In the case of the parse methods of the Digester class. The abstract type is only the type of the return. There is no way for the compiler to infer the right concrete type.

Sunday, October 9, 2011

Object Attributes and States, From Modeling to Programming

Regarding things as objects with attributes is a powerful thinking technique,  learned by some of us as early as in elementary school. As an example, in the popular logic game for children, Zoombinis Logical Journey, every zoombini has four attributes. (In the game, the attributes are visually identified without a text name. For our convenience of discussion, we just name them hair, eyes, nose, and feet.)

Zoombini Attributes
An attribute has a value. Legitimate values for a specific attribute may be elements of a finite or infinite set (the domain of the attribute). In the Zoombinis example, each attribute may have one out of five possible values. An object's state is the combination of its attribute values. In the zoombinis example, the particular zoombini in the picture above is in a state that can be described as

A Zoombini State
All possible states of an attribute together form the state space of the attribute. All possible states of all attributes of a object form the state space of the object. All possible states of all objects of a software system form state space of the software system.

An object may be mutable. In that case, its state can be changed. An object may be immutable. In that case, its state cannot be changed.

UML, as the claimed universal modeling language, directly supports the object/attributes thinking techniques. In UML, an object may have many attributes. In UML, we may model zoombinis as objects of a Zoombini class:

Zoombini Class in UML

 Unfortunately, UML does not offer a notation to distinct mutable and immutable attributes.

When we start coding zoombinis in a programming language, we often encounter a problem - most popular programming languages do not have the concept of attributes. For example, in Java, a object may have member fields and member methods, but not attributes. Because attribute is such a powerful concept in our rational thinking, we are unwilling to give it up so easily. What we can do is what Steve McConnell called "programming into a language". Actually, the JavaBean property concept is the same as object attribute. So we can code an object attribute as an object property in Java. For an immutable attribute, just omit the mutator method of the property. However, we can also code an object's mutable attribute as a public field of the object.

Saturday, October 1, 2011

Immutable Objects and val Variables Are Not the Same Thing in Scala

In Scala programs, some objects may be mutable, others immutable. A mutable object's state can be changed. An immutable object's state cannot be changed.

Listing 1 - A Mutable Object

object Example1 extends Application {
    val aList = scala.collection.mutable.Set(1, 2, 3)
    println(aList)
    
    aList.add(4)
    println(aList)
}

In Listing 1, we create a mutable Set object with 3 elements (viz 1, 2, and 3) in it. Then, add a new element, 4, to it. Run the program, it will display:

Set(2, 1, 3)
Set(2, 1, 4, 3)

Obviously, we can change the state of the mutable Set object. If instead, we create an immutable Set object, for example, with the following statement
 
val aList = scala.collection.immutable.Set(1, 2, 3)

We won't be able to add a new element into that Set object. Accordantly, there is not the add method for the immutable Set class. (The + method will create a new Set object rather than add a new element into the original set).

In Scala programs, an variable may be a var or val variable. An variable holds a reference to an object. An var variable can be re-assigned to reference another object. A val variable cannot be re-assigned.


Listing 2 - val Variable Cannot Be Re-Assigned

object Example1 extends Application {
    val aList = scala.collection.mutable.Set(1, 2, 3)
    aList = scala.collection.mutable.Set(1, 2, 3, 4)
}

When we compile the program in Listing 2. Scala compiler will complain: reassigment to val. If we change val to var as in Listing 3, the program will compile fine.

Listing 3 - var Variable Can Be Re-Assigned

object Example1 extends Application {
    var aList = scala.collection.mutable.Set(1, 2, 3)
    aList = scala.collection.mutable.Set(1, 2, 3, 4)
}

Notice that in Listing 1, even aList is a val variable, we can change the state of the object referenced by it since the object is a mutable object.

Even though both immutable and val are about somethings that cannot be changed, one is about the object states, another objects referenced. They are indeed totally different. However, beginner Scala programers may get confused.