« August 2006 »
SunMonTueWedThuFriSat
     
2
3
6
7
9
10
11
13
15
16
17
20
23
24
28
29
30
       
Today
XML

Blog::Navigation

GetJava Download Button
Get the Source
Personal Blog

Blog::Referers

Today's Page Hits: 519

Powered by Roller Weblogger.
« Previous month (Jul 2006) | Main | Next month (Sep 2006) »
20060927 Wednesday September 27, 2006

Java, JavaScript and Jython - Part 2

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)

/pattern/

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.

import re

# prints ["Javascript", "Java"]
print re.findall('J[a-z]*', 
  "Javascript Java Python")

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:

color = { red: 0, green: 1, blue: 2 }

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

function greet(name, msg) {
  if (name === undefined) {
    name = "Sundar";
  }
  
  if (msg === undefined) {
    msg = "Hello, World";
  }
  println(name + ", " + msg);
}

// assume defaults for both
greet()
// assume default for "msg"
greet("Kannan");
// no defaults
greet("Sun", "Network")


def greet(name="Sundar", 
       msg="Hello, world"):
  print(name + ", " + msg)

# assume defaults for both
greet()
# assume default for "msg"
greet("Kannan");
# no defaults
greet("Sun", "Network")

Nested, inner and anonymous classes
// Inner class
class Book {
   class Order { }
}

// Nested class
class Node {
   static class AndNode {
   }
   static class OrNode {
   }
}

// Anonymous class
class Main {
  public Runnable getRunnable() {
    return new Runnable() {
      public void run() { 
        // code
      } 
    };
  }
}

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.


// nested class
function Node() {  
}

Node.AddNode = function() {
  print("AddNode constructor");
}

obj = new Node.AddNode();

// inner class
function Book(name) {
  this.name = name
  var book_this = this;
  this.Order = function(number) {
     this.number = number;
     println("Order #" + number + 
           " for " + book_this.name);
  }
}

b = new Book("Solaris Internals")
o1 = new b.Order(10)
o2 = new b.Order(11)

b2 = new Book("JVM Specification")
o3 = new b2.Order(22)
o4 = new b2.Order(25)

The trick is to use closures! - refer to new point.

class Node:
  class AddNode:
    def __init__(self):
      print("AddNode")

  class OrNode:
    def __init__(self):
      print("OrNode")   

n = Node.AddNode();

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.

function addWith(x) {
  return function(y) {
      return x + y
  }
}

var addTwo = addWith(2)
println(addTwo(3))

Python functions can be nested and nested function can refer to the locals of nesting function.

from __future__ import nested_scopes

def addWith(x):
  def f(y):
    return x + y
  return f

addTwo = addWith(2)
print(addTwo(3))

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

from __future__ import nested_scopes

def addWith(x):
  return lambda y: x + y

addTwo = addWith(2)
print(addTwo(3))

Lambda forms can be used wherever functions are required. Lambda's body is restricted to a single expression.
instance of check

obj instanceof ClassName

// for exact instance check 
// excluding subtype objects
obj.getClass() == ClassName.class



obj instanceof Constructor

function Person(name) {
  this.name = name
}

p = new Person();
// prints true
println(p instanceof Person)
// prints false
println(p instanceof Number)

Use isinstance function.

class Person:
  def __init__(self, name):
    self.name = name


class Employee(Person):
  def __init__(self, name):
    Person.__init__(self)

p = Person("Sundar")
# prints 1
print isinstance(p, Person);

# prints 0
print isinstance(p, Employee);

Accessing Class object obj.getClass(); typeof(expression) returns a descriptive string

obj.__class__

Throwing Exception throw exception; Same as Java - except that anything including number, string etc. can be thrown.

raise exception
raise exception, argument
raise exception(argument)

Examples:

raise "hello"
raise NameError, "hello"
raise NameError("hello")

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:

function printStackTrace() {
  try {

    var c = undefined;
    c.toString();
  } catch (e) {
    e.rhinoException.printStackTrace();
  }
}

function f() {
  g()
}

function g() {
  printStackTrace()
}

f();

See also More JavaScript debugging tips (Mustang context)

import traceback

def g():
  traceback.print_stack()

def f():
  g()

def main():
  f()

main()

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).

function Person(name) {
  this.name = name
}
Person.prototype.greet = function() {
    println("Hi, I'm " + this.name);
  }

p1 = new Person("Sundar")
p2 = new Person("Kannan")

// override "greet" just for p1
p1.greet = function() {
  println("Hello, world");  
}


// prints "Hello, world"
p1.greet();
// prints "Hi, I'm Kannan"
p2.greet();
// add a method just for p1

p1.sayHi = function() {
   println(this.name + " says hi");
}

p1.sayHi();

// p2.sayHi() will fail!


from __future__ import nested_scopes

class Person:
  def __init__(self, name):
    self.name = name

p1 = Person("Sundar")
p2 = Person("Kannan")

def attach_method(instance, func):
  def attached_method(*args, **kwargs):
    return func(instance, *args, **kwargs)
  return attached_method

def greet(self):
  print("Hi, I'm " + self.name)

p1.greet = attach_method(p1, greet);
p1.greet()

# p2.greet() will fail by exception

Essentially, add a closure valued property to the object in question. See also: Replacing methods without subclassing
Constructing object using reflection


Class c = obj.getClass();
// assuming default constructor
Object o = c.newInstance();

Objects are created using constructor functions. Functions are first class values. So, it is easy to construct objects using apply or call

function create(func, args) {
  // create an "empty" object
  var obj = new Object();
  // Now, apply constructor
  // and pass new object as "this"
  return func.apply(obj, args);
}

function Person(name) {
  println("new person: " + name);
  this.name = name
}

x = new Person("Kannan");
println(x instanceof Person);

// create indirectly
y = create(Person, ["Sundar"]);
println(y instanceof Person);

Classes are functions too. Just call..

class Person:
  def __init__(self, name):
    print("Created " + name)
    self.name = name
  def greet(self):
    print("Hello from " + self.name)


# just call
def create(clazz, *args):
  return clazz(*args)

p = create(Person, "Sundar")

# call a method on Person
p.greet()

Calling a method using reflection


Method m = obj.getClass().getMethod(
        name, classArray);
m.invoke(thisObj, argsArray);


Functions are first class values. So, it is easy to call indirectly using apply or call

function Person(name) {
  this.name = name
}

Person.prototype.greet = function() {
  println("Hi from " + this.name);
}

p = new Person("Sundar");
// get "method" attribute
method = p.greet;

// apply the method
// pass "this" object and args array
method.apply(p, []);


class Person:
  def __init__(self, name):
    self.name = name

  def greet(self):
    print("Hi from " + self.name)

p = Person("Sundar")

# may be, you get the
# method name from a
# config file!
func = getattr(p, "greet")

# call method indirectly
func()

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

from __future__ import nested_scopes

class Person:
  def __init__(self, name):
    self.name = name

  # special method to handle 
  # attribute "gets"
  def __getattr__(self, name):
    if name == 'greet':
       def f():
         print("Hello from " + self.name)
       return f
    else:  
       raise AttributeError, name  

p = Person("Sundar")
# calls "__getattr__"
p.greet()



( Sep 27 2006, 11:59:41 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060926 Tuesday September 26, 2006

Java, JavaScript and Jython

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

/*
 * multiline comment
 */

/**
 * javadoc comment
 */

// single line comment


/*
 * multiline comment
 */

// single line comment


# single line comment

No multiple line comments. But, Owen Densmore notes that multiline string literals may be used instead.
Control Statements


if (condition) {
  // statements
}

if (condition) {
  // statements
} else if (condition) {
  // statements
} else {
  // statements
}

while (condition) {
  // statements
}


do {
  // statements
} while (condition);

for (Type t : iterable) {
  // statements
}

for (init; condition; increment) {
  // statements
}

switch (target) {
  case constant_expr:
    // statements
    [break]
  ..
  default:
    // 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

if (condition) {
  // statements
}

if (condition) {
  // statements
} else if (condition) {
  // statements
} else {
  // statements
}

while (condition) {
  // statements
}

do {
  // statements
} while (condition);

for (init; condition; increment) {
  // statements
}

// for-each statement uses 
// "in" keyword unlike Java

for ([var t in iterable) {
  // statements
}

switch (target) {
  case constant_expr:
    // statements
    [break]
  ..
  default:
    // statements
}
* 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.

if expression:
  # statements
elif expression:
  # statements
elif expression:
  # statements
else:
  # statements

* There can be zero or more 
  elif parts
* The else part is optional
* The keyword `elif' is short 
  for `else if'


while expression:
  # statements

Example:
while 1:
  print("hello")

for item in seq:
  # statements

Example:
a = ["Java", "JavaScript", "Jython"]
for x in a:
   print(x)

* 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")

Example:

a = [ "Java", "JavaScript", "Jython"]
for x in a:
   print(x)
else:
   print("done")

String Literals "hello world"

// double-quoted
"hello, world"

// single-quotes are okay too
'hello, world'

* Need not escape " within single-quoted string
* Need not escape ' within double-quoted string

"String with double-quotes"

// single-quotes are okay too
'hello, world'

""" A multiple
line string
literals like this
"""

* 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.

function name(arg1, arg2) {
  // code here
}

function(arg1, arg2) {
  // code here
}

* 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
Examples:

function hello(name) {
   alert("hello, " + name);
}

var greet = function(name) {
   alert("hello, " + name);
}

// call unnamed function
greet("Sundar");

// or even

(function() { alert("hello "); })();

// nested function refers to local of
// enclosing function
function addWith(x) {
  return function(y) { return x + y; }
}

// returned function stored as value
var addTwo = addWith(2);

alert(addTwo(3));

def name(arg1, arg2):
   # code here

# anonymous functions
lambda arg1, arg2: expression

* 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

def hello():
  print("hello")

# unnamed lambdas
square = lambda x: x*x
square(10)
print("hello")
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__

# nested function
from __future__ import nested_scopes

def func(x):
    def j(y):
       return x + y
    return j

addTwo = func(2)
print(addTwo(10))

Class Declaration

class Foo {
    // methods
    // fields
}


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).


// a constructor function "Person"
// to create Person objects
function Person(name, age) {
   // this.foo introduces
   // new object fields.
   this.name = name;
   this.age = age;
}

There is JavaScript framework called "Prototype" that supports class based object orientation with JavaScript.

// create a new Class with Class.create
var Person = Class.create();

// add methods to the new Class created
Person.prototype = {
   initialize: function(name) {
      this.name = name;
   },
   greet: function() {
      println("Hello from " + this.name);
   }
};	


class Name:    
    # methods here

Example:

class Person:
  print("class Person")


class Person:
  def greet(self):
    print("hello world")   

Classes can have executable statements (like print call in above example).
Instance Variables

int i;
float f;
double d;
String s;

No need to declare instance variables. No special syntax for instance variable names. Just introduce instance variable by

obj.fieldName = Expression

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.

obj.fieldName = Expression

Example:

class Person:
  def setName(self, name):
    print("setting name as " +name);
    self.name = name

Static Variables

static int i;
static float f;

static double d;
static String s;

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.

function Person(name, age) {
  this.name = name;
  this.age = age;
  // increment the "static" count field
  this.__proto__.count++;
}

// introduce a static "count" field
Person.prototype.count = 0;

// create two Person objects
p1 = new Person()
p2 = new Person()

// now check the Person count
println(Person.prototype.count);

// or equivalently - because 
// prototype is searched if a field 
// is not found in
// object!
println(p1.count);
You may want to read Private Static Members in Javascript as well.
Class variables are declared within the "class".

class Person:
  # "static" field
  count = 0
  def __init__(self):
    Person.count += 1

# print static field value
print(Person.count)

# create two Person objects
p1 = Person()
p2 = Person()

# now print the count
print(Person.count)

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
class Person {
  public void greet() {
    System.out.println("hello");
  }
}
To define an instance method: add a function valued property to prototype [of the constructor function]
function Person(name) {
  this.name = name;
}

Person.prototype.greet =
  function() {
    println("hello from " + this.name);
  }
class Person:  
  # additional "self" 
  # parameter for 'this'
  def greet(self):
    print("hello world")
Note: Unlike Java and JavaScript, you have to specify special "self" parameter explicitly.
Static Method Definition
class Person {
  public static void greet() {
    System.out.println("hello");
  }
}
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

return expression;
return;


return expression;
return;


return expression;
return;

Object Creation
Person p = new Person();
var p = new Person();
Use class name like as a function name.
class Person:
  # statements

# create a new Person object
p = Person();
Method Call
obj.foo(param1, param2);
p.greet();
obj.foo(param1, param2);
p.greet();
obj.foo(param1, param2);
p.greet();
Referring to the current object this this self
Object Initialization
class Person {
  // declare constructor method
  // same as class name
  public Person() {
    // initialize new object here
  }
}
Objects are created by constructor functions!
function Person(name, age) {
  this.name = name;
  this.age = age;
}

var p = new Person();
class Person:
  # declare constructor method 
  # with the name __init__
  def __init__(self):
    # initialize new object here
    self.name = name;
    # initialize new object here
    print("I'm " + self.name);

p = Person("Sundar")
Extending another class

class Employee extends Person {
}

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.

class Name(Base1, Base2):
  # code here

* Jython supports multiple inheritance. User specifies zero or more superclasses within the parans just after the class name.
Null null null None
Arrays
int a[] = new int[10];
String[] s = new String[2];
a[0] = 3;
s[0] = "hello";

var a = new Array(10);
a[0] = 3;
a[1] = "hello";
println(a[0]);
println(a[1]);

# use lists
x = []
x.append(3)
x.append("hello")
print(x[0])
print(x[1])

Array Literals
int a[] = { 10, 4354, 432 }
String[] s = { "dsjfhsd", "sdfsd"}
a[0] = 3;
s[0] = "hello";

a = [2, 3, 4354]
s = ["hello", "world"]

print(a[2]);
print(s[0]);

a = [3, 4, 546]
a[0] = 3
a[1] = "hello"
print(a[0])
print(a[1])

Array length arr.length

arr.length
// but length can be assigned as well!
arr.length = 10
// array "index" can be strings -- 
// objects are associative arrays.
// arrays are objects with (mostly)
// "integer" property names
var arr = []
arr["Sun"] = "Network"
println(arr["Sun"])
println(arr.Sun)

len(arr)
Hash Literals Not supported Use JavaScript Object Literals. Objects are associative arrays.

var o = { key: value, key1: value1 }

Examples:

o = { 
      hello: "world", 
      Sun: "Network"
   }

println(o["Sun"]);

// field access syntax
println(o.Sun);


o = { key: value,
      key1: value1 }

Examples:

o = { 
      'hello': "world", 
      'Sun': "Network"
   }

print(o['hello'])
print(o['Sun'])

varargs methods Use JDK 1.5+. The "..." after the last formal argument means this is a vararg method.
class Person {
 public void greet(Object...args) {
  // access the "args" array here
 }
}
JavaScript functions can accept any number of arguments. "arguments" object is filled with all arguments.
function vararg() {  
 var i = 0
 for (i < arguments; i++) {
  println(arguments[i]);
 }
}
def greet(*args):
  print args

greet("hello")
greet("hello", "world")
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.

// function that accepts an object
function greet(arg) {
  println(arg.msg + 
          ", " + arg.name);
}

// caller passes object 
// literals with matching 
// "properties"
greet({ msg: "Hello", 
        name: "Sundar" })
greet({ name: "Sundar", 
        msg: "Hello" })

Functions can be called with keyword arguments of the form "keyword = value"

def greet(name, msg):
  print msg + ", " + name

greet(name="Sundar",msg="Hello");

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.

class Complex:
  def __init__(self, x, y):
    self.real = x
    self.imag = y

  def __add__(self, other):
    return Complex(
      self.real + other.real,   
      self.imag + other.imag)

  def print(self):
    print "real = ", self.real
    print "imag = ", self.imag

c1 = Complex(2, 3)
c2 = Complex(3, 2)
c = c1 + c2
c.print()

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.

class Person:
  def greet(self):
    print "Person's greet"

class Employee(Person):
  def greet(self):
    print "Employee's greet"
    Person.greet(self)

e = Employee()
e.greet()

Exception Handling

try {
  // statements
} catch(Exception e) {
  // statements
} finally {
  // statements
}


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).

try {
  // statements
} catch(e) {
  // statements
} finally {
  // statements
}

try {
   // code that could throw three exceptions
} catch (e if e == "IOException") {
   // handler for IOException
} catch (e if e == "EOFException") {
   // handler for EOFException
}

Thanks to lopex for notifying the multiple catch clauses.

try:
  # code that could throw exceptions
except IOError, (errno, strerror):
  # hadler for IOError
except ValueError:
  # handler for ValueError
except:  
  # handler for any-other Error
else:
  # code that will be executed if
  # exception was not thrown

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

package com.acme.foo;

import java.net.*;

// or import a specific class
import java.net.URL;

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__.


# importing a module
import mymodule

# or import only specific stuff
from mymodule import func, func2

Refer Modules section of Python tutorial.



( Sep 26 2006, 04:50:54 PM IST ) Permalink Comments [6] del.icio.us | furl | simpy | slashdot | technorati | digg

20060925 Monday September 25, 2006

Nice Ruby Metaprogramming intro...

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"



( Sep 25 2006, 09:30:04 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060922 Friday September 22, 2006

Method Closures

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; 



( Sep 22 2006, 01:02:31 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060921 Thursday September 21, 2006

Metaclasses in Ruby and Smalltalk

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:

  1. Everything is an object. With few languages, nearly everything is an object;-)
  2. Every object is an instance of some class
  3. classes "hold" methods - while instances of classes share the methods
  4. instances hold instance variables.
  5. A class derives/extends from another class (called superclass) - except for a special "root" class (typically called "Object") whose superclass is null.
  6. method search: When a method is called on an object, the method is looked on it's class, if not found on superclass-of-class and so on (till the superclass is null)
Note: Yes, I've left multiple inheritance!

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:

Ruby Metaclasses

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:

Smalltalk Metaclasses

What is the answer of Smalltalk to the class-of-class question? In Smalltalk,

More info on Smalltalk metaclasses:

Smaltalk vs. Ruby metaclasses

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.



( Sep 21 2006, 10:25:43 PM IST ) Permalink Comments [2] del.icio.us | furl | simpy | slashdot | technorati | digg

20060919 Tuesday September 19, 2006

Java, Groovy and (J)Ruby - Part 2

This is continuation of my earlier post.

What this is not? Then, what exactly is this?
Feature Java Groovy JRuby
Default argument Not supported (intentionally!)

class Person {
  def greet(msg="hello world") {
    println(msg);
  }
}

p = new Person()
// leave argument, default taken
p.greet()

// argument to override the default
p.greet "Groovy!"


class Person 
  def greet(msg="hello world")
    puts msg
  end
end

// leave argument, default taken
Person.new.greet

// argument to override the default
Person.new.greet "JRuby!"

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

println 5.class
5.times { println "hello" }

null seems like an object (you can call methods on it). but (null instanceof Object) is false!
Yes

puts 5.class
5.times { puts "hello" }

nil is an object. (nil.kind_of? Object) is true.
instance of check

obj instanceof ClassName

// for exact instance check 
// excluding subtype objects
obj.getClass() == ClassName.class

Same as Java. In addition, you could compare MetaClass as well (which is dynamic and be changed).

obj.metaClass == known_metaClass


class Person 
end

class Employee < Person
end

e = Employee.new

# kind_of? includes subtypes
# Note: kind_of? is like Java's 
# instanceof is_a? is 
# synonym for kind_of?

# prints true for both these
puts e.kind_of?(Employee)
puts e.kind_of?(Person)

# Note: instance_of? 
# is different from Java's 
# instanceof.

# this prints false
puts e.instance_of?(Person)

# this prints true
puts e.instance_of?(Employee)

Class Literals

ClassName.class
java.awt.Frame.class
Person.class

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, Person.class that is different -- that is similar to saying Person.class.getClass() in Java.


class Person   
end

def factory(klass)
  obj = klass.new
  puts "Created #{obj}"
  return obj
end

# To pass Person class, we
# just use Person!
factory Person

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");

def method1
  method2
end

def method2
  method3
end

def method3
  puts caller.join("\n");
end

method1

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.

class Person {
  def invokeMethod(String name, args) {
    println(name + " called");
  }
}

p = new Person();

// no "greet" method, "invokeMethod"
// is called.
p.greet();

Note: There are also more powerful ways to intercept method dispatching with MetaClasses in Groovy.

class Person 
  def method_missing(name, *args)
     puts name.to_s + " called"
  end
end

p = Person.new

# no "greet" method, so "method_missing"
# will be called

p.greet

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

class Person {
  def greet() {
    sayHello()
  }
}

p = new Person()

class Greeter {
  static def sayHello(obj) {
    println "hello world"
  }
}

use(Greeter) {
  p.greet()
}

Note that the above works only within the use statement. What if you want to make the change global?


class Person 
  def greet
    sayHello
  end
end

# again class Person!
# could be defined anywhere.
# declare more methods.

class Person 
  def sayHello
    puts "hello world"
  end
end

Person.new.greet

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

class Person {
  def greet() {
    sayHello()
  }
}

p = new Person()
def pmc = ProxyMetaClass.
         getInstance(Person.class);
class MyInterceptor 
      implements Interceptor {
   def invoke

   Object beforeInvoke(Object object,
     String name, Object[] args) {
     if (name == "sayHello") {
       println "hello world"
       invoke = false
     } else {
       invoke = true
     }
   }

   boolean doInvoke() {
     return invoke
   }

   Object afterInvoke(Object obj, 
     String name, Object[] args, 
     Object res) {
     return null
   } 
}

pmc.interceptor = new MyInterceptor()
p.metaClass = pmc;
p.greet()

Using Expando

// Expando allows you to add properties
// dynamically. The properties may be
// Closure valued.
class Person extends Expando {
}

p = new Person()
// add a property that is a closure 
p.greet = { println "p's hello"}
// call it like a method
p.greet()

p2 = new Person()
p2.greet = { println "p2's hello" }
p2.greet()


class Person   
  def greet 
    puts "hello"
  end
end

p1 = Person.new
p2 = Person.new

# change p2's greet method
def p2.greet 
  puts "p2's hello"
end

p1.greet
p2.greet

# extend "p2" to override
# and may be even add 
# more methods
class <<p2
  def greet
    puts "p2's changed hello"
  end
  def goodbye
    puts "p2's goodbye"
  end
end

p2.greet
p2.goodbye



( Sep 19 2006, 05:37:46 PM IST ) Permalink Comments [5] del.icio.us | furl | simpy | slashdot | technorati | digg

20060918 Monday September 18, 2006

Java, Groovy and (J)Ruby

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

/*
 * multiline comment
 */

/**
 * javadoc comment
 */

// single line comment


/*
 * multiline comment
 */

/**
 * javadoc comment
 */

// single line comment


=begin
 Ruby doc comment
=end

# this is single line comment

Control Statements

if (condition) {
  // statements
}

if (condition) {
  // statements
} else if (condition) {
  // statements
} else {
  // statements
}

while (condition) {
  // statements
}

do {
  // statements
} while (condition);

for (Type t : iterable) {
  // statements
}

for (init; condition; increment) {
  // statements
}

switch (target) {
  case constant_expr:
    // statements
    [break]
  ..
  default:
    // 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.

if (condition) {
  // statements
}

if (condition) {
  // statements
} else if (condition) {
  // statements
} else {
  // statements
}

while (condition) {
  // statements
}

while (condition) {
  // statements
}

// for-each statement uses "in" keyword 
// unlike Java
for (t in iterable) {
  // statements
}

switch (target) {
  case constant_expr:
    // statements
    [break]
  ..
  default:
    // statements
}
* 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?)

if condition 
  # statements
end

if condition
  # statements
elsif condition
  # statements
else
  # statements
end

while condition 
  # statements
end

unless condition
  # statements
else
  # statements
end

expression if condition
expression unless condition

# no do-while but you can use
# begin..end and put while or 
# until at the end
begin
 # statements
end until condition

begin
 # statements
end while condition

case target_expression
  when comparison 
    # statements
  when comparison
    # statements
  else
    # statements
end

* 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"

// double-quoted
"hello, world"

// single-quotes are okay too
'hello, world'

// multiple line strings for
// embedded "here docs"
""" multiple
line
strings"""

// substituted strings
"String with ${expression}
interpolated"

Example:

name = 'Sundar'
// ${name} is replaced with name's value
println "Hello, ${name}"


'no interpolation'
"#{interpolation}"
%q(no interpolation)
%Q(interpolation)
%(interpolation)

<<identifier   - interpolated 
<<"identifier" - same as above
<<'identifier' - no interpolation
<<-identifier  - indent using "-"

Examples:

name = 'Sundar'
puts "Hello, #{name}"

puts(<<EOF

This is a hello world
in multiple lines

EOF
)

Class Declaration

class Foo {
    // methods
    // fields
}


class Foo {
    // methods
    // fields
}


class Foo 
    # methods
    # fields
end

Instance Variables

int i;
float f;
double d;
String s;

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.

def i;
def f;
def d;
def s;
instance variable names start with '@'

@i
@f
@d
@s
Static Variables

static int i;
static float f;
static double d;
static String s;

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 '@@'

@@i
@@f
@@d
@@s
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 "$"

$xx 

Method Definition
class Person {
  public void greet() {
    System.out.println("hello world");
  }
}
class Person {
  def greet() {
    println("hello world");
  }
}
class Person
  def greet()
    puts("hello world")
  end
end
Static Method Definition
class Person {
  public static void greet() {
    System.out.println("hello world");
  }
}
class Person {
  static greet() {
    println("hello world");
  }
}
use className.methodName as method name.
class Person
  def Person.greet()
    puts("hello world")
  end
end
Returning from a method

return expression;
return;

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
Person p = new Person();
def p = new Person();
'new' is a method in Ruby!
p = Person.new 
Method Call
obj.foo(param1, param2);
p.greet();
can omit parans in some cases
obj.foo(param1, param2);
p.greet();
* If no arguments, need to use parans
* Parans can be omitted only for method calls in top-level statements
Example:

obj.foo param1, param2
"hello".substring 1, 3
can omit parans in some cases
obj.foo(param1, param2);
p.greet();
p.greet
Static Method Call
className.foo(param1, param2);
Person.greet();
System.exit(0);
className.foo(param1, param2);
Person.greet();
System.exit(0);
* If no arguments, need to use parans
* Parans can be omitted only for method calls in top-level statements
Example:
className.foo param1, param2
"hello world".substring 1, 3
className.foo(param1, param2);
className::foo(param1, param2);
Person::greet();
Person::greet;
Person.greet;
Object Initialization
class Person {
  // declare constructor method
  // same as class name
  public Person() {
    // initialize new object here
  }
}
class Person {
  // declare constructor method 
  // same as class name
  Person() {
    // initialize new object here
  }
}
class Person 
  # declare "initialize" method 
  # not the class name!
  def initialize()
    # initialize new object here
  end
end
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.

nil.nil?
nil.class
nil.methods

Arrays
int a[] = new int[10];
String[] s = new String[2];

a[0] = 3;
s[0] = "hello";

def a = new int[10];
def s = new String[2];

a[0] = 3;
s[0] = "hello";

// Array is a class
a = Array.new(10);
a[0] = 3;
a[1] = "hello";

Array Literals
int a[] = { 10, 4354, 432 }
String[] s = { "dsjfhsd", "sdfsd"}
a[0] = 3;
s[0] = "hello";

Note that Groovy has List literals (represented by a java.util.List instance). The following list literal syntax can be used.

def a = [2, 3, 4354]
def s = ["hello", "world"]

a[0] = 33;



a = [3, 4, 546]
a[0] = 3;
a[1] = "hello";

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

[ key: value, key1: value1 ]

Examples:

v = [ 
      hello: "world", 
      Sun: "Network"
    ]

println(v["Sun"]);


{ key=> value, key1=> value1 }

Examples:

v = { 
      "hello" => "world",
      "Sun" => "Network"
    }

puts v["Sun"]


varargs methods Use JDK 1.5+. The "..." after the last formal argument means this is a vararg method.
class Person {
  public void greet(Object...args) {
    // access the "args" array here
  }
}
Declare the last argument of the method as an array with that Groovy packs "excess" arguments in method call into that array argument
class Person {
  public void greet(Object[] args) {
    // access the "args" array here
  }
}

class Person
  # "*" before the last argument
  def greet(*args)
    # access args Array here
  end
end
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.

def func(arg) {
   println(arg["Sun"]);
}

// Note that we omit "[", "]"
func("Sun": "Network");

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.

def func(arg)
   puts arg["Sun"]
end

# Note that we omit "{", "}"
func("Sun"=>"Network");

Operator Overloading Not supported - except for built-in String + operator

class Complex {
  double x, y;
  Complex(x, y) {
    this.x = x;
    this.y = y;
  }

  def plus(Complex c) {
    new Complex(x + c.x, y + c.y);
  }
 
  def print() {
     println("${x} +i${y}");
  }
}

c1 = new Complex(3, 2);
c2 = new Complex(1, -2);
// + calls plus method
(c1+c2).print();

Special methods are defined in the class to overload operators. For example, "plus" to overload "+".

class Complex 
  def initialize(x, y) 
    @real = x
    @imag = y
  end

  attr :real , true
  attr :imag , true

  def +(c) 
    Complex.new(real + c.real, imag + c.imag);
  end
 
  def print() 
     puts  "#{real} +i#{imag}";
  end
end

c1 = Complex.new(3, 2);
c2 = Complex.new(1, -2);
(c1+c2).print();

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

class Employee extends Person {
}


class Employee extends Person {
}


class Employee < Person
end

Referring to super class method super.foo(); super.foo();

class X 
 def func
  puts "I'm func"
 end
end

class Y < X
 def func
  puts "I'm extended func"
  super  
 end 
end

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
// Inner class
class Book {
   class Order { }
}

// Nested class
class Node {
   static class AndNode {
   }
   static class OrNode {
   }
}

// Anonymous class
class Main {
  public Runnable getRunnable() {
    return new Runnable() {
      public void run() { 
        // code
      } 
    };
  }
}
* 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!


# Nested class
class A 
  def initialize
    @y = 0
  end

  # "B" is nested in "A"
  class B 
    def initialize
      @x = 0
    end
    def f
      # ...
    end
  end
end

a = "hello"
# create a duplicate
b = a.dup

# anonymous class for "a"
class <<a
  def to_s
    "I'm special '#{self}'"
  end
  def doubleMe
    self + self
  end
end

# prints "I'm special 'hello'"
puts a.to_s

# prints "hello"
puts b.to_s

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 ;-)
{ param1, param2 -> /* statements */ }

/* single param named as "it" */
{ /* statements */ }

Examples:

[3, 4, 4].each { x -> println(x) }
[3, 4, 4].each { println(it); }

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).

{ |param1, param2| ... }
do |param1, param2| ... end

Examples:

[3, 4, 5].each { |x| puts x }
[3, 4, 5].each do |x| 
   puts x 
end

For detailed critic, refer to closures-in-ruby.rb
Exception Handling

try {
  // statements
} catch(Exception e) {
  // statements
} finally {
  // statements
}

Exception handling is same as Java - except that declarations of exceptions in method signature are optional - even for checked exceptions.

begin
  expressions
[rescue [errorType [=> var],..]
  expressions]..
[else
  expressions]
[ensure
  expr..]
end

In addition, there is another way to do non-local jump:

catch (:done) do
    # some statements
    throw :done 
end

The catch is searched by symbol (symbol is an internalized string).
Modules, Namespaces

package com.acme.foo;

import java.net.*;

There may be future improvements in this area.
Same as Java

module ModuleName
  # module level "functions" 
  # module level constants
  # zero or more classes
end

Example:

module Math
  PI = 3.141592654
  def Math.sin(x)
   # ..
  end
  def Math.cos(x)
   # ..
  end
end

require "name_of_file"

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.

class Greeter {
  static greet(Person p) {
    println(p.msg);
  }
}

class Person { 
  @Property def msg;
}

p = new Person();
p.msg = "hello"
use(Greeter) {
  // with "use" we can call 
  // "greet" on "Person" object

  p.greet();
}


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

module Greeter
 def greet
   puts msg
 end
end

class Person
 # "include" zero or more 
 # modules to get restricted
 # (and safe!) form of multiple
 # inheritance

 include Greeter
 attr :msg, true
end

p = Person.new
p.msg = "hello"
p.greet

Accessing Class object obj.getClass(); obj.class // or obj.getClass() obj.class
Constructing object using reflection

Class c = obj.getClass();
// assuming default constructor
Object o = c.newInstance();

Same as Java - except that not forced to handle exceptions

klass.new
klass.new(param1, param2);

Calling a method using reflection


Method m = obj.getClass().getMethod(
        name, classArray);
m.invoke(thisObj, argsArray);


obj.invokeMethod(name, args);

Example:

class Person {
  def getName(name) {
     println("hello ${name}");
  }
}

p = new Person();
p.invokeMethod("getName", "Sundar");


obj.send(:name_symbol, args)

Example:

class Person 
  def greet (name)
   puts "hello, #{name}"
  end
end

p = Person.new
p.send(:greet, "Sundar")

# or alternatively

# get method object
m = p.method(:greet);

# ... and call it
m.call("Sundar");




( Sep 18 2006, 02:01:42 PM IST ) Permalink Comments [11] del.icio.us | furl | simpy | slashdot | technorati | digg

20060914 Thursday September 14, 2006

BeanShell JSR-223 script engine

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.



( Sep 14 2006, 10:54:57 AM IST ) Permalink Comments [3] del.icio.us | furl | simpy | slashdot | technorati | digg

20060912 Tuesday September 12, 2006

FreeMarker JSR-223 script engine

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.



( Sep 12 2006, 12:44:26 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060908 Friday September 08, 2006

Scripting Project - Status Report

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 languages

If 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 languages Procedural languages Text Processing and Templating languages

If 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.

XML

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!



( Sep 08 2006, 04:25:15 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Velocity JSR-223 script engine

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



( Sep 08 2006, 12:44:16 PM IST ) Permalink Comments [1] del.icio.us | furl | simpy | slashdot | technorati | digg

20060905 Tuesday September 05, 2006

Bex script

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.html

This blog is well compiled and I refer to it regularly for scripting on Java platform news! (Japanese site?)



( Sep 05 2006, 01:10:03 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060904 Monday September 04, 2006

Why not JavaScript?

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:

  1. First-class functions - yes
    • Functions can be passed, returned and stored as values
    • Function literals (anonymous functions) supported
    • Can create Function values from code strings (Function.prototype)
  2. Default parameters - Yes (indirectly)

    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;
      }
     
     

  3. Tuples - Yes, JavaScript arrays are dynamically sized. length property can be assigned. Java arrays can also be accessed with the same syntax. JavaScript arrays and objects are treated uniformly. Object fields and methods can be accessed using array index operator with string keys.
  4. Closure support - yes

    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.

  5. Continuations - although not yet part of JavaScript standard Rhino implementation supports continuations
  6. Meta-Programming/reflection - yes
    • Rhino supports assignable "protos" (__proto__ property)
    • Walking all "fields"/"methods" of an object by "for..in" loop
    • "eval" code in a string
    • Changing parent scope by assignable __parent__ property



( Sep 04 2006, 08:55:48 PM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

20060901 Friday September 01, 2006

invokespecialdynamic?

There are 4 JVM bytecodes to call methods:

  1. invokeinterface - used to call an interface method on an object
  2. invokestatic - used to call a static method of a class
  3. invokevirtual - used to call a overridable method
  4. invokespecial - used to call
    • constructors
    • private instance methods
    • super class methods (super.foo() calls in the source)
All these instructions require the specification of
  1. target class (or interface for invokeinterface) name
  2. the name of the method (or <init> for constructors)
  3. the signature of the method.

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());

Problem with calling super class methods

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():

  1. Look for "foo" in super class or it's super class and so on. If found, generate invokespecial
  2. if matching method is not found in super class(es), instead of throwing error, call the 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?

What would the invokespecialdynamic do?

invokespecialdynamic would be like invokespecial except that

  1. it won't accept the method signature (handle overloading in the same way as invokedynamic would do!)
  2. if the method of specified name is found at runtime, fallback step is taken (that could be same as invokedynamic -like throwing exception or calling a special method)

With invokespecialdynamic, Groovy would be able to flexibly implement super.foo() calls.



( Sep 01 2006, 08:26:44 PM IST ) Permalink Comments [6] del.icio.us | furl | simpy | slashdot | technorati | digg

Extra bytes at the end of a .class file?

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!



( Sep 01 2006, 09:50:10 AM IST ) Permalink del.icio.us | furl | simpy | slashdot | technorati | digg

Copyright (C) 2005, A. Sundararajan's Weblog