Wednesday, December 5, 2007

Restricted syntax fun

WARNING: This entry's content relies on Javascript so you'll need to read it in a browser window.

Neal Gafter has blogged about some possible alternatives to the RestrictedFunction approach used by the current Closures spec, and I think it may be useful to get more of a glimpse at how a couple of these suggestions look in terms of code.

If you've just opened this page you should see some code below which illustrates the use of one of Neal's suggestions - allowing function types to be declared in such a way that we can additionally specify certain marker interfaces (such as RestrictedFunction) as part of a function type's type declaration.

Neal also mentions another option, which uses a slightly different syntax for unrestricted and restricted closures (and function types). The two input fields below allow you to vary the tokens used - click the 'Show me' link after changing them to see the effect. When the tokens are the same, '&RestrictedFunction' will be present in the type declarations, when they are different it will not.

Don't take the code examples too seriously!

Normal token: Restricted token: Show me

interface Foo {

void execute(Runnable r);

// invokes fn synchronously
void loop(int count, {=> void} fn);

// stores command in an instance variable for later invocation
void setCommand({=> void}&RestrictedFunction command);

// invokes reducer in the same thread
<T> T reduce(List<T> list, {T,T => T} reducer);

// invokes each evaluator concurrently, returning the evaluator with the highest
// result for the specified value
{int => int}&RestrictedFunction max(Collection<{int => int}&RestrictedFunction> evaluators, int value);

// invokes combiner in multiple threads
<T,U,V> ParallelArray<V> combine(ParallelArray<T> array1, ParallelArray<U> array2,
{T,U => V}&RestrictedFunction combiner);

// curries a 3-argument unrestricted function
<A1,A2,A3,R> {A1 => {A2 => {A3 => R}}&RestrictedFunction}&RestrictedFunction
curry({A1,A2,A3 => R} fn);

// curries a 3-argument restricted function
<A1,A2,A3,R> {A1 => {A2 => {A3 => R}&RestrictedFunction}&RestrictedFunction}&RestrictedFunction
curry({A1,A2,A3 => R}&RestrictedFunction fn);

for (int i = 0; i < 10; i++) {

Foo foo = makeMeAFoo();

int count = 0;

foo.execute({=> if (++count == i) break silliness;});
foo.execute({=> System.out.println("executed!");});

foo.loop(5, {=> if (++count == i) break silliness;});
foo.loop(5, {=> System.out.println("executed!");});
foo.loop(5) {
if (++count == i) break silliness;

foo.setCommand({=> System.out.println("executed!");});

{String, String => String}&RestrictedFunction reducer = {String s1, String s2 => s1 + " " + s2};
String result1 = foo.reduce(myListOfStrings, reducer);
String result2 = foo.reduce(myListOfStrings,
{String s1, String s2 =>
if (++count == i) {
break silliness;
s1 + " " + s2

List<{int => int}&RestrictedFunction> evaluators = new ArrayList<{int => int}&RestrictedFunction>();
evaluators.add({int i => i + 1});
evaluators.add({int i => i * 2});
evaluators.add({int i => i * i});
{int => int}&RestrictedFunction maxEvaluator = foo.max(evaluators);

{String => {String => {String => String}}&RestrictedFunction}&RestrictedFunction
curried1 = curry({String s1, String s2, String s3 => s1 + s2 + s3});

{String => {String => {String => String}&RestrictedFunction}&RestrictedFunction}&RestrictedFunction
curried2 = curry({String s1, String s2, String s3 => s1 + s2 + s3});