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

Comments:

Post a Comment:
Comments are closed for this entry.
About

sundararajan

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today
Bookmarks
Links

No bookmarks in folder

Blogroll

No bookmarks in folder

News

No bookmarks in folder