Friday, March 18, 2011

High order loop function in Javascript

Writing Javascript code after Groovy code makes you wish you could extend the language. So I tried to write a Javascript function to rewrite the 'for' loop in a different way, passing the loop parameters and a function to my new 'loop' function. Here are a few ways of doing it, the difference is how the 'for' parameters are passed to the 'loop' function. I wish this was integrated in jQuery, that would make some code more fluid than a 'for' loop in the middle of jQuery code. The next step could be to add the little bit of code to make it a jQuery extension.

OBJECTIVE:
I want to replace a *normal* for loop like this:

var res = []; // array to hold all the results of the fn(args) calls
for (var i = 0 ; i < max ; i + step) res.push(fn(args)); // loop and call the fn(args) function, collecting the results in the res array

by something a bit less verbose like that:

var res = loop(0, max, step, fn, args);

First try:

Passing the parameters in an array [start, end, increment] and the function to call as the second argument. The argument for the function is not there, because I worked out a second form that I like better before including the argument for the function.

Params:
p : number or array

- if number: end index value. The start index is set to 0 and the increment to 1.
- if array of numbers:
p[0] = loop index start
p[1] = loop index end + 1
p[2] = loop index increment

fn: function to apply in the loop. The function receives the loop index as its argument

Result:
Array of results returned by the function

Loop function definition:

function loop(p, fn)
{
var ar = [];
for (var k = (p[0] || 0) ; k < (p[1] || p) ; k += (p[2] || 1))
{
var r = fn(k);
if (r !== undefined) ar.push(r);
}
return ar; // return an array of the function results
}

Examples:

var fn1 = function(index)
{
alert("fn1 index: " + index);
return (index);
}

var res = loop(4, fn1);
alert("fn1 result: " + res); // [0,1,2,3]

res = loop([1, 10, 2], fn1);
alert("fn1 result: " + res); // [1,3,5,7,9]


Second try: to avoid the array for the loop parameters, the loop function can be written like the following. Parameters for the function have been added as well.

function nloop(_s, _e, _i, _f, _c, _a0, _a1, _a2)
{
// _a0, _a1, _a2 are the argument to pass to the function, on top of the index. Optional
// Default if all arguments are specified
// call arguments: (start, end, step, function [,context [arg0 [, arg1 [, arg2]]]]).
var c; // function context: 'this' for the function. Optional
var f; // function to call, required
var i; //  step, loop increment. Optional
var e; // loop end. Optional
var s; // loop count or loop start if _e is defined. Required
var ar = []; // result, array of results from the function _f calls

if (_f instanceof Function)
{
c = _c;
f = _f; // function to call
i = _i; //  step
e = _e; // end
s = _s; // loop count or loop start if _e is defined. Required
}
// call arguments: (start, end, function, context). Default step = 1.
else if (_i instanceof Function)
{
c = _f;
f = _i; // function to call
i = 1; //  step
e = _e; // end
s = _s; // loop count or loop start if _e is defined. Required
}
else if (_e instanceof Function)
{
c = _i;
f = _e; // function to call
i = 1; //  step
e = _s; // end
s = 0; // loop count or loop start if _e is defined. Required
}
else return ar;
// alert('start: ' + s + ' end: ' + e + ' step: ' + s);
// var undef; // to test if the function result is undefined
for (var k = s ; k < e ; k += i)
{
var r = f.call(c, k, _a0, _a1, _a2);
// if (!(r === undef)) // looks like it's working in FF and IE6. Is it a proper way to test for undefined?
if (typeof(r) !== 'undefined') // would it be a bit slow to test for a string?
{
// alert('f result: ' + r);
ar.push(r);
}
}
return ar;
}

Examples of calls:

var fn2 = function(index, a, b, c)
{
// check the parameters and the context
alert("fn2 index: " + index + ' a: ' + a + ' b: ' + b + ' c: ' + c + ' this.name: ' + this.name);
return (index);
}

// An object to pass as the context (aka 'this') for the function called in the loop
var anobject = { name: 'an Object' };

// loop from 1 to 10 step 2, calling fn2 with 'anobject' as 'this' and with 'a', 'b' and 'c' as parameters to fn2
res = nloop(1, 10, 2, fn2, anobject, 'a', 'b', 'c');
alert('nloop fn2 result: ' + res);

res = nloop(1, 3, 1, fn2, anobject, 'a', 'b', 'c');
alert('nloop fn2 result: ' + res);

// function parameters are optional
res = nloop(1, 10, 2, fn2, anobject);
alert('nloop fn2 result: ' + res);

// step optional
res = nloop(1, 5, fn2, anobject);
alert('nloop fn2 result: ' + res);

// start index optional, 4 is the end index + 1
res = nloop(4, fn2, anobject);
alert('nloop fn2 result: ' + res);

var fn3 = function(index)
{
alert('fn2 index: ' + index);
return index;
}
res = nloop(1, fn3, anobject);
alert('nloop fn3 void result: ' + res + ' res == []: ' + (res == []) + ' res == null: ' + (res == null) + ' res.length: ' + res.length);


Sunday, July 18, 2010

On Reserved Words in Programming languages...


I just got bitten by IE when I inadvertently used 'class' as a variable name in Javascript. Firefox doesn't mind but IE generates an error (and I am glad it does). My reference (the David Flanagan "Javascript, The Definitive Guide", 4th Ed) shows that 'class' is not a reserved word in the ECMAScript (aka Javascript) Language definition, but is in the ECMA extension. I should not have used it anyway, I wasn't not paying attention, especially when Notepad++ was showing it as a reserved word in italic.


That's not the first time I encounter that issue, SQL has many variants and it's quite difficult to know and remember what words are reserved in which dialect of SQL. Using Hibernate or other layers on top of a SQL database complicates that as well. I spent some time in the past chasing a bug like this in one of my Grails applications.


So, in conclusion: if I was a good boy, I would get the list of reserved words of all the components that have some in each of my projects and keep them handy for a check when things look really weird, or as part of a final Q&A check.

Thursday, October 15, 2009

Over my last few Grails projects, although Grails cuts the number of code lines for a Web application down a lot, I realized that I was doing a lot more of code editing than I wanted to. A few areas on my projects needed some improvement: the controllers and the views (show, edit, create) are mostly the same for different domain objects and a lot of code for the persistence should be in services instead of the controllers.

I also wanted to be able to test the persistence layer independently from the controllers and being able to switch to something else than Hibernate if I wanted to without having to touch the controller code. So I designed a project with an "InstanceController", two views and an "InstanceService" that implements the common code for most domain objects. This is really the first draft and I envision a lot of improvements over this concept. With the dynamic features of Groovy, it could be possible to add the same features in a Groovy-er way. Work in progress.

The InstanceController works with two views for each domain object: "crud.gsp" and "list.gsp" and the InstanceService sub-classed for the particular domain object. So the structure of the Grails project is basically the same but "crud.gsp" implements all the functions of "edit.gsp", "show.gsp", "create.gsp".

So no more of editing three files when the domain object changes or the GUI changes. The GUI is consistent across the CRUD operations. The controller has an additional action "formactions" used in "crud.gsp" to manage the "cancel", "save", "edit" and "delete" buttons in the "crud.gsp" view. It also has a "void bindmore(instance, params)" method that can be overridden to bind checkboxes or other particular HTML elements to the domain class properties.

The usual "index", "list", "show", "create", "edit", "update", "delete" and "save" actions are still there if needed, but the view is handled by "crud.gsp" and the "formactions" in the controller. "formactions" calls "create", "edit", "save" and "delete" from the buttons clicked in "crud.gsp". All action closures call the methods of the same name to be able to override them in a subclass of the InstanceController.

The UI flow is: display "list.gsp", from an application menu for example, then a click on an item in the list calls "show" in the subclass of InstanceController for the domain object, which displays "view/domainobject/crud.gsp". Then clicking "delete", "edit", "save" or "cancel" calls the "formactions" closure in "/controller/domainobjectController". "formactions" calls "save", "update", "delete", "create" or displays the "list.gsp" view.

A couple of things there, the handling of "cancel" can be done with consistence, depending on the context and the application. "cancel" while editing means drop the changes and go back to the "show" mode, but "cancel" in show mode should go back to the "list" view. We could also hide the "cancel" button in "show" mode in "crud.gsp".

A small, but quite appreciated by the users, feature is highlighting the last object worked on in the "list.gsp" view. The object instance "id" is passed to "list.gsp" which adds the "selected" class to the line where the object is displayed, so the line is highlighted in the table (in yellow with my CSS style). It makes it very easy for the user to locate the last line worked on.

The GUI mode ("SHOW", "EDIT", "CREATE" is maintained between "crud.gsp" and "formactions" in the InstanceController and allows showing or hiding elements and buttons.

The subclass of the "InstanceController" must implement the "setup" method to define the "InstanceService" associated with the controller for the persistence operations and the domain object name displayed in the views. The "InstanceController" subclass can override any of the "InstanceController" methods if need be.

For the persistence layer, the "InstanceService" implements "list", "getCount", "getById", "newinstance", "save", "update", "delete", "findByName", "createDefaults" (creates initial values if none exist in the database) and "archive" if the domain object has an "archived" property. The subclass of "InstanceService" for the domain object needs to implement the "setup" method, where the initial domain objects are defined in the "defaults" list if needed. The "instanceclassname" containing the domain class name must be defined as well as the domain object property name used for sorting the "list.gsp" view. Here too, the "InstanceService" subclass can override any of the "InstanceService" methods if need be. Last thing not to forget, the "setup" method of each "InstanceService" subclass must be called in "Bootstrap.groovy", or in the "setUp" method of any integration test.

The domain class must implement "String toMessage()", to display a user-friendly domain object name. For example, my class name is "Streettype", but "toMessage" will return "Street Type". It's used in "crud.gsp" and "list.gsp". "toString" could be used, but then a bit tricky if "toString" is also used for debugging. I guess we could check if "toMessage" is implemented and use "toString" if not.

The code is posted at http://code.google.com/p/thecodefactory/wiki/GrailsRefactoring



Friday, November 23, 2007

I just discovered the "Scala" language, thanks to an excellent article "Java EE meets Web 2.0" (http://www.ibm.com/developerworks/web/library/wa-aj-web2jee/) on IBM's developerWorks. Scala is very close to Java and generates class files that run on the JVM. I am a user and a fan of Groovy, but I am interested in Scala for its Actors library: Actors are "tasks" that can send and receive messages synchronously or asynchronously. There is a short tutorial at http://lamp.epfl.ch/~phaller/doc/ActorsTutorial.html by Philipp Haller, the author of the library.

The Scala documentation says that Scala objects can call Java objects and vice-versa. I wanted to write a code snippet to see how a Java application can create and call Scala objects. It's very basic but it works!

A Java class "Zoo" with the "main" method creates a Scala object "Dog" and calls its method "talk".

Running the Zoo main on Windows:

C:\ScalaTest>java Zoo
Zoo...
Woof, woof!

Here it is the code for the 2 files Zoo.java and Dog.scala:

Zoo.java:

class Zoo {
public static void main(String[] args)

{
System.out.println("Zoo...");
Dog dog = new Dog();
dog.talk();
} // main
} // class Zoo

Dog.scala:

class Dog
{
val sound = "Woof, woof!"
def talk() = println(sound)
} // class Dog

How to build it on Windows:

Compile the Scala file first:
C:\ScalaTest>scalac Dog.scala

Then compile the main app, Java will find the Dog.class
C:\ScalaTest>javac Zoo.java

Run it:

C:\ScalaTest>java Zoo
Zoo...
Woof, woof!

"Zoo" is printed by the Java Zoo class
"Woof, woof" is printed by the Scala "Dog" class.

That's it!

Preliminary steps to install Java and Scala:
  • install a JDK (download it from http://java.sun.com/javase/downloads)
  • add the path to your java \bin folder (something like C:\jdk1.5.0_09\bin) to your PATH environment variable.
  • check that the Java compiler is accessible by opening a cmd window an typing "javac" and return. A list of options will be displayed, starting like this: "Usage: javac ...".
  • add the Java libraries to the "classpath" environment variable, something like this: "classpath=.;C:\jdk1.5.0_09\jre\lib\rt.jar;C:\jdk1.5.0_09\lib\tools.jar;"
  • install Scala (download it from http://www.scala-lang.org/)
  • add the Scala bin folder to your PATH environment variable. Should look like this: "...;C:\scala-2.6.0-final\bin;"
  • add the Scala libraries to the "classpath" environment variable. Should look like this with the Java libraries: "classpath=.;C:\jdk1.5.0_09\jre\lib\rt.jar;C:\jdk1.5.0_09\lib\tools.jar;C:\scala-2.6.0-final\lib\scala-library.jar;"
  • check that the Scala compiler is accessible from a cmd window: "C:\ScalaTest>scalac" will display a list of options: "Usage: scalac ..."

That should do it. If not, check java.sun.com for Java installation issues and scala-lang.org for the Scala ones.

I am off to try some Actors code in Scala.

Wednesday, October 25, 2006

I just did some work with the YahooUI Calendar and created a helper to make it easier to use. It is a Javascript file that you include in your HTML page header, a SPAN or DIV element where the icon for the calendar and the calendar itself will be displayed and a SCRIPT where the YahooCalendar object is created with a few parameters.