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