This is a blog about Joose and my other mostly JavaScript-related projects. The official Joose homepage is located at Google Code.
Showing newest posts with label Type Coercions. Show older posts
Showing newest posts with label Type Coercions. Show older posts

Sunday, January 18, 2009

Typed Method Signatures in Joose/JavaScript (parseInt never again)

Typed method signatures have landed in Joose. This is what you get from the new feature:
  • You can define type constraints, classes and roles that a method parameter must match
  • If the type checks fail there is a runtime exception
  • If you enable coercions, Joose tries it's best to convert the parameter types to the one you want!
That is why I call type coercions the death of parseInt (and friends). JavaScript client side programming deals with a lot of user provided string data that needs to be validated and converted to domain values. With type coercions, once you have defined your types (or the use the built-in types), input validation and conversion is completely transparent to your code.

Lets consider this example: If you want to write code that adds the number 3 to the value of this input field: (Just an input-field with a 2 inside (for the feed readers))

To make this reliable, you need to
  • check whether the value of the input field is actually something that can be added to (in a numerical sense)
  • convert the value from a string to a number
This is where Joose type coercions can help you. Here is the code doing all that using type coercions:
    // Make a class thats adds to its instance variable "amount"
Class("Adder", {
has: {
amount: { is: "rw" }
},
methods: {
// add is a method with a signature
add: {
signature: [Joose.Type.Int], // the first parameter must be an integer
method: function add (num) {
return num + this.amount // add the argument num to our instance var amount
},
coerce: true // enable coercions for arguments
}
}
})

// Make an adder that always adds 3
var addTo3 = new Adder({ amount: 3 })

// add 3 to the value of the input field
alert(addTo3.add(form.addMe.value));
If you would run the above code without type constraints and coercions the result of the method would actually be "23". The code above, however, does the right thing and alerts 5.
This is obviously a lot of code for such a trivial use case, but once things start to become more complicated you save a lot of typing, produce code that might have less bugs and document your parameters a little more thoroughly. The extra benefit of the Joose built in types is that we already wrote unit tests for them (allthough there is always room for more) so you don't have to.
I'm aware that a lot of JavaScript purist will find this totally over the top, but as we go into writing ever more complex JS applications things like this have their place. I, personally, find it great that I get extra security while being lazy at the same time.

Thanks again for the great input from the discussion on the best builder syntax. The current syntax is not final, however. I chose it, because
  • it fits well into Joose
  • the types are close to the actual signatures
It is not ideal, because
  • unless, you repeat (which is bad) the method name in the function declaration, your methods will be called "method" in firebug and similar tools.
  • is is pretty verbose
New ideas that would eliminate these short comings are very welcome.
You might have noticed, that coercions needs to be enabled by opt-in. This is due to the fact, that coercions come with a pretty heavy performance penalty. It is absolutely no problem in a use case where you have a "front-end" function to parse user input (DOM access is magnitudes slower) but might be too big for your canvas ray tracer.

Sunday, January 4, 2009

Type constraints for method parameters (and return values)

As an add on to type constraints for instance variables (see last post) we think about adding them to method parameters and maybe even method return values. The hard part here is not the implementation but rather to find a nice syntax to declare these constraints. Here are a couple examples of possible definitions for typed method signatures:
    Class("TypedMethodParas", {
methods: {
typed1: [
[Joose.Type.Int, Joose.Type.Date],
function (int, date) {
// ...
}
],

typed2: {
takes: [Joose.Type.Int, Joose.Type.Date],
does: function (int, date) {
// ...
},
returns: Joose.Type.Int
},

typed3: Method(Joose.Type.Int, Joose.Type.Date, function (int, date) {
//
},
Joose.Type.Int)
}
})

Which one do you like best? Do you have better ideas? Is this feature even worthwhile?

Go to Comments

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.

Saturday, October 4, 2008

Type Constraints and Type Coercions

Jeremy and me continue to work on the type contraint and type coercion system for Joose.
Just a quick heads up to what this actually means using an example from the test suite (please be aware that the naming of types will likely change until the next release)
Class("CoercionTest", {
has: {
numAttr: {
isa: TYPE.Num,
coerce: true,
is: "rw"
},
strAttr: {
isa: TYPE.Str,
coerce: true,
is: "rw"
}
}
})
The class above has two attributes numAttr and strAttr. These are constraint to be of TYPE.Num and TYPE.Str. That means that it will not be possible to set these attributes to anything that does not match those types. However, the coerce: true property activates coercion which in turn activates magic that can convert a value from one type to another.

Some examples from the case above
  • coerce.setNumAttr("2") will assign the number 2 to the attribute numAttr (not the string "2")
  • coerce.setStrAttr(2) will assign the string "2" to the attribute strAttr
  • coerce.setStrAttr(["a", "b"]) will assign the string ["a", "b"].toString() to the attribute strAttr.
Type constraints will help to make your code
  • more correct (because values are contrained to the correct type)
  • more correct (because we already tested the type checks in Joose's test suite)
  • more declarative
  • shorter (because of centralized coercions)
  • more correct (because we already tests the type coercions in Joose's test suite)
The next steps are to provide a standard type system for Joose with all general coercions in place. This will make working with JavaScript in the browser a lot more fun, because
  • you get a validation framework for free
  • all data coming from the user (like input fields, etc.) is text based and coercions turn these into meaningful data automatically.
The type system is actually in place already, but most of the coercions are still missing. Since most coercions turn strings into structured data, many coercions must actually be localized (think "13,000.45" va. "13.000,45"). Thus, we will also provide hooks to activate coercions based on the current locale. Joose will ship with coercions for english speaking countries and I'll write extentions for Germany.

We'll keep you posted with updates about the type system.

Friday, September 26, 2008

Type Constraints in Joose

Jeremy Wall of Google provided a great patch to Joose to actually hook up the long standing implementation of type constraints and coercions into the default attribute meta class.

So what does this actually mean:

First: You can build Types which are basically just things that express certain contraints for a value containers like an instance variable.
This is a type that will only allow boolean values:
Type('BooleanTest', {
where: function(value) {
if (typeof value == 'boolean') {
return true;
}
return false;
}
})
Now where this gets useful is if you add what is called coercions, which are just little functions that look at data and tranform them in a way that they match a type. Here is the type declaration with a coercion added, that turns 0 into false and other integers into true:
Type('BooleanTest', {
where: function(value) {
if (typeof value == 'boolean') {
return true;
}
return false;
},
coerce: [{
from: TYPE.Integer,
via: function (value) {
if ( value == 0 )
return false;
return true;
}
}]
}
);
Now we can build a class that constraints it's instance variables to be of type BooleanTest like this:
Class("BooleanTypeConstrained", {
has: {
attr1: {
is: 'rw',
isa: TYPE.BooleanTest,
coerce: true
}
}
})
We have to add the extra coerce: true, in order to enable the coercion because it does have a certain impact on runtime performance. What we can do now is this:
var constrained = new BooleanTypeConstrained();
constrained.setAttr1(1)
Without the coercion this would fail, because the field attr1 is contrained to be a boolean. However, because we added a coercion that transforms integers into booleana, this still works (and it actually sets the value of the instance variable to true).

I think that this can be a big thing for JavaScript programing, because when we do client side programming, dealing with user input is very important. With type coercions this becomes very declarative and easy. For example, you can have the user input a date in many different formats and then have coercions that transform these strings into instances of Date.

Friday, April 25, 2008

Type System and Type coercions

Joose's next big feature will be types and and type coercions. These allow type checked attributes and more importantly automatic conversion between string data and Objects (via coercion).

This might prove to be a really useful feature for JavaScript programming because it makes converting user input into useful objects really easy.