Implementing JavaScript Generics

an article added by: Sonja Lande at 05312007


In: Categories » » AJAX » Implementing JavaScript Generics

Problem You want to implement “generics” in JavaScript. Theory Programming languages such as Java and C# have a programming concept called generics. The idea behind generics is to write code in such a way that an identifier is defined as a general type that is manipulated in a class or method. For example, the following code would be a generic class in either Java or C#:

    class Container<Type> {
    Type _managed;
 }

The Container class has a generic parameter, Type, which can reference any other type. And in the declaration of Container, the _managed data member is the same type as the generic parameter. In an abstract notion, Container manages any type. A JavaScript programmer might look at the code and think, “Hey, I have this already in JavaScript!” Here is the same code, this time in JavaScript:

    function Container() {
    this._managed = /* whatever type */
 }

As illustrated in Recipe 2-8, you can have reference-based duck typing or value-based duck typing. Implementing “generics” for JavaScript is like implementing a preprocessor, thus we want value-based duck typing. The following code example shows what can go wrong when you mix value and reference duck typing together:

    proxy : function(instance, funcIdentifier,  newFunc) {
    if (!instance[funcIdentifier]) {
    throw new Error("Cannot proxy nonexistent  method(" + funcIdentifier + ")");
    }
    eval( "var generatedOrigFunc = " +  instance[funcIdentifier].toString());
    eval(  "var generatedProxyFunc = " + newFunc.toString());
    instance[funcIdentifier] = function() {
    var  origFunc = generatedOrigFunc;
    var  proxyFunc = generatedProxyFunc;
    var args = new Array();
    for (var c1 = 0; c1 < arguments.length; c1  ++) {
    args.push(arguments[c1]);
    }
    args.push(origFunc);
    args.push(arguments);
    proxyFunc.apply(this, args);
    }
 },

This source code is an example of how not to write a Proxy pattern implementation. The problem of the implementation is shown in the bold code. At the beginning of the bold code are two eval statements, which are generating the values of the generatedOrigFunc and generatedProxyFunc variables. In the embedded function instance[funcIdentifier], the variables are referenced, and due to closure, the origFunc and proxyFunc variables will reference the correct variables. The concept of the Proxy pattern is that when a method is called, it first calls the function referenced by proxyFunc, which then calls the function referenced by origFunc. Because proxyFunc is called first, it has the ability to preprocess or postprocess the data.

The code as written will work with a single application of the Proxy pattern, but it will fail if the proxy pattern is applied multiple times. For example, imagine the generated code embedding of the Proxy pattern on an already applied Proxy pattern. This code is an example of a “gotcha” piece of code in JavaScript. Look closely at the declarations of the generatedOrigFunc and generatedProxyFunc variables what are they referencing? To understand the error, think of the proxy code on the left as proxy implementation 1 (PI1) and the code on the right as proxy implementation 2 (PI2). If a generic caller were to call PI1, the following sequence of events would take place:

1. PI1 is called.

2. PI1’s proxyFunc is called.

3. PI1’s origFunc is called, which is PI2.

4. PI2’s proxyFunc is called, which is PI1’s proxyFunc.

5. PI1’s proxyFunc is called, calling PI1’s origFunc. Following these steps, you will notice that a recursion is taking place. The recursion is because of the way the generatedOrigFunc and generatedProxyFunc variables are declared. These variables are declared without any scope and because the proxy scope function is amix of using references with eval code. This is a bad practice, because some variables will be serialized and others will not. We want a solution like the C preprocessor, where “generics” represent the physical replacing of an identifier with a desired type. We don’t want a templating system. A templating system would be described as follows:

   <%for( var count = 0; count < 10; count  ++) {%>
    series[<%=count%>] = GenSeries(  <%=count%>)
   <%}%>

This isn’t what we want because the code readability decreases dramatically, and in general it is not necessary. JavaScript is a dynamic code language, and many of the templating constructs can be implemented in code. It’s more difficult to implement the changing of a variable from using references to using values. Solution For illustration purposes, let’s simplify the Proxy pattern to a single method with a single method call, as follows.

    Source: /website/ROOT/ajaxrecipes/javascript/generics.html
    function EmbeddedReplace() {
    var func = __toCall;
    info( "Replace", "hello");
    func();
 }

The EmbeddedReplace function has declared a local variable, func. The func local variable references the __toCall variable. After the declaration of func is a call to the info function. The last function call is to func, which is a function call to __toCall. From looking solely at the usage of __toCall, you don’t know much about the declaration other than it’s a global variable. For the scope of this recipe, __toCall is an identifier that will be replaced. A JavaScript expansion call would be as follows (I’ll discuss the details shortly):

    EmbeddedReplace = Generics.expand(  EmbeddedReplace,
    { __toCall: function() { info(  "replaced in Replace", "hello");}});
 EmbeddedReplace();

The Generics.expand method has two parameters. The first parameter is the EmbeddedReplace function, which will have its implementation modified. The second parameter is the object structure that represents what identifiers will be replaced. The object structure is defined such that the property identifier defines the identifier to be replaced, and the value associated with the property is the replaced value. Note All of the code presented here uses standard JavaScript programmatic techniques. You don’t need to use special buffers or tags that confuse editors and make it more complicated to build reliable, maintainable code. When the Generics.expand method has finished executing, the following function declaration is generated:

    function GeneratedEmbeddedReplace()  {
    var func = (function () {
    info("replaced in  Replace", "hello");
    });
    info("Replace",  "hello");
    func();
 }

The generated buffer is what we expect, and the behavior is what we expect. When GeneratedEmbeddedReplace is called, the embedded function is called. For comparison’s sake, let’s look at how this could have worked without expanding an embedded function:

    function __toCall() {
    info("replaced in Replace",  "hello");
    };
    function EmbeddedReplace() {
    var func = __toCall;
    info( "Replace", "hello");
    func();
 }

Calling GeneratedEmbeddedReplace will call the __toCall function and behave, look, and feel like the expanded example. But why should you do this? The reference-based expansion is not an expansion at all. You have simply created a global variable (__toCall) that can be assigned at runtime. With a value-type expansion, you can have multiple functions with different functionalities that do not conflict with one another. Because behavior is determined by assignment, you can run into the situation outlined in Recipe 2-14, where functions are shared. If functions are shared, then a conflict can arise if the functionality of the function is altered. Or you can have a situation where a function does one thing one time, and another thing another time. To illustrate the “do one thing now, but not later” problem, consider the following code scenario:

    function __toCall() {
    info("replaced in Replace",  "hello");
    };
    function EmbeddedReplace() {
    info( "Replace", "hello");
    __toCall();
    }
    function Caller() {
    EmbeddedReplace();
    __toCall = function() { }
    EmbeddedReplace();
 }

When Caller is called, the first call to EmbeddedReplace results in some output. Then __toCall is reassigned, and calling EmbeddedReplace again results in other output being generated. Maybe this is the desired effect, but most likely it isn’t. One way to solve the problem is to restrict your usage of the dynamic capabilities of JavaScript. However, at this point I would ask, why are you using JavaScript and Ajax? My opinion is that JavaScript and Ajax represent an evolution in programming and thus you should use their dynamic behavior capabilities.

Had EmbeddedReplace been expanded, then modifying __toCall would have had no effect on EmbeddedReplace. And this is what you need to consider when writing JavaScript code. Sometimes you will use references, and sometimes you will use expansions like those proposed by JavaScript generics. I would like to add one more point. It is not a rule of thumb, but an idea that in specific contexts can have its place. Imagine writing an application where a payment is calculated based on the current daily interest rate. In most programming languages, the current interest payment would be a variable that would be loaded and assigned at runtime. Using JavaScript generics and behavior-based code, the following expanded code could be used:

    function CalculateInterestPayment( amount) {
    return amount * 0.04;
 }

This code is what other programming languages call hard-coded. It’s considered hardcoded because the number 0.04 is compiled into the application and cannot be changed. But here is the advantage of the behavior-based code: using JavaScript generics, the hard-coded value is trivial to change, and keeping to a traditional programming model when you don’t need to doesn’t make any sense whatsoever.

You use a hard-coded programming strategy when the data is read-mostly, or when the data is read more often than it is written. Having the data hard-coded can be a performance gain, offer more flexibility, and simplify the algorithm. Using JavaScript generics today, the interest calculation is a simple number, but tomorrow the calculation could be a compound calculation that uses a sliding rule based on the amount that is processed. Having explained the why, how, and when of JavaScript “generics,” I’ll now cover how JavaScript “generics” are implemented. It’s a very simple process that involves searching and replacing an identifier in a buffer. The full implementation is as follows.

    Source: /website/ROOT/scripts/common.js
    var Generics = {
    expand : function(toProcess,  itemsToInject) {
    var bufferToProcess =  ops.singleSerialize(toProcess);
    for( itemToReplace in  itemsToInject) {
    var recurFind =  function(startIndex) {
    var offset =  bufferToProcess.indexOf(itemToReplace, startIndex);
    if (offset == -1) {
    return;
    }
    var left = bufferToProcess.slice(0,  offset);
    var right = bufferToProcess.slice(offset  + itemToReplace.length);
    var middle =  ops.simpleSerialize(itemsToInject[itemToReplace]);
    bufferToProcess = left + middle +  right;
    offset ++;
    recurFind(offset);
    }
    recurFind(0);
    }
    var genBuffer = "var cls =  " + bufferToProcess + ";";
    eval(genBuffer);
    return cls;
    }
 }

To expand a JavaScript object, the object has to first be converted to a buffer. The ops.singleSerialize method converts any JavaScript object into a buffer, and in the case of the preceding example, it converts the toProcess parameter into a buffer. After the conversion to a buffer, the process of finding an identifier and replacing it using a loop is started. With each iteration of the loop stored in the itemToReplace variable is the identifier to replace in bufferToProcess. In the loop, the recurToFind variable references a function that is called recursively. The purpose of the recursion is to incrementally search the buffer for the identifier to replace.

Note Recursion strategy is covered in Recipe 2-6. To find an identifier within bufferToProcess, the indexOf method is used. indexOf has two parameters: the first parameter is the identifier to find, and the second parameter is the index to start searching. If indexOf does not find an identifier, then a value of -1 is returned and the recursion stops. If indexOf finds the identifier, then the index of where the identifier starts is returned. Having found the identifier, the buffer is split into a left part and a right part. The left and right parts are combined with the text to be replaced, and a new bufferToProcess is created. When no identifiers are found, the buffer is considered expanded. The last remaining step is to convert the buffer into an object instance. Converting the buffer is a problem because executing the return eval( bufferToProcess) command might lead to unpredictable scenarios. To make the conversion predictable, bufferToProcess is concatenated with an assignment to the cls variable. Then when the new buffer is executed using the eval statement, the local variable cls is instantiated, and it can be returned to the caller. The code to expand and implement JavaScript “generics” is relatively simple, but the effects are profound. When using JavaScript “generics,” keep the following points in mind:

• JavaScript references are easier to implement and, in many cases, good enough. However, as pointed out in Recipe 2-14, references do pose a “gotcha” problem.

• You have to make a decision between using references for everything and using eval for everything. “Everything” here doesn’t refer to an entire application, but everything within the scope of a type or function. Don’t mix references with the eval statement; doing so will cause problems.

• Overall, your code is more robust and stable if you use eval-like techniques. References work for simple cases, but if your code embeds code multiple times, then errors could result.

• With references, you run the risk that multiple pieces of code will reference the same code and the same variables. This can cause corruption and should not be underestimated.

• Using eval-like statements makes debugging easier, because if you serialize a function or object, you will get the current state of the code and thus be able to follow what the problem is. If you use references, you will need a debugger, and with code that determines its behavior at runtime, debugging can be tedious.

• Using JavaScript “generics” as described in this recipe is IDE-friendly because you are not creating buffers by hand, and you are not writing code with special tags that IDEs such as X-develop, Visual Studio, Komodo, and Visual SlickEdit do not understand.

legal notice

Our website is not responsible for the information contained by this article. Web-articles is a free articles resource.
Suggestion: If you need fresh, daily updated content for your website, feel free to use our service. Click here for more information.

Useful tools and features

Link to this article from your page    Send this article to you or to a friend
If you like this article (tutorial), please link to it from your web page using the information above.

related articles

1. Testing a Dynamic Contract with Ajax
Coding the Contract Using Test-Driven Development Techniques Coding the contract using agile and test-driven development techniques requires writing a number of tests and implementing aMock URL layer. Problem You want to code the contract using these development techniques. Solution To demonstrate, let’s define a use case, implement the use case as a contract, write a test case(s) to implement the contract, implement the contract in the Mock URL, and finally...

2. Testing the Client Side Logic
Problem You want to effectively test your application’s client-side logic. Theory Testing GUI code tends not to be a productive task because of the complications that arise. The main complication is how to test the correctness of a user interface. Imagine a situation where clicking a button causes a table to be filled with data. Now imagine that when a check box is checked and the button is clicked again, a different table is filled with content. The fact that clicking the same button results in two ...

3. Understanding JavaScript and Types
Understanding JavaScript and Types Problem You want to work around the fact that JavaScript does not have types declared for its variables. Theory JavaScript code does not have any variables with a declared type. The lack of typed variables is apparent when you declare functions. That said, not having typed variable declarations does not mean JavaScript has no types or no type safety. Let’s start out with the simple declaration of a function, as illustrated by the following ex...

4. Coding Using Conventions and Not Configurations
Coding Using Conventions and Not Configurations Problem You want to make your JavaScript constructs more efficient by applying the Rails “convention over configuration” principle to them. Theory You may already be familiar with the programming platform Ruby on Rails, which is used to build Web applications. The focus of this recipe is not Ruby on Rails, but one aspect of Ruby on Rails namely, convention over configuration (see http://en.wikipedia.org/wiki/ Ruby_on_Rails for m...

5. Advantage of parameterless functions in JavaScript
Using Parameterless Functions Problem You want to take advantage of parameterless functions in JavaScript. Theory JavaScript functions for the most part have parameters. You may think that the previous sentence states the obvious after all, without parameters, what data could be passed to a function? JavaScript has the ability to declare functions that have no parameters, even though the caller of the function has passed parameters to the function. For example, let’s look at...

6. JavaScripot Functions
Treating Functions Like Objects Problem You want to take advantage of the fact that functions are objects (remember, everything is an object in JavaScript). Theory Many people think that a function is some keyword used in JavaScript. A function is also an object that can be manipulated. Knowing that a function is an object makes it very interesting from the perspective of writing JavaScript code, because the code can treat the function like another other object. This mean...

7. Implementing an Error and Exception Handling Strategy
Implementing an Error and Exception Handling Strategy Problem You want to implement a clean error and exception handling strategy in your applications, to make them run more smoothly. Theory Of course, you might argue that one error is a dialog box and the other is generated in the JavaScript console. The fact that one browser uses a dialog box to show an error and the other does not is a browser issue, not an error issue. A concise way of classifying the two errors is to ...

8. Understanding the Behavior of Variables When Implementing Recursion
Understanding the Behavior of Variables When Implementing Recursion Problem You want to implement recursion in JavaScript, and you also want to understand how variables will behave under those circumstances. Theory In JavaScript, you do not need to declare the variable type, or even declare the variable. For example, the following code works perfectly: if( counter == 1) { buffer = "counter is 1"; } document.getEle...

9. Using Functions to Initialize and Make Decisions JavaScript
Using Functions to Initialize and Make Decisions Problem You want to use functions to initialize and make decisions. Theory Usually when you write a piece of code where a change of logic needs to take place based on a context, you use a decision structure. For example, say you are implementing a light switch using a program. You turn on the light if the light is off, and you turn off the light if the light is on. The behavior of the program is determined by the conditions. One example behavior t...