My JavaScript book is out! Don't miss the opportunity to upgrade your beginner or average dev skills.

Saturday, May 26, 2007

JavaStrict Act III - Documentation and official 1.0 Release

My JavaScript Strict Type AS 2.0 like proposal now has a dedicated documentation page with some example code for each function or public static method too.

The big limit in this "IE yet loosing users but persists" era is that native DOM nodes aren't usable as return value or arguments on cross-browser libraries, "just" for FireFox, Safari or Opera, where each node has its specified constructor and where Window is a valid constructor too.

I'm yet waiting for your feedbacks, expecially from some Dojo Toolkit developer ... shouldn't Strict function be useful to write better code removing a lot of comments from your unpacked sources? I hope so :-)


Update 2007-05-27
Alex Russell asked me a better example to understand why JavaStrict should be a good Dojo implementation.

This is just a quick and simple example on how src/json.js file should be:

dojo.json = {

jsonRegistry: new dojo.AdapterRegistry(),

register:Strict(Void, function(name, check, wrap, override){
// ... code ...
}, [String, Function, Function, Boolean], "json.register"),

evalJson:Strict(Object, function(json){
// ... code ...
}, [String], "json.evalJson"),

serialize:Strict(String, function(o){
// ... code ...
}, [Object], "json.serialize")
};


As You can see, JavaStrict syntax, using Strict function shortcut, is not so different from Java or other languages:

returnType <== callback <== [One, Or, More, Argument, Type]


You can use JavaStrict function to compare generic instances too.
For example, if You need a function that accept at least an Object, with different type, You can compare them using one or more constructor:

doSomething = Strict(
String, function(o){

var somethingToDo;
switch(true) {
case JavaStrict(o, Array):
somethingToDo = "pop";
break;
case JavaStrict(o, String):
somethingToDo = "toUpperCase";
break;
default:
somethingToDo = "toString";
break;
};
return o[somethingToDo]();

}, [Object]
);



At this point the uniq thing that's not yet done, is this dedicated Dojo version :-)

dojo.strict = function(returnValue, callback, arguments, name){
return dojo.strict.debug ? dojo.strict.returnValue(returnValue, dojo.strict.apply(callback, arguments, name), name) : callback
};
dojo.strict.apply = function(callback, args, name){
return function(){
for(var i = 0; i < arguments.length; i++){
if(!dojo.strict.check(arguments[i], args[i]))
throw new Error("[".concat(name || callback.name, "] dojo.strict arguments ", i, " Error"));
};
return callback.apply(this, arguments)
}
};
dojo.strict.call = function(){
var name = (arguments = [].slice.call(arguments)).length;
return dojo.strict.apply(arguments.shift(), arguments, dojo.strict.check(arguments[name-2], "".constructor) ? arguments.pop() : dojo.strict.Void)
};
dojo.strict.check = function(arguments, constructor){
var returnValue = constructor === dojo.strict.Void;
return arguments === dojo.strict.Void ? returnValue : (arguments === null ? !returnValue : (returnValue ? false : (dojo.strict.object ? (typeof arguments === "object" ? arguments instanceof constructor : arguments.constructor === constructor) : (constructor === Object ? true : (arguments instanceof constructor || arguments.constructor === constructor)))))
};
dojo.strict.returnValue = function(args, callback, name){
return function(){
var returnValue = callback.apply(this, arguments);
if(!dojo.strict.check(returnValue, args))
throw new Error("[".concat(name || callback.name, "] dojo.strict returnValue Error"));
return returnValue
}
};

dojo.strict.debug = true;
dojo.strict.object = false;
dojo.strict.Void = undefined;



testMe = dojo.strict(String, function(o){return o.toString()}, [Object], "testMe");
try {
alert(testMe(dojo)); // Ok
alert(testMe(dojo.strict)); // Ok
alert(testMe(dojo.strict.Void)); // Error
}
catch(e) {
alert(e);
};

Wednesday, May 23, 2007

JavaStrict Act II - AS2.0 like Strict Type with JavaScript

I've just updated my JavaStrict public, static, function.

It has been successfully tested with different cases and now it behaviour is like ActionScript 2.0

With this function, and dedicated Strict shortcut one, You can:


  • define a return type, using a specific constructor or Void, if function mustn't return any kind of variable (null too)

  • define one or more argument constructor, using specified constructor or Void if function mustn't accept any kind of parameter (null too)

  • use a generic Object constructor, as returned or accepted instance if You don't know what kind of object function, r method, will accpet or return



You can use Object for DOM elements too, expecially with Internet Explorer (6 or lower) where DOM Elements are typeof "object" but aren't instances of Object.

Object is the super incoming or outgoing value type, it can be null or every kind of instance (obviously, Void is not Object, so You can't use Object to return Void values and vice-versa).

You can specify every other constructor type as returned value or accepted parameter, so You can write JavaScript using a special Stric Type automatic check to create easyly your own Web Apps, having an exception every time some parameter is wrong or isn't expected type.

I hope someone will be interested about this new way to write and debug JavaScript, quite strongly typed, not yet compiled style but, at least, more debuggable with every kind of library.

Performance ? Good enought, so have fun with JavaStrict :-)

(read here to view some example)

Sunday, May 20, 2007

JavaStrict - Strict Type arguments / returned values with JavaScript

I've just uploaded on devpro my last experimental (stable) function, called JavaStrict.

What is JavaStrict goal?
JavaStrict allows developers to add Strict Type in every kind of function or method, with or without prototype.

Strict Type should be used for function arguments or for its returned value.

JavaStrict static methods just create a function wrapper that will check automatically if arguments or returnValue are exactly specified instances.


How does JavaStrict work?
JavaStrict function has 3 public static methods:

  • apply, to set Type of each accepted argument using an array as second one

  • call, to set one or more valid Type manually

  • returnValue, to set a valid returned value Type




Examples

// showMe is a basic function
function showMe(str){
alert(str);
};

// I need that single argument is a string instance
// (new String("abc") or "abc" works correctly)
showMe = JavaStrict.call(showMe, String);

// test them
try {
showMe("Hello Strict!"); // Ok
showMe(1); // Error!
}
catch(e) {
alert(e); // argument 0 is not a String instance
};


This is just the first basic example ... let's go to view something more interesting ?


// constructor example with
// 2 public methods and a private
// property
function MyConstructor(){
var property = "";

this.getProperty = function(){
return property;
};

// I need this method accept only String instances
this.setProperty = JavaStrict.call(function(value){
property += value;

// don't worry about internal scope (this referer)
alert(this.getProperty());
}, String);
};

// test them
var instance = new MyConstructor;
instance.setProperty("test");
instance.setProperty(new String(" me"));
try {
// this time I try to set an object
// that's not a String instance
instance.setProperty({});
}
catch(e) {
alert(e);
}


Seems interesting? That's another example, using public static returnValue method:

charToCode = JavaStrict.returnValue(
Number,
JavaStrict.call(
function(str){
return str.charCodeAt(0);
},
String
)
);

try {
alert(charToCode("a"));
}
catch(e) {
alert(e);
}

charToCode is a function that accept only String instances and returns a Number.
If You try to change function return usng, for example, a String or another type of instance, You'll view Error instead of char code.

If You want to create easyly strict type functions/methods You could use this shortcut too:
Strict = JavaStrict.call(function(returnValue, callback, arguments){
return JavaStrict.returnValue(returnValue, JavaStrict.apply(callback, arguments))
}, Function, Function, Array);

charToCode = Strict(Number, function(str){return str.charCodeAt(0)}, [String]);

Strict accepts a valid return type as first argument, callback as second and its arguments type as third parameter (that need to be an Array, as specified on Strict declaration).



apply and call difference
Both apply and call do the same thing but in a different way:

function concat(a, b){
return "".concat(a, b);
};

// after one of these lines concat will accept
// only String instances
concat = JavaStrict.call(concat, String, String);
// the same of ...
concat = JavaStrict.apply(concat, [String, String]);


If You want to add a String instance as return value, just use this line before or after call/apply one:

concat = JavaStrict.returnValue(String, concat);



How to accept or return every kind of instance?
JavaScript is not strongly typed (atleast not yet) and sometime a generic argument or returned parameter should be useful.
For these case You can specify, as expected argument/result, generic Object instance, that will accept null or undefined variables too.
However, if You use Object for every method, function or returned value, probably You don't need JavaStrict.


I hope this simple, tiny and packable function will be useful for your next JavaScript project!

Thursday, May 17, 2007

Joking with JavaScript constructors

This object is Rhino on Cocoon Flow.js Ready (if it's configured to don't use code evaluation using eval), have fun with crazy inheritances and constructors :)
var Instance = {

/*
Description:
creates a new instance of specified constructor using second parameter as constructr arguments.
This is just a New method alias.

Example:
var str = Instance.Create(String, ["Hello World"]);

Arguments:
Function instance constructor
Array constructor arguments or empty array

Returns:
Object new instance of specified constructor
*/
Create:function(){
return this.New.apply(this, arguments);
},

/*
Description:
creates a new instance of last specified constructor and extends them with every precedent constructor, if present.
Each constructor need to have a dedicated array (empty too) to use them as its arguments.

Example:
function String2(){
this.trim = function(){
return this.replace(/^\s+|\s+$/g, "");
};
};
var str = Instance.Extended(String2, [], String, [" Hello World! "]);

Arguments:
Function1 instance constructor
Array1 constructor arguments or empty array

[Function2 optional instance constructor
Array2] constructor arguments or empty array

...

[FunctionN optional instance constructor
ArrayN] constructor arguments or empty array

Returns:
Object new instance of last specified constructor.
Every precedent constructor will be inherited
without prototype (Object will be instance of last constructor).
*/
Extended:function(){
for(var
i = arguments.length - 3,
Instance = this.New(arguments[i + 1], arguments[i + 2]);
i > 1; i -= 2
) arguments[i - 1].apply(Instance, arguments[i]);
if(arguments.length - 2)
arguments[0].apply(Instance, arguments[1]);
return Instance;
},

/*
Description:
Only one difference with Extended: last argument must be an array, used as every constructor arguments.

Example:
var str = Instance.Multiple(String2, String, [" Hello World! "]);

Arguments:
Function1 instance constructor
[Function2] optional instance constructor

...

[FunctionN] optional instance constructor
Array constructor arguments (used with each constructor) or empty array

Returns:
Object new instance of last specified constructor.
Every precedent constructor will be inherited
without prototype (Object will be instance of last constructor).
*/
Multiple:function(){
var j = arguments.length - 1,
i = 0,
Instance = [];
while(i < j)
Instance.push(arguments[i++], arguments[j]);
return this.Extended.apply(this, Instance);
},

/*
Description:
Method used by Create one.
*/
New:function(constructor, arguments){
for(var
i = 0,
j = arguments.length,
Instance = new Array(j);
i < j; i++
) Instance[i] = "arguments[".concat(i, "]");
return new Function("constructor, arguments",
"return new constructor(".concat(Instance.join(","), ")")
)(constructor, arguments);
}
};