Enactor Script Objects
Enactor Script cannot define brand new Java classes, but it can still give you object-oriented behaviour through scripted objects - a style of object built from method closures, similar to the approach used in JavaScript or Perl. It grows naturally out of the way methods already work in Enactor Script.
In standard Java, an instance method can refer back to its enclosing object using the special variable this:
// MyClass.java
MyClass {
Object getObject() {
return this; // return a reference to our object
}
}
Enactor Script has its own version of this idea, built around method invocations rather than class instances.
The 'this' Reference
Like any method invocation, a running Enactor Script method has its own local scope holding its parameters and any locally declared variables:
// Define the foo() method:
foo() {
int bar = 42;
print( bar );
}
// Invoke the foo() method:
foo(); // prints 42
print( bar ); // Error, bar is undefined here
bar only exists for the duration of that call to foo() - once the method returns, it is gone, just like a local variable in Java.
Enactor Script lets you hold on to that scope after the method returns, by returning the special this reference from inside the method:
foo() {
int bar = 42;
return this;
}
fooObject = foo();
print( fooObject.bar ); // prints 42!
Here, the value handed back by foo() - its this reference - behaves like an instance of a "foo" object, using the usual . notation to reach bar. In effect, every call to foo() builds a new object, and foo() has become an object constructor rather than a plain method.
Nested Methods
Methods in Enactor Script can contain other methods, nested to any depth:
foo() {
bar() {
...
}
}
A nested method like bar() is local to the invocation of foo() that defines it, and is not visible from outside - except through an object reference, exactly as you'd invoke a method on a Java object:
foo() {
int a = 42;
bar() {
print("The bar is open!");
}
bar();
return this;
}
// Construct the foo object
fooObject = foo(); // prints "the bar is open!"
// Print a variable of the foo object
print ( fooObject.a ) // 42
// Invoke a method on the foo object
fooObject.bar(); // prints "the bar is open!"
A method declared inside a block (such as an if statement) is treated exactly as if it had been declared directly in the enclosing method - there's no such thing as a block-local method:
foo() {
bar() { }
if ( true ) {
bar2() { }
}
return this;
}
In this example both bar() and bar2() end up defined directly within foo().