« [Tip] HTML subsummary example | Main | [Tip] Barcodes Baby! »

March 23, 2005

[Challenge] Week 3/7/05: Code Contortions (answer)

by David Workman
Data Mosaic, Inc

(original challenge here)

Like almost any endeavor -- say for example which route to take to the grocery store -- writing code in Servoy can be done in a number of ways for a given task. The question then becomes: what makes for "better" code? This is not always clear so knowing a variety of coding techniques can be helpful.

Some things to consider about your code:

  • execution speed
  • ease of reading and debugging
  • reusability
  • how long it takes to write

All five of the methods that I listed do the same thing. No tricks involved! Each one takes a specified number of field objects on a form and changes the background and foreground color of each field based on the values in two global fields that the user chooses:

Screen1_5

With these thoughts in mind, let's take a look at the differences of each method.

Method 1

In this method I set each property of each object individually. This is as about as straight forward of a method as you can get. While easy to read and understand, it suffers on all other accounts. First, if I had 100+ field objects on the form, that is a lot of clicking and typing so it's not a very fast way to get the job done. Second, this code will only work for this one form leaving it as the worst contender in the flexibility department.

I find myself only coding in this style when I'm testing functionality of a method and need to see exactly what is changing. Once I get everything working the way I expect, I will almost always convert this type of coding to one of the following styles.

//user defined styles (VER 1)

elements.fld_city.fgcolor = globals.fgcolor;
elements.fld_city.bgcolor = globals.bgcolor;

elements.fld_companyname.fgcolor = globals.fgcolor;
elements.fld_companyname.bgcolor = globals.bgcolor;

elements.fld_contactname.fgcolor = globals.fgcolor;
elements.fld_contactname.bgcolor = globals.bgcolor;

elements.fld_contacttitle.fgcolor = globals.fgcolor;
elements.fld_contacttitle.bgcolor = globals.bgcolor;

elements.fld_country.fgcolor = globals.fgcolor;
elements.fld_country.bgcolor = globals.bgcolor;

elements.fld_dateee.fgcolor = globals.fgcolor;
elements.fld_dateee.bgcolor = globals.bgcolor;

elements.fld_ddd.fgcolor = globals.fgcolor;
elements.fld_ddd.bgcolor = globals.bgcolor;

elements.fld_fax.fgcolor = globals.fgcolor;
elements.fld_fax.bgcolor = globals.bgcolor;

Method 2

This is the standard way to loop through objects on a form. You get the number of objects using the "elements.length" function. Notice that I've put in a check for object names and only process objects with names starting with "fld". This is important in case you have other named objects on the form that you don't want to process.

The strength of this coding style is that it works with unlimited number of objects, works with any form, and can target specific objects using naming conventions. Once you attain comfortable coding skills, this method scores high marks on all of the coding concerns: execution speed, ease of debugging, reusability and time it takes to write.

//user defined styles (VER 2)

var check;

for ( var i = 0 ; i < elements.length ; i++ )
{
    check = elements[i].getName();
    check = check.slice(0,3);    
    
    if (check == 'fld')
    {    
        elements[i].fgcolor = globals.fgcolor;
        elements[i].bgcolor = globals.bgcolor;
    }    
}

Method 3

This is a variation of method 2. I basically compress seven lines of code in the previous example to four lines in this example. This savings was accomplished by combining the check for the string "fld" onto one line. This demonstrates the object oriented nature of JavaScript.

I also introduce a different variation of the "for" statement. Instead of the usual "for ( var i = 0 ; i < elements.length ; i++ )" JavaScript allows me to loop through all the children of an object using "for (var i in [object])" where "elements" is the object. Since this loop will process every object.child, this isn't necessarily the fastest executing method because Servoy has a number of hidden objects that method 2 doesn't not process. View the variables in the debugger to see what I'm talking about (word of caution: don't start trying to change the properties of these hidden objects unless you want to spend the next two hours putting Servoy back together with glue and tape).

//user defined styles (VER 3)

for (var i in elements)
{
    if (elements[i].getName().slice(0,3) == 'fld')
    {    
        elements[i].fgcolor = globals.fgcolor;
        elements[i].bgcolor = globals.bgcolor;
    }    
}

Method 4

Now I'm starting to get a little esoteric. Not only do I loop through each object element using the "for" statement variation, I also loop through each of the functions and properties of a named element the same way. As a result, I use a switch statement to check for when I hit the property I want to process. In a sense, I've turned the logic inside out in this method.

Is this style of coding useful? Who knows. I'll let you know someday if this technique saves me.

//user defined styles (VER 4)

for (var i in elements)
{
    if (elements[i].getName().slice(0,3) == 'fld')
    {
        for (var k in elements[i])
        {        
            switch(k)
            {
                case 'fgcolor':    elements[i][k] = globals.fgcolor; break;
                case 'bgcolor': elements[i][k] = globals.bgcolor; break;
            }
        }    
    }
}

Method 5

In this context this method is major overkill. However, it illustrates one way to set up and process your own data structures to use as reference data. In an earlier challenge, setting up my own data structures was the key for abstracting the code to use throughout a solution.

This particular data structure ("elementOBJ") is called an associative array. A normal array is referenced by number; as in: myArray[0] = 'red'. An associative array is referenced by a unique name such as: myArray['favoriteColor'] = 'red'. You can also reference an associative array with an alternate notation: myArray.favoriteColor = 'red'. Do the two sytax variations look familiar? Yup, all objects in Servoy are associative arrays! Which reveals the mystery of why you can reference Servoy objects with either notation.

//user defined styles (VER 5)

var propertyARY = new Array("fgcolor", "bgcolor");

var valueARY = new Array(globals.fgcolor, globals.bgcolor);

var elementOBJ = new Object;
        
for ( var i = 0 ; i < propertyARY.length ; i++ )
{
    elementOBJ[propertyARY[i]] = valueARY[i];
}

for (var i in elements)
{
    if (elements[i].getName().slice(0,3) == 'fld')
    {
        for (var k in elementOBJ)
        {
            elements[i][k] = elementOBJ[k];
        }    
    }
}

Conclusion

Knowing how do code in a variety of ways gives you flexibility to choose the best way for the challenge at hand. When you are new to JavaScript, you will naturally code with readability and debugging as your priorities. As your experience increases, you will find that coding with reusability as your priority will save you a LOT of time. Understanding the fundamental nature of objects and combining with naming conventions is the key to making this "abstract" coding style work for you.

| Posted by David Workman on March 23, 2005 at 12:57 PM in Challenge | Permalink

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/t/trackback/118167/2116677

Listed below are links to weblogs that reference [Challenge] Week 3/7/05: Code Contortions (answer):

Comments

Thanks David

Showing multiple ways to achieve the same task is a great training method. A feature on 'associative arrays' would have been useful - but probably hard to follow - however being able to compare with the simple methods made it clear for me.

Great work.

Graham

Posted by: Graham Greensall | Mar 24, 2005 3:56:09 AM

Post a comment