This is continuation of my earlier post titled "Java, JavaScript and Jython".
| Feature | Java | JavaScript | Jython |
|---|---|---|---|
| Regular Expression Literals | Not supported. Regular Expressions are specified as Strings (to String class methods and java.util.regex.Pattern class methods) |
Regular expression objects may also be created using the
RegExp
constructor. See also Regular Expressions
|
You can use Python raw strings
to specify regular expressions. In "raw mode", backlash
characters are just left (i.e., the usual
"C" escape sequences such as \", \n, \t in strings are not
interpreted). This helps in specifying regular expressions.
re
module provides regular expression matching operations.
|
| enum | Java enum guide |
Not supported - although enum is a reserved word (almost
all Java keywords are!). It is possible to simulate enums
with an an object literal will "constant" properties:
|
Not supported. But, you can do something like Enums for Python |
| Default arguments | Not supported (intentionally!) |
Not directly supported. But, caller
can pass lesser number of arguments.
Callee function can check "undefined"
params
|
|
| Nested, inner and anonymous classes |
|
Everything in JavaScript is object (well, nearly!) - including functions. It is eary to add more "slots" to functions. If we add function valued slot to a constructor function, we will have "nested class". Similarly, we can simulate inner classes as well.
The trick is to use closures! - refer to new point.
|
For inner classes refer to:
Implementing Java inner classes using descriptors
|
| Closures |
* Not yet part of Java. But, may become! * Nominal Closures for Java (version 0.2) * Full Disclosure * For now, use local and anonymous classes
|
JavaScript nested functions are closures.
|
Python functions can be nested and nested function
can refer to the locals of nesting function.
from __future__ import nested_scopes is required with Jython 2.1 (to allow access of "x" from "addWith" in the nested function "f" It is also possible to use lambda's
Lambda forms can be used wherever functions are
required. Lambda's body is restricted to a single
expression.
|
| instance of check |
|
|
Use isinstance function.
|
| Accessing Class object | obj.getClass(); | typeof(expression) returns a descriptive string |
|
| Throwing Exception | throw exception; | Same as Java - except that anything including number, string etc. can be thrown. |
The first argument to raise names the exception.
The optional second argument specifies the exception's
argument.
|
| Printing Stack Trace | Thread.dumpStack(); |
Rhino specific solution:
See also More JavaScript debugging tips (Mustang context)
|
See also traceback -- Print or retrieve a stack traceback
|
| Is everything an object? |
No, there are primitive types and reference types.
But, with auto boxing/unboxing,
you can use primitives with ease
|
No, there are "number", "string" etc. that are not objects. There are also primitive wrapping constructors such as Number, String etc. [similar to Java's primitive wrapper classes] | Yes |
| Extending a specific object | Not supported. You may think of singleton instance of an anonymous class. But, that does not allow you to extend a pre-existing instance. |
It is very easy to extend any JavaScript object
after construction. Just add new attribute -- that
could be a primitive value or an object or
even a function (method).
|
Essentially, add a closure valued property to the
object in question. See also: Replacing methods without subclassing
|
| Constructing object using reflection |
|
Objects are created using constructor functions.
Functions are first class values. So, it is easy
to construct objects using apply
or call
|
Classes are functions too. Just call..
|
| Calling a method using reflection |
|
Functions are first class values. So, it is easy
to call indirectly using apply
or call
|
|
| Handling "missing method" | This can not happen in Java! That's the point of static type checking. Either you have to use reflection or change classes incompatibly behind javac's back to get this error. In such cases, you have to catch NoSuchMethodException or NoSuchMethodError. | Use JSAdapter to "trap" access and setting of all attributes (fields or methods). See also doesNotUnderstand in JavaScript |
|
When I wrote Java, Groovy and (J)Ruby, Owen Densmore and Lawrence Oluyede suggested that I should include Jython as well. Here it is.... JavaScript and Jython for Java programmers. Note that while I am reasonably comfortable with Java and JavaScript, I don't know much about Jython. If you find anything wrong here, please let me know. I used Jython version 2.1. For JavaScript, I used Rhino 1.6R2 that is co-bundled with JDK 6. The jsr-223 script engine for Jython and many other languages are avaiable at http://scripting.dev.java.net
| Feature | Java | JavaScript | Jython |
|---|---|---|---|
| Type System | Static with few dynamic checks inserted as needed. | Dynamic | Dynamic | Comments |
|
|
No multiple line comments. But, Owen Densmore notes that multiline
string literals may be used instead.
|
| Control Statements |
* break can be used in
loops to break out of loop. * continue statement skips the current iteration of a for, while, or do-while loop and valuates the boolean expression that controls the loop. * Labeled break and continue |
* null is treated as false. * undefined is treated as false. * Unlike Java, switch statement works for arbitrary expressions (not just for integral expressions and enums as in Java). * break can be used in loops to break out of loop. * continue statement skips the current iteration of a for, while, or do-while loop and valuates the boolean expression that controls the loop. * Labeled break and continue as in Java are supported. |
* for statement iterates over the items of any
sequence (a list or a string)* Note that statement grouping is done by indentation. No explicit "{" "}" around group of statements. * The break statement, like in Java, breaks out of the smallest enclosing for or while loop. * The continue statement, like in Java, continues with the next iteration. * do..while is not supported. * Loop statements may have an else clause which is executed when the loop terminates normally (i.e., not when "break")
|
| String Literals | "hello world" |
* Need not escape " within single-quoted string* Need not escape ' within double-quoted string |
* Need not escape " within single-quoted string* Need not escape ' within double-quoted string * Thanks to Owen Densmore for the info. about multi-line string literals |
| Defining functions | Not supported. Everything has to be inside a class. Use static methods instead. |
* functions may be unnamed (anonymous functions)* functions are first-class values - can be passed, assigned and returned as values. * functions may be nested inside other functions * nested function can refer to local variables of the enclosing functions
|
* functions are first-class values - can be passed,
assigned and returned as values.* functions may be nested inside other functions * nested function can refer to local variables of the enclosing functions [closures] * functions may be unnamed (anonymous functions called "lambdas") * lambdas are restricted -- the body of lambdas can only be expressions. lambda definition does not include a "return" statement -- it always contains an expression which is returned
Without the "from __future__ import nested_scopes",
nested scopes don't work as "expected" normally.
This behaviour depends on Python version - refer to
What's New in Python 2.1 by A.M. Kuchling and
Back to the __future__
|
| Class Declaration |
|
JavaScript supports prototype-based object orientation. No direct support for classes. JavaScript supports first -class functions. Any function can serve as object constructor. An object is an associative array - with keys being either string or integer. The values could be strings, numbers, object or even function (which then becomes a "method" of the object).
There is
JavaScript framework called "Prototype" that supports class
based object orientation with JavaScript.
|
Classes can have executable statements (like print call in
above example).
|
| Instance Variables |
|
No need to declare instance variables. No special
syntax for instance variable names. Just introduce
instance variable by
Typically, constructor functions initialize instance
variables. All fields are "public". If you want private instance
variables and methods, you may want to
read Private Members in JavaScript
|
No need to declare instance variables. No special
syntax for instance variable names.
|
| Static Variables |
|
There are no classes in JavaScript. But, every object
has a prototype -- identified by a special property (or field)
called __proto__. The prototype
property is set when the object is created and this property
can be changed later if needed. The "static" fields can be
stored in the prototype object.
You may want to read Private Static Members in Javascript
as well.
|
Class variables are declared
within the "class".
Note: Unlike Java, all variables declared inside class
declaration are class variables. Instance variables are
initialized only within the instance methods.
|
| Global Variables | Not supported. Use public static final variables in a class or use enum as appropriate. | Top-level variables are supported. No special naming enforced. No need to declare and can be "defined" by initialization. Actually, the "globals" are contained in "Global" object - which contains all "global" definitions - variables and (global) functions. "this" in glabal scope refers to Global object. | Top-level variables are supported. No special syntax for global variable names. |
| Method Definition |
|
To define an instance method:
add a function valued property
to prototype [of the constructor
function]
|
Note: Unlike Java and JavaScript, you have
to specify special "self" parameter explicitly.
|
| Static Method Definition |
|
There are no classes in JavaScript. But, every object has a prototype -- identified by a special property (or field) called __proto__. You may want to read Private Static Members in Javascript for variety of way to code static members. | You may want to read The Static Method Thing |
| Returning from a method |
|
|
|
| Object Creation |
|
|
Use class name like as a function name.
|
| Method Call |
|
|
|
| Referring to the current object | this | this | self |
| Object Initialization |
|
Objects are created by constructor functions!
|
|
| Extending another class |
|
Every JavaScript has a prototype. This can be accessed via __proto__ field. When a property is not found in an object, it's prototype is searched. If not, prototype of the prototype is searched and so on - till prototype chain ends with an object with null __proto__. You can have Classical Inheritance in JavaScript or use JavaScript "Prototype" framework. |
* Jython supports multiple inheritance. User specifies
zero or more superclasses within the parans just after
the class name.
|
| Null | null | null | None |
| Arrays |
|
|
|
| Array Literals |
|
|
|
| Array length | arr.length |
|
len(arr) |
| Hash Literals | Not supported |
Use JavaScript Object Literals. Objects
are associative arrays.
|
|
| varargs methods |
Use JDK 1.5+. The "..." after the last formal
argument means this is a vararg method.
|
JavaScript functions can accept any number of
arguments. "arguments" object is filled with all
arguments.
|
The "excess" args are packed as tuple and passed.
|
| Keyword arguments (a.k.a Named Parameters | Not supported |
Not supported. You can accept Object but pass Object
literals from caller.
|
Functions can be called with keyword arguments of
the form "keyword = value"
|
| Operator Overloading | Not supported - except for built-in String + operator | Not supported - except for built-in String + operator |
Specially named operator methods are
defined by class author.
|
| Referring to super class method | super.foo(); | JavaScript supports prototypes for objects. It is possible to get any method anywhere in the prototype chain (for example: obj.__proto__.__proto__.func where "func" is a function valued property defined in the prototype of prototype of obj) and then explicitly apply that on "this" object. |
|
| Exception Handling |
|
Exception handling is similar as Java - except that
anything (including string, number) can be thrown.
Also, catch clause cannot specify "exception type".
But as lopex comments, there may be
multiple catch clauses (which seems to be an extension of the ECMAScript-262 standard).
Thanks to lopex for notifying the multiple catch clauses.
|
Thanks to Lawrence Oluyede for clarifying the "else:"
usage. So "else:" clause code is executed only
if exception was not thrown in try block. There is also
finally: clause -- similar
to finally in Java. See Lawrence Oluyede's comment in
this entry for CPython/Jython version specific behaviour.
Also, you may want to refer to Errors and Exceptions section of the Python tutorial as well.
|
| Modules, Namespaces |
There may be
future
improvements in this area.
|
No explicit support for modules/packages. Use objects for everything. For example, you may use this idea. Or similar to the package system of Dojo. Similarly, Phobos webapp framework has it's own namespace support for JavaScript. |
A Python module is a file containing Python definitions and statements. The file name is the module name with the suffix .py appended. Within a module, the module's name is available as the value of the global variable __name__.
Refer Modules section
of Python tutorial.
|
Read this very nice "Ruby Metaprogramming techniques". Also, few days back I wrote on Ruby Metaclasses. You may also want to check out "The Ruby singleton class"
You may have read the latest closure proposal for Java (Nominal Closures for Java (version 0.2)).
A simple example given in Neal Gafter's page is as follows:
interface IntFunction {
int invoke(int i);
}
IntFunction plus2 = (int x){ x+2 };
Essentially, closures types exists transiently only at compile time - closure types are converted at object types at compile time. [Note: I wonder why user has to repeat the types of closure parameters - why not allow (x) { x + 2 }; and infer the "x"'s type to be int from the IntFunction.invoke's signature. In fact, it seems that the return type of closure is inferred rather than specified. Am I missing something??]
Groovy supports closures. Also, it supports method closures.
class Person {
def name
Person(name) {
this.name = name
}
def greet() {
println "Hello, I'm ${name}"
}
}
p = new Person("Sundar")
// The ".&" operator converts a method as Closure
greet = p.&greet
// the following prints true
println(greet instanceof Closure)
// call the method closure
greet()
For Groovy, there are these is an RFE to allow conversion from closure to interface. For now, user can use the following with Groovy JSR-223 engine.
import java.awt.*;
import java.awt.event.*;
class Person {
def name
Person(name) {
this.name = name
}
def greet(ActionEvent evt) {
println "Hello, I'm ${name}"
}
}
p = new Person("Sundar");
// just assign method closure to
// a global variable - the name of
// the variable matches interface
// method we want to implement
actionPerformed = p.&greet;
f = new Frame("hello")
b = new Button("greet")
f.add(b, "Center")
// Note: "engine" is a variable of type javax.script.ScriptEngine
b.addActionListener(engine.getInterface(ActionListener));
f.setVisible(true);
You might think that I could perhaps implement ActionListener directly
by Person class. But, the assumption is that Person class could be from
a third party library which you can't (or don't want to) modify. And you
want to avoid writing wrappers. That is when method closures along with
interface conversion can help.
Method closures could be added to Java as well (see also: better closures)
interface IntFunction {
int invoke(int i);
}
Person p = new Person();
// closure conversion of a method closure
IntFunction func = p.&greet;
Disclaimer: The following is my understanding (possibly misunderstanding!) of Ruby and Smalltalk metaclasses. I am a Java programmer. I've played a bit with Squeak and Strongtalk. As I said in my earlier posts, I am learning Ruby using the JRuby 0.9.0 implementation. If you are Rubyist or Smalltalker (or both!) and find gross errors here, please let me know [how do we call a Java programmer?]
With class based object-oriented programming languages:
Point number (1) implies every class is an object too. If so, per point (2) every class has to be an instance of ... well another class [called "metaclass"]. So, what is a metaclass of a metaclass? And how do we end this seamingly "infinite" chain?
Java's answer for this:
class Person {
static {
System.out.println("I'm " + Person.class);
}
}
class Person
end
# prints true
puts(Person.instance_of?(Class))
Huh! That looks pretty similar to Java, isn't it? (except for the syntax changes and the metaclass name). No, that is not the complete story. Look at the following Ruby code.
class Person
# "static" method?
def Person.greet
sayHello
end
# another "static" method?
def Person.sayHello
puts "Person: hello, world"
end
end
class Employee < Person
# "Override" "static" method?
def Employee.sayHello
puts "Employee: hello, world"
# calling "super" method?
super
end
end
Employee.greet
If you run above program, you get
Employee: hello, world Person: hello, world
In Java, the static methods don't have "this" object and can't access "super" either. The "static" methods of Java are not really connected to any object in the system -- static "methods" are just like good old global functions except for namespace and accessibility.
Clearly, "static" methods in Ruby are not like static methods of Java. Class methods [as these are known in Ruby and Smalltalk world] are very much like instance methods - can be overriden, can call super method and have "self". "self" inside a class method is - guess what - the class itself (recall that classes are objects!). In fact, "self" used anywhere inside class body (except inside an instance method) refers to the class. For example:
class Person
puts self
end
So, you can write "class methods" with the syntax as well:
class Person
# "self" here refers to "Person"
def self.greet
sayHello
end
def self.sayHello
# "self" here refers to "Person"
puts "hello, world ${self}"
end
# instance method
def whoAraYou
# "self" here refers to the Person
# object on which "func" was called
puts "I'm ${self}"
end
end
# call a class method
Person.greet
# call an instance method
p = Person.new
p.whoAreYou
I mentioned class holds instance methods, if so which class would hold class methods of a class? For example, Person "holds" the instance methods such as "whoAreYou" Which class would hold the class methods (such as "greet") of Person class? Is it Person.class? - no, that can not be. Recall that Person.class is Class - which can only "hold" methods common to all classes (like general reflective queries such "superclass", "instance_methods" etc.). The Class class can't hold class methods of the Person class. If Class class had the class methods of, say Person class, then you could call that on any class. For example, you can call "greet" class method of Person class on any other class in the system!
Ruby's answer for this is as follows: in Ruby, every object has an optional singleton class [also known as exclusive class]. Whenever a method is called on an object, first the associated singleton class, if available, is looked up for the method. If not found, only then the "actual" class of the object is searched [and then the usual superclass chain search]. How would you add singleton methods to a specific object - in other words how would you define singleton class for an object? When we defined class methods like Person.greet, you are actually adding a singleton method to Person's singleton class. In fact, you can define singleton class with the following syntax - so that you can add multiple singleton methods in "one shot":
class Person
# "self" here refers to "Person"
# add singleton methods.
class <<self
def greet
sayHello
end
def sayHello
puts "hello, world"
end
end
end
For every Ruby class, there is a singleton class associated with it. The singleton class holds the "class methods" of that Ruby class. For Person class, there is Person singleton class. For Employee (which is a subclass Person), there is Employee singleton class and so on. Also, Employee's singleton class is subclass of Person's singleton class [singleton class mirrors regular class hierarchy]
Note that every Ruby object can have an optional singleton class. Yes, that is right -- every object, not just class objects can have a singleton class associated with it.
class Person
end
x = Person.new
y = Person.new
# now, add singleton class to "y" object
class <<y
def wonder
puts "I'm wondering!"
end
end
# calls wonder method in "y"'s singleton class
y.wonder
# won't work - method_missing error!
x.wonder
The singleton classes alongwith clone method can be used to write prototype based object-oriented programs (as with Self). i.e., you don't need classes at all. You just create objects (say using Object.new) and you specialize some of your objects by defining singleton classes for those (note that singleton classes are unnamed). Whenever similar behaving objects are needed [you need a class of objects], then clone one or more prototypical objects!
To understand Ruby class, singleton class relationship, the following session with JRuby could help:
Update: - the output of the following script with JRuby 0.9.0 is different from Ruby 1.8.4. It seems that Ruby hides singleton classes as an implementation detail. I've filed a bug with JRuby ancestors() on a singleton class returns result different from Ruby 1.8.4
# add a method called "singleton"
# to Object class
class Object
# return singleton class associated
# with the current object
def singleton
# create a singleton class for "self"
class <<self
# note that class is expression
# in Ruby, we just return "self"
# Note: "self" here is the singleton
# class itself
self
end
end
end
class Person
end
class Employee < Person
end
class Manager < Employee
end
puts "Manager's singleton = #{Manager.singleton}"
puts "Employee's singleton = #{Employee.singleton}"
puts "Person's singleton = #{Person.singleton}"
def print_hierarchy(klass)
puts "#{klass}'s hierarchy"
puts "\t" + klass.ancestors.join("\n\t")
end
# print class hierarchy of each class
print_hierarchy(Manager)
print_hierarchy(Employee)
print_hierarchy(Person)
# print class hierarchy of each singleton class
print_hierarchy(Manager.singleton)
print_hierarchy(Employee.singleton)
print_hierarchy(Person.singleton)
From the output of above program, we can see that singleton hierarchy parallels the class hierarchy.
More info on Ruby metaclasses:What is the answer of Smalltalk to the class-of-class question? In Smalltalk,
Person
|
Employee
|
Manager
PersonMetaclass
|
EmployeeMetaclass
|
ManagerMetaclass
Ruby's treatment is similar yet different from that of Smalltalk. Ruby's singleton classes serve like Smalltalk's metaclasses. But, unlike Smalltalk metaclasses which have single instances, we can't create instances of Ruby singleton classes:
jruby>Object.singleton.new
script error: org.jruby.exceptions.RaiseException: can't create instance of virt
ual class
jruby>o = Object.new
#<Object:0x16c9867>
jruby> o.singleton.new
script error: org.jruby.exceptions.RaiseException: can't create instance of virt
ual class
Hence it has been suggested that singleton classes be referred to as "sterile metaclasses" It is important to note that Ruby's singleton classes can be associated with any (ordinary) object (unlike Smalltalk). Because of this, Ruby supports prototype based object orientation.
This is continuation of my earlier post.
What this is not?
Also, commenters need to post something
| Feature | Java | Groovy | JRuby |
|---|---|---|---|
| Default argument | Not supported (intentionally!) |
|
|
| Type for floating point literals [Thanks to Scott Hickey] | double | java.math.BigDecimal | Float class (representation is Java double) |
| enum | Java enum guide | Not supported (yet?) |
Not supported. See also: * Add enum to Ruby * Ruby idiom for enum? |
| Is everything an object? |
No, there are primitive types and reference types.
But, with auto boxing/unboxing,
you can use primitives with ease
|
Yes
null seems like an object (you can call methods on it).
but (null instanceof Object) is false!
|
Yes
nil is an object. (nil.kind_of? Object) is true.
|
| instance of check |
|
Same as Java. In addition, you could compare
MetaClass
as well (which is dynamic and be changed).
|
|
| Class Literals |
|
Same as Java. |
Java Trap: just use ClassName for class literal of ClassName. All the built-in and user classes have a corresponding global constant with the same name as the class.
If you say,
|
| Throwing Exception | throw exception; | Same as Java - except the throwing method need not have throws clause - even for checked exceptions. | raise exception |
| Printing Stack Trace | Thread.dumpStack(); | Same as Java. |
caller.join("\n");
|
| Handling "missing method" | This can not happen in Java! That's the point of static type checking. Either you have to use reflection or change classes incompatibly behind javac's back to get this error. In such cases, you have to catch NoSuchMethodException or NoSuchMethodError. |
Note: There are also more powerful ways to
intercept method dispatching with
MetaClasses in Groovy.
|
|
| Open Classes | Static typing is incompatible with this! |
Not directly supported. But, I think you can play with use and/or MetaClasses to simulate it. Using Categories
Note that the above works only within the
|
See also:* Another example: here * The Open Class Mindset * Are Ruby's Open Classes a Poor Fit for Large Projects? |
| Extending a specific object | Not supported. You may think of singleton instance of an anonymous class. But, that does not allow you to extend a pre-existing instance. |
Changing MetaClass
Using Expando
|
|
So, you want to learn few scripting and dynamically typed language(s) for the Java platform? The following will get a Java programmer started with Groovy and (J)Ruby. It is said that you can write Fortran in any language! While you still have to learn language specific idioms, naming, coding conventions/styles etc., the table below would help you with "quick start". To reiterate: you need to pick up language specific idioms as Reg Braithwaite notes in his comment below.
I wrote simple script samples and tried the same with command line
wrappers of jrunscript. If
you CVS checked out script engines from
scripting.dev.java.net, these scripts are in
bin directories of respective script
engine directories. I used Groovy 1.0 JSR 06 and JRuby 0.9.0 versions respectively.
| Feature | Java | Groovy | JRuby |
|---|---|---|---|
| Type System | Static with few dynamic checks inserted as needed. | Dynamic, optional static types | Dynamic | Comments |
|
|
|
| Control Statements |
* break can be used in
loops to break out of loop. * continue statement skips the current iteration of a for, while, or do-while loop and valuates the boolean expression that controls the loop. |
* do.. while
is not supported. * for (init; condition; increment) is not supported. * null is treated as false. Truth value special cases for data structures. * Unlike Java, switch statement works for arbitrary expressions (not just for integral expressions and enums as in Java). isCase method is used on objects. * Labeled break and continue are not supported (yet?) |
* nil is treated as false. C/C++ Trap: 0 is true!
* break terminates loop immediately. * redo immediately repeats w/o rerunning the condition. * next starts the next iteration through the loop. * retry restarts the loop, rerunning the condition. |
| String Literals | "hello world" |
|
|
| Class Declaration |
|
|
|
| Instance Variables |
|
Same as Java or you can omit types.
Think "def" means java.lang.Object!
John Wilson notes that 'def' is really untyped. If I declare a variable as being of type Object it is not 100% the same as 'def'ing it. Please refer to his comments below.
|
instance variable names start with '@'
|
| Static Variables |
|
Same as Java or you can omit types.
Think "def" means java.lang.Object!
John Wilson notes that 'def' is really untyped. If I declare a variable as being of type Object it is not 100% the same as 'def'ing it. Please refer to his comments below.
static def i; static def f; static def d; static def s; static k; |
Static variable names start with '@@'
|
| Global Variables | Not supported. Use public static final variables in a class or use enum as appropriate. | Top-level variables are supported. No special naming enforced. [Actually, these are contained in "Script" class - which contains all "global" definitions] |
Has to start with "$"
|
| Method Definition |
|
|
|
| Static Method Definition |
|
|
use className.methodName as method name.
|
| Returning from a method |
|
Same as Java. But can leave the return statement - in that case the last expression evaluated is returned. | Same as Java. But can leave the return statement - in that case the last expression evaluated is returned. |
| Object Creation |
|
|
'new' is a method in Ruby!
|
| Method Call |
|
can omit parans in some cases
* If no arguments, need to use parans* Parans can be omitted only for method calls in top-level statements Example:
|
can omit parans in some cases
|
| Static Method Call |
|
* If no arguments, need to use parans* Parans can be omitted only for method calls in top-level statements Example:
|
|
| Object Initialization |
|
|
|
| Referring to the current object | this | this | self |
| Null | null |
null - Guillaume Laforge notes that "Null Object Pattern" is supported in Groovy. See also: NullObject.
So, you can call null.toString() for example.
|
nil -
but "nil" is a proper object. So, methods
can be called on it without getting NullPointerException.
|
| Arrays |
|
|
|
| Array Literals |
|
Note that Groovy has List literals (represented
by a java.util.List instance). The following
list literal syntax can be used.
|
|
| RegEx Literals | Not supported. Regular Expressions are specified as Strings. |
/pattern/
Note from Guillaume Laforge: The "slashy" string syntax creates strings, in fact, it's not a regular expression per se, but it allows one to avoid to have to escape each and every character as it's the case in Java. But, this syntax doesn't really create some kind. Thanks! |
/pattern/ |
| Hash Literals | Not supported |
|
|
| varargs methods |
Use JDK 1.5+. The "..." after the last formal
argument means this is a vararg method.
|
Declare the last argument of the method as an array
with that Groovy packs "excess" arguments in method
call into that array argument
|
|
| Keyword arguments (a.k.a Named Parameters | Not supported |
Not directly supported. But hash literals can be
passed as an argument. When passing a hash literal
as an argument, the "[" and "]" chars can be omitted.
|
Not directly supported. But hash literals can be
passed as an argument. When passing a hash literal
as an argument, the "{" and "}" chars can be omitted.
|
| Operator Overloading | Not supported - except for built-in String + operator |
Special methods are defined in the class to overload
operators. For example, "plus" to overload "+".
|
Method names can be operators. Also, when calling
operator methods, you need not say obj.methodName.
instead you say obj methodName param1. But, you
can use usual method call syntax as well.
|
| Extending another class |
|
|
|
| Referring to super class method | super.foo(); | super.foo(); |
Unlike Java and Groovy, super
keyword calls the super class method of the currently executing
method. You are not calling arbitrary super method.
|
| Nested, inner and anonymous classes |
|
* Nested and inner classes are not supported (yet?). * Local and anonymous classes are not supported (yet?) But, we can use closures
|
From what I read, nested class is possible but
not "inner" classes. Please correct me if I am
wrong!
|
| Closures |
* Not yet part of Java. But, may become! * Nominal Closures for Java (version 0.2) * Full Disclosure * For now, use local and anonymous classes
|
For detailed explanation, refer to
Closures in Groovy
|
* Blocks must follow a method invocation. * Proc objects can be created by Proc.new or proc method (in Kernel).
For detailed critic, refer to
closures-in-ruby.rb
|
| Exception Handling |
|
Exception handling is same as Java - except that declarations of exceptions in method signature are optional - even for checked exceptions. |
In addition, there is another way to do non-local
jump:
The catch is searched by symbol (symbol is an
internalized string).
|
| Modules, Namespaces |
There may be
future
improvements in this area.
|
Same as Java |
require is like import.
There is also load -
but unlike "require", "load" loads the file everytime
when called (i.e., require loads and caches - subsequent
require on the same file is a no-op).
|
| Mixins | Not supported. |
Mix-in categories can be used. But, there seems to
another Mixin
proposal as well.
Guillaume Laforge notes that the @Property notation (striked above) is not needed anymore and will be forbidden in the RC-1 release. See also Groovy Beans
|
|
| Accessing Class object | obj.getClass(); | obj.class // or obj.getClass() | obj.class |
| Constructing object using reflection |
|
Same as Java - except that not forced to handle exceptions |
|
| Calling a method using reflection |
|
|
|
Pat Niemeyer has checked in JSR-223 script engine for BeanShell into the http://scripting.dev.java.net project. I've re-generated the binaries to include BeanShell engine. [Note: BeanShell is being standardized by JSR 274]. Daniel Fuchs wrote about using jconsole (monitoring and management console and not the 'jconsole' that comes with BeanShell!) with BeanShell. Now, that there is a jsr-223 script engine for BeanShell, it is possible to use BeanShell with jconsole script shell plugin.
Added JSR-223 script engine for FreeMarker - a Java-based general purpose template engine. As usual, the sources and binaries are available at http://scripting.dev.java.net
If you want to use FreeMarker with Phobos Framework, you do not need this engine. Phonos has built-in support for FreeMarker templates. Look for mappedServices.template in bootstrap.js.
But, this FreeMarker (and possibly the Velocity engine) script engine could be useful in stand-alone applications - For example, you can use it an application that processes template emails or other kind of template text.
The Java Platform supports multiple languages in addition to the Java Programming Language. With JDK 6, support for scripting languages has been included in the form of JSR-223 (javax.script). The scripting.dev.java.net project has been created to implement JSR-223 script engines and applications of it. So far, JSR-223 script engines are available for the following languages:
Expression only languagesIf you want a simple expressions-only language (and therefore possibly low footprint!) that can be embedded in some other full-fledged language in Java (or in some other language!), then you may want to look at these.
Functional Object based, Object oriented languagesIf you are looking for language for just text processing (and the rest of your logic would be implemented in another host language), then you may want to consider these. These text processing/templating languages would be useful in dynamic HTML generation in webapps, email template text processing and so on.
If you are looking for language to do XML processing (and the rest of your logic would be implemented in another host language), then you may want to consider these:
Today, I came to know this great news: The JRuby experts Charles Nutter and Thomas Enebo have joined Sun!.
To the JRuby greats: Welcome to Sun! And I came to know that they are iworkers - so another welcome - I am also an iworker!
Few minutes back, I added JSR-223 script engine for Velocity - a Java-based general purpose template engine. As usual, the sources and binaries are available at http://scripting.dev.java.net
Came across this: http://bexscript.sourceforge.net/. From the author of the Bex script:
Bex script is a (yet another) scripting language for the Java platform. It is heavily based on another great scripting language BeanShell.
Bex script comes with a JSR-223 script engine for the language (Bex script engine is written in Bex itself!). I did a quick test with a jrunscript session:
jrunscript -cp bex-1.0.jar -l bex
bex> x = 10
bex> y = 12
bex> x + y
22
bex> square = |x| { x * x}
bex.Block@26d4f1
bex> square(10)
100
bex> System.exit(0)
BTW, I came across this from:
http://machine.homeunix.org/weblog/archives/cat_script_on_java.htmlThis blog is well compiled and I refer to it regularly for scripting on Java platform news! (Japanese site?)
I just came across this post: Java isn't just Python without the cool language features - Java platform as such does not miss cool scripting features. While the examples suggested are Jython Groovy and JRuby, I'd like to point out JavaScript can be added to the list as well - in particular because JDK 6 includes Rhino based JavaScript engine and JavaScript does support these:
JavaScript function arity is not fixed. A function can always get all arguments by arguments object. Also, function can check for undefined values.
function mul(x, y) {
// if 'y' is passed assume default value of '3'
if (y == undefined) y = 3;
return x * y;
}
Nested functions are supported -- "inner" function can be returned and stored. Inner functions have the "outer" function's local scope as "parent" scope and therefore can access locals of the outer function. If you are looking for Smalltalk-like block closures with special "return" instruction to return from enclosing function, then you have to simulate that by exceptions.
There are 4 JVM bytecodes to call methods:
invokeinterface - used to call an interface method on an object
invokestatic - used to call a static method of a class
invokevirtual - used to call a overridable method
invokespecial - used to call
Please refer to the JVM specification for further details.
To facilitate the compilation of dynamically typed languages such as Groovy, JRuby, Jython to JVM bytecodes, a new bytecode called invokedynamic is being proposed (JSR-292). Note that the details of this JSR will be available only in future. Whatever I say below could be (or could become) completely wrong!
invokedynamic will (probably) not require the target class name and the
method signature. invokedynamic will search the specified method on the
target object based using just the name. The way to handle method overloading
will have to be specified by JSR]. How to handle failure to find required method?
- again this will also need to be specified by the JSR (For example, throw NoSuchMethodException or
call a pre-defined doesNotUnderstand or handleMethodCall method).
Let us consider the case of Groovy.
(JSR-241). Groovy supports
a flexible method dispatching framework. Without going into details:
if a method to be called is found in the class, then a special invokeMethod
method is called. I wrote about that in an
earlier post. Groovy would be able to make
use of invokedynamic to speed-up it's Meta Object Protocol
implementation.
class Person {
public Object invokeMethod(String methodName, Object args) {
System.out.println("calling " + methodName);
return methodName.toUpperCase();
}
};
Person b = new Person();
// This works. Calls "invokeMethod" because there is no "name"
// method in Person class.
System.out.println(b.name());
While Groovy's method dispatch is flexible for "clients" of classes,
calling a super class method is not so flexible. For example, when
super.foo() is called from a Groovy class, it is compiled
much like Java - i.e., using invokespecial. So, method
searched has to be found at "compile time". This means the following
will not work.
class Person {
public Object invokeMethod(String methodName, Object args) {
System.out.println("calling " + methodName);
return methodName.toUpperCase();
}
};
class Employee extends Person {
public String name() {
// This does *not* work! there is no "name" method in Person!
// Ideally, one would expect super.name() to call Person.invokeMethod().
return "Employee " + super.name();
}
}
We get the following "compile time" error:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed,
General error during class generation: No such method: name for class: Employee.
Node: org.codehaus.groovy.ast.expr.MethodCallExpression. At [11:40] t.groovy
1 error
A more flexible language like Smalltalk will allow the user
to call super class methods even not found during compilation. If the method
is not found in super class at runtime (or it's super class and so on), then doesNotUnderstand
method will be called [or should I say, doesNotUnderstand
message will be sent!]
But, because Groovy is limited by JVM can do, currently it uses either Java reflection or bytecode generation to implement it's meta object protocol. Java reflection does not allow us to call a overriden super class method on an object. java.lang.reflect.Method.invoke's javadoc says: If the underlying method is an instance method, it is invoked using dynamic method lookup as documented in The Java Language Specification, Second Edition, section 15.12.4.4; in particular, overriding based on the runtime type of the target object will occur.
Similarly, the reflection speed-up classes generated by Groovy can not call super class methods. [I am not sure why Groovy folks do this reflection speed-up -- HotSpot JVM already speeds up reflective calls by bytecode generation internally!]
The only way to call super class method is to generate invokespecial
which can only be inside a subclass! (and not in an unrelated reflection "speed-up" class). This explains why Groovy has to translate super.foo() with
invokespecial instruction. Groovy could probably do
the following to compile super.foo():
invokespecial
invokeMethod method.
But the problem here is that the above scheme "fixes" method dispatching
during compilation. For example, if a super class introduced "foo" method
after the compilation of subclass then that new method won't be called! (invokeMethod would be called. So, do we probably need invokespecialdynamic?
invokespecialdynamic would be like invokespecial
except that
invokedynamic would do!)
invokedynamic
-like throwing exception or calling a special method)
With invokespecialdynamic, Groovy would be able to flexibly implement
super.foo() calls.
I accidentally deleted my Jython installation. I attempted to reinstall Jython 2.1). Last time I had installed it with JDK 1.5.0_06. This time I attempted with JDK 6. I got the following error:
D:\downloads\Java\Jython>d:\jdk1.6.0\bin\java jython_21
Exception in thread "main" java.lang.ClassFormatError: Extra bytes at the end of class file jython_21
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:620)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:124)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:260)
at java.net.URLClassLoader.access$000(URLClassLoader.java:56)
at java.net.URLClassLoader$1.run(URLClassLoader.java:195)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:188)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:276)
at java.lang.ClassLoader.loadClass(ClassLoader.java:251)
at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:319)
Looks like Jython folks are self-extracing using the installer (jython_21.class). The installer class has extra bytes at the end of the .class file (which persumably has the installation data in compressed form).
JVM spec second edition section 4.9.1 makes it clear - a .class files can not have extra bytes at the end. May be the .class is verified with JDK 6 - but not with JDK 1.5.0_06? In fact, when using this command
D:\jdk1.5.0_06\bin\java -Xverify:all jython_21
I got the same aforementioned error - so clearly, with bytecode verification 1.5.0_06 also throws the same error. I tried the following command line:
D:\jdk1.6.0\bin\java -Xverify:none jython_21
Guess what? I got the same error! So, it appears that JDK 6's does not allow extra bytes at the end of .class files even when not doing bytecode verification!