A C++ virtual class or a Java interface provides a mechanism to define a contract concept in code. We always speak of the interface as a contract between different components of software; this can provide good separation of concerns. JavaScript has no formal concept of an interface, so how can we do it?
The simplest approach is to define the contract informally and simply rely on the developers at each side of the interface to know what they are doing. Dave Thomas has given this approach the name of "duck typing" —if it walks like a duck and it quacks like a duck, then it is a duck. Similarly with our Shape interface, if it can compute an area and a perimeter, then it is a Shape.
Let's suppose we need to add areas of two shapes, in Java this could be look like:
public double addAreas(Shape s1, Shape s2){
return s1.getArea() + s2.getArea();
}
Java is type strict so the method signature will forbid passing any other objects rather than a Shape, but in JavaScript there is no guarantee :
function addAreas(s1,s2){
return s1.getArea() + s2.getArea();
}
Another way of thinking: JavaScript is highly customizable so lets plugin our interface mechanism in the Object prototype:
Object.prototype.implements=function(funcName){
return this && this[funcName] && this[funcName] instanceof Function;
}
Here we have three check points:
1. there is an Object
2. that has the specified Name ( each JS object is considered as an associative array )
3. and at last it is a function
This allows us to have our interface definition:
function isShape(obj){
return obj.implements("getArea") && bj.implements("getPerimeter");
}
If you notice the java method above there is a single check missing to complete our interface : the return value. With the current interface you can not guarantee that these two methods are returning doubles or double string representations, we can never know this in JS until we invoke the functions.
So we need another check point for the type:
function isNum(arg){
return parseFloat(arg)!=NaN;
}
At this point we have completed our Shape interface, we can rewrite our addAreas() function like this :
function addAreas(s1,s2){
var total=null;
if (isShape(s1) && isShape(s2)){
var a1=s1.getArea();
var a2=s2.getArea();
if (isNum(a1) && isNum(a2)){
total=parseFloat(a1)+parseFloat(a2);
}
}
return total;
}
we have used parseFloat here, so if a1="12" and a2="34" we don't get "1234"
In summary, duck typing keeps things simple but requires you to trust your development team to keep track of all the details. Duck typing is popular among the Ruby community. As one moves from a small team to larger projects involving separate subgroups, you can not rely on this trust, and you may want to add a few checks and balances to your code on top of duck typing.
Thursday, February 28, 2008
JavaScript Interfaces and Duck Typing
Posted by
michaelyta
at
2:56 AM
0
comments
Links to this post
Thursday, February 14, 2008
Compile and run Java code in a Java program
With the new Compiler API introduced in the JDK SE 6 it is possbile to compile Java code in a Java program.
Start by making an instances of Java Compiler and Java File Manager.
JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
DiagnosticCollector
jc.getStandardFileManager(dl, null, null);
After that you make a compilation task for the Java compiler, it is possible to add more then one task to the Java Compiler. The getJavaFileObjects method accepts a variabel amount of parameters, this way you can pass more then one file. Don’t forget to close the Java File Manager when you no longer need it.
File javaCode = new File("c:/java/CompilerTest.java");
Iterable codeObject = sjfm.getJavaFileObjects(javaCode);
jc.getTask(null, sjfm, null, null, null, codeObject).call();
sjfm.close();
When there are no errors in the CompilerTest.java you should have a compiled version generated beside your java file. When you need to have the class file generated some other place you’ll have to add some options to the compilation task.
String[] options = new String[]{"-d", "c:/java/classes"};
jc.getTask(null, sjfm, null, Arrays.asList(options), null, codeObject).call();
After compiling the Java code you can load the class into a running program.
File classesMap = new File("c:/java/classes");
URL[] urls = new URL[]{classesMap.toURL()};
URLClassLoader ucl = new URLClassLoader(urls);
Class clazz = ucl.loadClass("the.package.of.the.class.CompilerTest");
Note: you need JDK 6.0 jars to run the code
Posted by
michaelyta
at
11:49 PM
3
comments
Links to this post