Sunday, January 4, 2009

Type Contraints and Type Coercions in Joose

There is a new feature in the upcoming Joose 2.0 that is called type constraints that has great potential of changing the nature of many JavaScript applications:

Joose type constraints are only somewhat related to types in the traditional sense of computer science. They allow the programmer to define a set of contraints which a value that is stored in a variable will have to fulfil. As they apply to values rather than containers these checks are performed at runtime rather than compile time.

In this class definition the attribute "anAttribute" is constrained to the type Joose.Type.MySmallNumber:
Class('MyClass', {
has: {
anAttribute: {
is: 'rw', // TypeConstraints only work for rw attributes
isa: Joose.Type.MySmallNumber, // use the MySmallNumber constraint
coerce: true // turn on coercions for this attribute
}
}
})
The definition of the type itself looks like this:
Type('MySmallNumber', {
uses: Joose.Type.Int, // this is a specilization of the Joose.Type.Int Class
where: function (value) {
if ( value > 1 && value < 5 ) { // we only accept Ints between 1 and 5
return true;
}
return false;
}
});
This type specializes the built-in type Joose.Type.Int which only accepts integers. Only values greater than 1 and smaller than 5 are accepted. If you assign values to instance variables which do not match this constraint, the program will throw an exception (As an alternative you may also add an onError callback as a second parameter to a setter-Method to handle the exception).

Type Coercions
The real magic starts when we add in so called type coercions. Type coercions are rules how values can be tranformed from one type to another (kind of like casting). Here is an example of the above type with one coercion rule:
Type('MySmallNumber', {
uses: Joose.Type.Int, // this is a specilization of the Joose.Type.Int Class
where: function (value) {
if ( value > 1 && value < 5 ) { // we only accept Ints between 1 and 5
return true;
}
return false;
},
coerce: [{ //optional coercion definition list
from: Joose.Type.Str, //coercion from string to number
via: function(str) {
return new Number(Str); //perform our coercion
}
}]

});
This coercion transforms values that have the built-in type Joose.Type.Str to integers.

Joose provides a set of built-in types for your convenience. These are organized in a hierarchy. Things that are further down the hierarchy need to match all the contraints of parent-types.

Joose type constraint hierarchy
This diagram has been created with the Joose sample app blok.


Conclusion
Type coercions have been proven to be extremely useful in JavaScript code because many tasks in JavaScript deal with user provided data that is in string form. Coercions provide a very convenient way to transform this string data into meaningful things. After the definition of the types your application code can basically "ignore" things like data validation and conversion. This makes the code more expressive and should reduce errors because it is harder to forget to validate data.

Further topics
Defining inline types
Localization
Type constraint API

This post serves as a draft for the future documentation for Joose's type contraint system and will then move to the Joose wiki page on type constraints.
If you want to play with the features, you will have to download the Joose 2.0 release candidate.
Post a Comment