Subscribe via FeedPeter Presnell, Oct 30, 2009 3:17:05 AM
JavaScript is an Object-Oriented programming language. While languages such as LotusScript, Java, and C# use classes, Javascript (including SSJS) uses objects in a form of OOP known as Prototype-based programming. Inheritance is one of the key features of OOP. There are two techniques that can be used to implement Inheritance within JavaScript. These are commonly known as Closure and Prototype. Both techniques construct objects by defining a function and then assigning the function to a variable using the new statement. Where these techniques differ is the process by which Inheritance is implemented to add properties/methods.
Note: At this time properties are not supported in JavaScript and are typically supported by creating a pair of get and set methods.
Closure
With Closure methods are defined inside the parent object.
// Cartesian Coordinates - Closure implementation
function CartesianC(x, y)
{
this.x = x;
this.y = y; }
this.getX = function()
{
return this.x;
}
}
Closures allow a developer to define all the methods up front in much the same way that classes are typically built.
Prototype
In contrast, prototyping adds methods using the special prototype statement to effectively extend the existing object.
// Cartesian Coordinates - Prototype implementation
function CartesianP(x, y)
{
this.x = x;
this.y = y;
}
CartesianP.prototype.getX = function()
{
return this.x;
}
Prototype maximizes the flexibilty of JavaScript making it possible to add additonal methods at any stage.
Closure versus Prototype
Given there are two ways to implement inheritance, which one should we use? Well in client-sided Javascript it is generally held that Prototype is the superior choice. While I have heard some people suggest that prototype is a "hack", it is in fact the default way to implement inheritence and is described in the ECMAScript standard. There has been a lot written on the subject and most people seem to side with Prototype. The reasons include:- the code runs faster; consumes less memory; and the objects are more easily extended.
In contrast there is little written so far on the topic for SSJS. Given the SSJS code is implemented a little differently I decided to do a few tests to compare the performance of the two options. If you visit my Web site at www.dominoframework.com and look under "XPages Kindergarten" you will find an entry for Closure v Prototype (note: There are issues with ie and digit trees so use a decent browser!). Here you can test the code out yourself. The results were somewhat inconclusive.
The bottom line is that there is perhaps no compelling reason to use one over the other. It most likely comes down to personal preference. Despite this, I am presently siding with Prototype within my own xDomino Framework. The key reason being it matches the style of the JavaScript language. The key strength of JavaScript is the flexibility of the language. That is part of the reason I see it as such a good fit for Lotus Notes. Implementing inherence through Prototype magnifies flexibility.
Note: There is at least one compelling reason to use Closures within SSJS. At present the SSJS Editor in DDE does not recognize the prototype statement for what it is and hence the methods it creates do not show up in the outline as methods of the parent object. This makes navigation of SSJS the same nightmare LotusScript was prior to ELSE (EclipseLotuSScript Editor).
18 responses to Prototype versus Closure in SSJS
Nathan T. Freeman, November 1, 2009 7:46 PM
Karsten, not to nitpick, but XULRunner is 1.8.1.3, which is Firefox 2. It's still outrageous, though.
Karsten Lehmann, November 1, 2009 4:15 PM
"If IBM doesn't plan on supporting the full, current language spec, we'll end up with an old, out of date scripting language in Notes."
Well, I hope they will update their JavaScript engine. I also hope they update the Xulrunner engine, because the Xulrunner that is part of Notes 8.5.1 comes from Firefox 1.5. And I hope the base of Symphony will be updated to OpenOffice 3.1.
And finally I also hope that Lotusscript will get all the things that have been added to Visual Basic in the last years. :-)
There must be a *need* (and a business case) for an update. So I hope that everybody will tell IBM that they want all these updates to happen.
Dan Sickles, November 1, 2009 2:08 PM
@Karsten - Javascript support is being added to Eclipse. Java is not being replaced. Remember, E4 is an incubator project. There is no timeline for when specific features will move to Eclipse.
@Peter "can we in fact rely on all the characteristics of prototype and closures found in ECMAScript to be present in SSJS"
You can in every other javascript implemntation. If IBM doesn't plan on supporting the full, current language spec, we'll end up with an old, out of date scripting language in Notes. Imagine that. I expect that IBM will implement Ecmascript edition 5. I also hope they implement the optional E4X, which is very useful on the server. The question is will they, and.when. I asked these questions in the lab at LS the last few years and the standard answer was "We'd love to do that. Maybe in a future release."
Karsten Lehmann, November 1, 2009 6:57 AM
@Nathan: There is another preferred programming language for Bindings that I forgot in my list and that is especially important for Lotus Notes developers? Hmm... ;-)
@Dan: Will the whole Eclipse platform be ported from Java to JavaScript or is it just an easier way for users to quickly add functionality, e.g. for a toolbar button or another simple function? I see the advantages of JavaScript for small code snippets like the bindings of XPages, but it makes me shiver when I think of a whole complex system written in JavaScript... ;-)
But anyway, a matter of taste. I guess when they started with Lotus Notes, they also didn't expect that someone would write a CRM suite on that platform. Even today, you have many things in the platform that make you think "This wasn't really intended to be used that way" :-)
Like all that Notes.ini and profile document hacks to simply pass parameters from A to B.
@Peter, regarding your question "And can we in fact rely on all the characteristics of prototype and closures found in ECMAScript to be present in SSJS":
I think the answer is no. They already added @formula support, which is not a JavaScript standard. And regarding the JSF basis of XPages: They also removed (or don't support) core JSF functionality. It's a new product and we can only leverage what's they let through and request what they haven't included yet.
Dan Sickles, November 1, 2009 5:59 AM
XPages supports Ecmascript 3 which is equivalent to Javascript 1.3 which was released in 1999 plus a few extensions like type annotations and @identifier naming (hack). Javascript is currently at 1.8. That's the version in Firefox. Rhino is at 1.7. The next version of Ecmascript will be Edition 5 (there is no 4) which should be approved as a spec before year end. It will include some, but not most, of the extensions in Javascript 1.4 - 1.8. You can back up through the versions here
And not to harp on it again but, that's why SSJS has no meaning other than running on the server. The extensions in Rhino and Spidermonkey are javascript languages extensions, they have nothing to do with server side, client side or any other side. The differences between running on client or server or embedded in an application, is in the host objects exposed to the javascript engine and these will be different for every server side application also.
Nathan T. Freeman, November 1, 2009 4:06 AM
"The stuff I'm working on uses Rhino features that are not available in XPJS but I'll post some code soon anyway (do I still have a blog?...where's that darn blog)"
This sounds very intriguing, as it suggests that there are extensions to SSJS that are not currently visible to xpages developers.
Dan Sickles, November 1, 2009 3:26 AM
There were several other scripting languages for the JVM that use class based OO and could have been used for XPages. Jython comes to mind. I don't think Groovy was available when XPJS was created. Jython is used as the scripting language for Websphere.
The only reasons I can think of for selecting Javascript are that so many developers know it, except that they dpn't really, and you have the possibility of 'run on client/server'. Other than that, Jython would have avoided the class-prototype mismatch. An improved Lotusscript ported to the JVM would have been the smoothest path, but even with improved OO features, it still would have been hobbled by non-existent or poor metprogramming features (IMHO).
@Karsten - The Eclipse E4 project has scripting language support as one of it's key goals. Javascript via Rhino will be the reference implementation. Writing plugins and RCP apps in Javascript and other languages will eventually be suuported in the Eclipse release train, then hopefully Expeditor.
@Peter didn't mean to crap up your post. I expect that Tim will post examples that will become "the way to do it" in XPJS. I would only suggest that you not consider prototypes and closures to be exclusive. There's some cool functional stuff to be done in Javascript too, closures being one example. The stuff I'm working on uses Rhino features that are not available in XPJS but I'll post some code soon anyway (do I still have a blog?...where's that darn blog)
Nathan T. Freeman, November 1, 2009 2:20 AM
"You should be able to call a method like setValueBinding or setMethodBinding for a field or a button control to set a different binding, something like a CobolMethodBinding or LispValueBinding. :-)"
Yes, theoretically, this should be the case. I wonder if there's an ideal language for Lotus developers? Hrmmmm....
"You should be able to call a method like setValueBinding or setMethodBinding for a field or a button control to set a different binding, something like a CobolMethodBinding or LispValueBinding. :-)"
I agree. Tim and I have discussed inheritance and polymorphism in closures on multiple occasions. He's done some extraordinary work in that area. As he says, hopefully the results will be made public soon.
Peter Presnell, October 31, 2009 9:53 PM
The discussion is great but a lot of it is over my head. Would someone be able to bring it back to terms a first grader such as I can understand. In particular, given the way IBM have implemented SSJS does it imply any natural advantage for one technique over another?. And can we in fact rely on all the characteristics of prototype and closures found in ECMAScript to be present in SSJS. Especially some of the more sophisticated applications of closures not covered in this article. I am told you cannot mix the two techniques so you very much need to chose your poison and live with it.
@Nathan. I agree in many cases the prototype code is somewhat clumsy and an absolute pain to maintain in the current DDE editor but I have also seen some of the more advanced implementations of Inheritance for closures and they can get decidedly ugly too. I know there are plans to extend JavaScript as a language but being an OpenSource language it seems these plans drag on for years and usually end up with a less than adequate compromise being implemented. And who knows what/when IBM will follow with in SSJS.
Karsten Lehmann, October 31, 2009 9:33 PM
I second the idea of writing a managed bean, but I guess that's not a real secret :-)
I'm really wondering how anyone can produce a large and maintainable project only with JavaScript code. Ok, the Closures improve the situation a bit compared to Prototypes. And also the JavaScript implementation of the XPages engine seems to require a variable declaration with VAR and throws an exception if it is missing. But I'm still missing a usable editor (with comparable type ahead support like the Java editor) and my biggest problem with the JavaScript language is that I cannot really use the code in other none-XPages projects like Eclipse RCP applications, Swing applications or even a legacy Java agent. Technologies come and go, so for easy portability I would prefer at least a programming language that not only works in one special environment.
BTW: The XPages engine does support different types of ValueBindings and MethodBindings internally. There is support for simple Bindings like #{sessionScope.variableABC} and also for complex JavaScript expressions. All the framework does is to ask the binding class to produce a value. Then it depends on the concrete binding class implementation what it does next - parse an Expression Language construct or use the JavaScript engine (should be Rhino) to parse the JavaScript code.
From a technical point of view, it should be possible to add other bindings, too. But I haven't tried it yet, because I don't have a real use case and you currently don't have a good XPages editor support.
You should be able to call a method like setValueBinding or setMethodBinding for a field or a button control to set a different binding, something like a CobolMethodBinding or LispValueBinding. :-)
Nathan T. Freeman, October 31, 2009 7:24 PM
@Jeremy, yeah, I suppose I should couch what I said in this: if you're working on something complex enough that you need to care about the performance difference between Closures and Prototypes in SSJS, you really should be writing a managed bean instead. Real Java code is going to beat either JS implementation hands-down, especially if you know how to properly scope your bean.
Nathan T. Freeman, October 31, 2009 7:18 PM
lol. The HTML filter cleaned out the JS source code in my block. The second parameter to the .createMethodBinding call should be "javascript:" followed by...
var viewRepeater = getComponent(compositeData.viewRepeatControlId);\n\nSorter.setSortColumn(thisHeaderColIndex.toString(), true);\nvar returnSet = Sorter.getOptimizedData();\n\nviewRepeater.setValue(returnSet);\n\ngetComponent(\"viewPager\").gotoFirst();\ncontext.reloadPage();\n}
We'll see if this comment makes it through successfully.
Nathan T. Freeman, October 31, 2009 7:16 PM
@Dan, I'm interested to know the source of your information on the compile technique used for "XPJS" (which I guess is your name for SSJS?) The actual .java that's generated from the XSP source creates com.ibm.xsp.compiled.AbstractCompiledPage objects with methods like:
private UIComponent createEventHandler(FacesContext context,
UIComponent parent, PageExpressionEvaluator evaluator) {
XspEventHandler result = new XspEventHandler();
String sourceId = "sortLink/xp:eventHandler[1]/xp:this.action[1]/text()";
MethodBinding action = evaluator.createMethodBinding(result,
"#{ \n}",
null,null, sourceId);
result.setAction(action);
result.setSubmit(true);
result.setEvent("onclick");
result.setRefreshMode("complete");
return result;
}
I honestly have no idea how the PageExpressionHandler processes a createMethodBinding call with Server-side Javascript in it. Do you have some documentation on how that package works?
Thanks.
Jeremy Hodge, October 31, 2009 6:39 PM
@Dan, actually, the xPage is compiled to java source code, before it is compiled to bytecode. If you open an xPage, Open the java perspective, make a change to the xPage, turn of "Build Automatically", save and then choose "build project", you can actually see the Java Source code that is created. However it looks like SSJS is actually stored as a string, and passed to an evaluator at run-time to actually execute. So the speed difference would be how the interpreter evaluates prototype vs closure.
HOWEVER, for SSJS i doubt there is little practical difference in performance between the two, especially when it comes in relation to your code that actually does the work. If you are looking for performance improvements, there are many other places to increase xPage performance. At this stage of the game, I don't believe anybody is writing any dojo or Ext size SSJS libraries where the amount of prototypes and/or the use of closures will affect performance.
Nathan has hit the nail on the head in this case. maintainability and code readability is king here, and for that, closure wins hands down.
Dan Sickles, October 31, 2009 4:48 PM
@Nathan The code is converted to Java bytecode, not Java source code and it's not the same bytecode that javac would generate. By definition, a dynamically typed language implementation will generate a lot more bytecode and will run slower than similar Java code. That's the price to be paid for the flexibility of dynamic typing. The type annotations in XPJS (most other JS implementations don't have them) are not used when generating bytecode. They do not override Javascript's dynamic typing. If they did, it wouldn't be javascript. The type annotations help to identify type errors at development time at the cost of some verbosity but like Java generics, there's no runtime benefit.
Closures are straight out of functional programming and can be used in addition to standard OO constructs in some languages. Closures were proposed for Java 7 but didn't make it in due to lack of consensus around any one of the three proposals. Many other popular languages support closures and class-based OO (python, ruby, Scala, C#...).
The goal of the getters/setters proposal for Ecmascript is to accomplish data and implementation hiding, like in Tim's example, but in an idiomatic way. Property access would be obj.property, not obj.getProperty().
Peter Presnell, October 31, 2009 4:33 PM
I have here a envelope here with the names of two people I considered most likely to read and/or comment on this article. The envelope was sealed before the articles was published. So lets see what those two names were....
Oh look it was Mr NTF (Nathan Freeman) and Tim Tripconny! Thx for all the feedback guys. I thing it is a great discussion as sooner or later all us LotusScript developers need to figure out smart ways to write our SSJS to underpin Xpage projects. As Xpage projects get bigger and bigger the maintainability of the underlying code will become more of an issue. This seems to be one of the key areas.
Tim Tripcony, October 31, 2009 12:44 PM
I'm not sure I'd classify closure as an inheritance technique; strictly speaking, it's just a way of binding variables to functions that would otherwise not have access to them. Specifically, many JavaScript developers now use closure to provide private members to public objects.
Here's an alternate version of your CartesianP function that illustrates how this works:
function CartesianP(x,y){
var xModCount = 0;
var yModCount = 1;
return {
getModCounts: function(){
return {x: xModCount, y: yModCount};
},
getX: function(){
return x;
},
getY: function(){
return y;
},
setX: function(newX){
x = newX;
xModCount++;
}
setY: function(newY){
y = newY;
yModCount++;
}
};
}
This version of the function returns an object that has public methods (getModCounts, getX, getY, setX, setY) which have access to private variables (x, xModCount, y, yModCount). Because JavaScript uses function scope for its variables, those 4 variables are bound by closure to any object returned from the function... the object's methods can access and modify them, but they're private in the sense that nothing outside of that function can change their value.
Using this convention, it doesn't matter whether you use the "new" keyword or not when constructing objects:
var plane1 = new CartesianP(1,2); // returns an object where x initially = 1, y = 2
var plane2 = CartesianP(3,4); // returns an object where x initially = 3, y = 4
Whether or not you use "new", the function creates a new object, binds it by closure to the private variables (including the containing function's arguments), and returns that object.
In short, closures are very powerful, but aren't specifically intended to provide object inheritance... if time permits, I'll blog later today about how inheritance can be achieved without using prototype.
Nathan T. Freeman, October 31, 2009 12:02 PM
There's no performance difference because they are both converted to Java source code anyway. My strong preference for Closures comes their substantial improvements in readability. Like a CLASS block, you can identify where the code for a particular object type begins and ends easily. With the .prototype() approach, class methods can be added or overloaded from anywhere, and where you put the code can ultimately affect the behavior of the object.
Closures improve maintainability of your code in the future.