Transfering control without growing control context -- i.e. how toimplement GOTO

  • Thread starter Jens Axel Søgaard
  • Start date
J

Jens Axel Søgaard

Hi all,

As a summer project I am writing a small compiler that produces
JavaScript. Right now I am looking for a method to tranfer control
that doesn't grow control context.

In a language with support for tail call optimization, I would
have used a normal function call. [I hope TCO will be a part of
ECMA-Script version 4].

In a language with GOTO, I would have used GOTO.


At first I thought I could use CONTINUE and BREAK together with
labelled statements, but a thorough reading of ECMA-262 reveals
that the labels have the wrong scope for my type of usage.

The best solution I have found so far consists of enclosing
the entire program in a switch:

Example that prints 02

var pc = 0;
while (pc >= 0) {
switch ( pc )
{ case 0 : document.write(0);
pc = 2; continue;
case 1 : document.write(1)
pc = pc+1; continue;
case 2 : document.write(2)
pc = -1;
}

The solution works in the sense that control is transferred
without growth of the control context. The naïve approach
above will in worst case require the same number of
comparisions in the switch as the number of labels in the
program. Nesting switchs inside switchs could bring this
down to a logarithmic number of comparisons, but I hope
there is a simpler solution.

The question is:

What is the most efficient method of
implementing control transfers without
growing control context?

The compiler is a whole-program-compiler, so anything goes.
If possible I'd like to avoid trampolines.
 
D

d d

Jens said:
As a summer project I am writing a small compiler that produces
JavaScript. Right now I am looking for a method to tranfer control
that doesn't grow control context.

Did you look at Google's GWT ? I only briefly looked at it
to see if it was any help on a project I was working on. I
remember though that it let you write code in Java and it
produced JavaScript from it. As it's open source (I think),
you might find some useful ideas in there.

http://code.google.com/webtoolkit/

~dd
 
R

ron.h.hall

Hi all,

As a summer project I am writing a small compiler that produces
JavaScript. Right now I am looking for a method to tranfer control
that doesn't grow control context.

In a language with support for tail call optimization, I would
have used a normal function call. [I hope TCO will be a part of
ECMA-Script version 4].

In a language with GOTO, I would have used GOTO.

At first I thought I could use CONTINUE and BREAK together with
labelled statements, but a thorough reading of ECMA-262 reveals
that the labels have the wrong scope for my type of usage.

The best solution I have found so far consists of enclosing
the entire program in a switch:

Example that prints 02

var pc = 0;
while (pc >= 0) {
switch ( pc )
{ case 0 : document.write(0);
pc = 2; continue;
case 1 : document.write(1)
pc = pc+1; continue;
case 2 : document.write(2)
pc = -1;
}

The solution works in the sense that control is transferred
without growth of the control context. The naïve approach
above will in worst case require the same number of
comparisions in the switch as the number of labels in the
program. Nesting switchs inside switchs could bring this
down to a logarithmic number of comparisons, but I hope
there is a simpler solution.

The question is:

What is the most efficient method of
implementing control transfers without
growing control context?

The compiler is a whole-program-compiler, so anything goes.
If possible I'd like to avoid trampolines.

At one time I wrote a parser generator that produced parsers under a
model similar to the following:

function test() {
var pc=0
var production = [
function() { document.write(0); pc = 2; },
function() { document.write(1); pc += 1; },
function() { document.write(2); pc=-1;}
];

while (pc >= 0 ) {
production[pc]();
}
}
 
J

Jens Axel Søgaard

At one time I wrote a parser generator that produced parsers under a
model similar to the following:

function test() {
var pc=0
var production = [
function() { document.write(0); pc = 2; },
function() { document.write(1); pc += 1; },
function() { document.write(2); pc=-1;}
];

while (pc >= 0 ) {
production[pc]();
}
}

Thanks. Your approach was what I had in mind, when I mentioned
trampolines. It might not be as bad as I feared. Did it work
well in your application? Did you try any alternatives?

If the control points are named, it is possible to omit the array
references:

function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}
 
R

Richard Cornford

Jens said:
At one time I wrote a parser generator that produced parsers under a
model similar to the following:

function test() {
var pc=0
var production = [
function() { document.write(0); pc = 2; },
function() { document.write(1); pc += 1; },
function() { document.write(2); pc=-1;}
];

while (pc >= 0 ) {
production[pc]();
}
}

Thanks. Your approach was what I had in mind, when I mentioned
trampolines.

Here you have a terminology problem. You are trying to express your
problem with the terminology that is familiar to you, but your desired
audience are people who know about javascript and so are likely familiar
with its terminology, but not necessarily both. You may have to be more
explicit about whatever it is you are trying to achieve. I, for one,
attach no absolute an certain meaning to the term "control context" and
so have no idea what constructs in javascript it may relate to, and so
why 'growing' them may be a problem.
It might not be as bad as I feared. Did it work
well in your application? Did you try any alternatives?

If the control points are named, it is possible to omit the array
references:

They are not "array references" they are "property accessors".
Javascript has no array-specific syntax.
function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

Globally declared named functions become properties of the javascript
global object so they can be referenced, but still with property
accessors, as members of that object. In a web browser where the global
object is available as a - window - property of the global object the
code would be:-
pc = label0 ();
while (pc=window[pc]()) {}

- in other environments it may be necessary to create your own global
reference to the global object. In inline code (as opposed to function
body code) that could be done with:-

var global = this; // as this - is a reference to the global object in
// the global execution context.

Richard.
 
R

ron.h.hall

At one time I wrote a parser generator that produced parsers under a
model similar to the following:
function test() {
var pc=0
var production = [
function() { document.write(0); pc = 2; },
function() { document.write(1); pc += 1; },
function() { document.write(2); pc=-1;}
];
while (pc >= 0 ) {
production[pc]();
}
}

Thanks. Your approach was what I had in mind, when I mentioned
trampolines.

I see (wasn't aware there was parser jargon for the TCO alternative).
It might not be as bad as I feared. Did it work
well in your application?

For my purposes, very well. My recollection is that it parses
Javascript source at between 1300 and 2500 lines/sec (50,000 to
100,000 tokens/sec) depending on the browser used, on a 3 GHz machine.
I'd have to re-test to confirm.
Did you try any alternatives?

No, since I found the implementation to meet my requirements. Neither
was any effort put into optimization.
If the control points are named, it is possible to omit the array
references:

function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

True. However indirect lookup isn't that costly, and is very useful if
you intend to include non-intrusive debugging capability.
 
J

Jens Axel Søgaard

Richard said:
Here you have a terminology problem. You are trying to express your
problem with the terminology that is familiar to you, but your desired
audience are people who know about javascript and so are likely familiar
with its terminology, but not necessarily both.

You are right, thanks for bringing it to my attention. I'll
try my best to explain a little further.
You may have to be more
explicit about whatever it is you are trying to achieve. I, for one,
attach no absolute an certain meaning to the term "control context" and
so have no idea what constructs in javascript it may relate to, and so
why 'growing' them may be a problem.

In languages (such as JavaScript) where continuations aren't first
class, the control context is normally referred to as the "control
stack". (In some languages the control context is a not a stack,
but a tree - hence the use of the more general term). Calling a function
in JavaScript will always push an activation record onto the control
stack. This "grows the control context".

If you look at how the behaviour of the control stack in the example:

function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

It will "jump up and down" - hence the nickname "trampoline".

Trampolines are a well-known way of compiler technique of
implementing Proper Tail Recursion [1], used when the target
language doesn't support Proper Tail Recursion.


As for why the growth of the control context is a problem,
when translating a source language supporting proper tail
recursion into a language without, consider the following
example. In the example the recursive call to sum is a tail
call (if a the result of a function call, is to be returned
by the calling function, then the function call is a tail call):

function sum (n, s) {
if (n==0)
return s;
else
return sum(n-1, s+n);
}
document.write(sum(1000,0));

In Scheme and ML which support tail recursion, the
a compiler essentially compiles sum(n-1,s+n) to
a jump instruction - which doesn't grow the control
context. Therefore the above works.

In JavaScript the control stack will grow, and eventually
you get the error "too much recursion" (wording taking from FireFox).


Supporting Proper Tail Recursion means that an arbitrary number
of tail calls can be active (a call is active, as long as the
callee hasn't returned) using nothing but a bounded amount of space.


A normal strategy to transfer control from one point to another
without growing control context is to use goto. However since
goto is not part of JavaScript, I need to find a construct that
works in a similar way. The switch-example is one solution and
the trampoline is another.
They are not "array references" they are "property accessors".
Javascript has no array-specific syntax.

The [1,2,3] notation are called array literals in the standard,
but I realize that it is nothing but syntactic sugar for
objects. Coming from Scheme it is hard for me to get used to say
"property accessor", when conceptually I am referencing
elements in an array.
function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

Globally declared named functions become properties of the javascript
global object so they can be referenced, but still with property
accessors, as members of that object. In a web browser where the global
object is available as a - window - property of the global object the
code would be:-
pc = label0 ();
while (pc=window[pc]()) {}

Thanks for mentioning this. I tried the trampoline example in FireFox
and it works there, but am I correctly reading between the lines, that
I can't expect it to work in other browsers?


I tried this example in FireFox:

function foo() {document.write(1); }
this.window.foo = function () {document.write(2);}
foo();

The example prints 2. If the line this.window.foo=... is
deleted, then the example prints 1. Variables in window
thus shadows global variables.

Can I expect one type of variable reference to be faster than
another in the current browser implementation of JavaScript?
Or is that non-measurable?
 
J

Jens Axel Søgaard

(e-mail address removed) skrev:
I see (wasn't aware there was parser jargon for the TCO alternative).

My fault - I have been a Schemer for so long I forget it isn't
common knowledge.
For my purposes, very well. My recollection is that it parses
Javascript source at between 1300 and 2500 lines/sec (50,000 to
100,000 tokens/sec) depending on the browser used, on a 3 GHz machine.
I'd have to re-test to confirm.

That's good to know.
No, since I found the implementation to meet my requirements. Neither
was any effort put into optimization.


True. However indirect lookup isn't that costly, and is very useful if
you intend to include non-intrusive debugging capability.

Good point. I consider "debugability" very important.
 
R

Richard Cornford

Jens said:
Richard Cornford wrote:
In languages (such as JavaScript) where continuations aren't first
class, the control context is normally referred to as the "control
stack". (In some languages the control context is a not a stack,
but a tree - hence the use of the more general term). Calling a
function in JavaScript will always push an activation record onto
the control stack. This "grows the control context".

So that would be the stack of "execution contexts" in
javascript/ECMAScript terms.
If you look at how the behaviour of the control stack in the example:

function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

It will "jump up and down" - hence the nickname "trampoline".

Trampolines are a well-known way of compiler technique of
implementing Proper Tail Recursion [1], used when the target
language doesn't support Proper Tail Recursion.

I think you are going to be stuck with either this or the switch-case,
and there seems to be much more mileage in your trampoline.
As for why the growth of the control context is a problem,
when translating a source language supporting proper tail
recursion into a language without, consider the following
example. In the example the recursive call to sum is a tail
call (if a the result of a function call, is to be returned
by the calling function, then the function call is a tail call):

function sum (n, s) {
if (n==0)
return s;
else
return sum(n-1, s+n);
}
document.write(sum(1000,0));

In Scheme and ML which support tail recursion, the
a compiler essentially compiles sum(n-1,s+n) to
a jump instruction - which doesn't grow the control
context. Therefore the above works.

In JavaScript the control stack will grow, and eventually
you get the error "too much recursion" (wording taking from
FireFox).

So your problem is that you are compiling a language that will (or
should) never cause a stack overflow into one that's only response to
the issue is to stop if recursion goes on for too long (and not all
ECMAScript environments do that (Opera, as I recall, will go on
recursing until it OS runes out of memory).
Supporting Proper Tail Recursion means that an arbitrary number
of tail calls can be active (a call is active, as long as the
callee hasn't returned) using nothing but a bounded amount of space.

A normal strategy to transfer control from one point to another
without growing control context is to use goto. However since
goto is not part of JavaScript, I need to find a construct that
works in a similar way. The switch-example is one solution and
the trampoline is another.

I think the trampoline is going to be your best option. So the next
question should probably be how to implement it in a way that is suited
to the task. for which a much more concrete example may be necessary.
For example, I am unclear as to how your are going to be handling the
variables in original language (their scoping and so on), and arguments
to your function calls in javascript.
They are not "array references" they are "property accessors".
Javascript has no array-specific syntax.

The [1,2,3] notation are called array literals in the standard,

OK, that is arguably array-specific.
but I realize that it is nothing but syntactic sugar for
objects. Coming from Scheme it is hard for me to get used to say
"property accessor", when conceptually I am referencing
elements in an array.
function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

Globally declared named functions become properties of the javascript
global object so they can be referenced, but still with property
accessors, as members of that object. In a web browser where the
global object is available as a - window - property of the global
object the code would be:-
pc = label0 ();
while (pc=window[pc]()) {}

Actually that is unnecessary, stupid, and will not work. Distracted by
the talk of labels I failed to notice that your functions do not return
strings but instead return function references, so your original is fine
and sticking 'window' in front will break it.

I was also thrown off a bit by the - pc = label0 (); - line. It could
have been - pc = label0; - (assigning a reference to the function
instead of a result to the first call to the function). Here the outcome
would have been the same, but doing it that way would have allowed the
fist function called to return false and so stop the process after only
one call.
Thanks for mentioning this. I tried the trampoline example in FireFox
and it works there, but am I correctly reading between the lines, that
I can't expect it to work in other browsers?

I don't see how that happened. But the - window - reference to the
ECMAScript global object is general to all web browsers (and some other
environments such as W3C standard SVG), it just is not available in all
environments, such as windows scripting host, JScript ASP and probably
stand-alone javascript interpreters.
I tried this example in FireFox:

function foo() {document.write(1); }
this.window.foo = function () {document.write(2);}
foo();

The example prints 2. If the line this.window.foo=... is
deleted, then the example prints 1. Variables in window
thus shadows global variables.

No, global variables _are_ properties of the global object, and -
window - is a reference to the global object so the global variable is
not shadowed, it is assigned a new value.
Can I expect one type of variable reference to be faster than
another in the current browser implementation of JavaScript?

For an unqualified Identifier the length of scope chain is a factor in
the speed of resolving it to a value or writing a value to it, for a
property accessor the location of the property on the prototype chain of
the object in question is a factor when reading the value (but not when
writing as writing will always assign to the object at the top of the
prototype chain).
Or is that non-measurable?

When measured the differences are miniscule, and often one browser will
favourer one thing while the next browser favours another.

Richard.
 
J

Jens Axel Søgaard

Richard said:
Jens said:
Richard Cornford wrote:
In languages (such as JavaScript) where continuations aren't first
class, the control context is normally referred to as the "control
stack". (In some languages the control context is a not a stack,
but a tree - hence the use of the more general term). Calling a
function in JavaScript will always push an activation record onto
the control stack. This "grows the control context".

So that would be the stack of "execution contexts" in
javascript/ECMAScript terms.
Yes.
If you look at how the behaviour of the control stack in the example:

function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

It will "jump up and down" - hence the nickname "trampoline".

Trampolines are a well-known way of compiler technique of
implementing Proper Tail Recursion [1], used when the target
language doesn't support Proper Tail Recursion.

I think you are going to be stuck with either this or the switch-case,
and there seems to be much more mileage in your trampoline.
Okay.
As for why the growth of the control context is a problem,
when translating a source language supporting proper tail
recursion into a language without, consider the following
example. In the example the recursive call to sum is a tail
call (if a the result of a function call, is to be returned
by the calling function, then the function call is a tail call):

function sum (n, s) {
if (n==0)
return s;
else
return sum(n-1, s+n);
}
document.write(sum(1000,0));

In Scheme and ML which support tail recursion, the
a compiler essentially compiles sum(n-1,s+n) to
a jump instruction - which doesn't grow the control
context. Therefore the above works.

In JavaScript the control stack will grow, and eventually
you get the error "too much recursion" (wording taking from
FireFox).

So your problem is that you are compiling a language that will (or
should) never cause a stack overflow into one that's only response to
the issue is to stop if recursion goes on for too long (and not all
ECMAScript environments do that (Opera, as I recall, will go on
recursing until it OS runes out of memory).
Exactly.
Supporting Proper Tail Recursion means that an arbitrary number
of tail calls can be active (a call is active, as long as the
callee hasn't returned) using nothing but a bounded amount of space.

A normal strategy to transfer control from one point to another
without growing control context is to use goto. However since
goto is not part of JavaScript, I need to find a construct that
works in a similar way. The switch-example is one solution and
the trampoline is another.

I think the trampoline is going to be your best option. So the next
question should probably be how to implement it in a way that is suited
to the task. for which a much more concrete example may be necessary.
For example, I am unclear as to how your are going to be handling the
variables in original language (their scoping and so on), and arguments
to your function calls in javascript.

I am using flat closures (so assigned to variables are converted to
boxes) represented as JavaScript objects. A reference to local variable
number 2 will be eventually become locals[2] in JavaScript, where locals
is a global JavaScript variable. This is a simple strategy, which
can be improved upon later if neccessary.

I can thus use the switch or the trampoline solution as-is.
If the control points are named, it is possible to omit the array
references:

They are not "array references" they are "property accessors".
Javascript has no array-specific syntax.

The [1,2,3] notation are called array literals in the standard,

OK, that is arguably array-specific.
but I realize that it is nothing but syntactic sugar for
objects. Coming from Scheme it is hard for me to get used to say
"property accessor", when conceptually I am referencing
elements in an array.
function label0 () { document.write(0); return label2;}
function label1 () { document.write(1); return label2;}
function label2 () { document.write(2); return false;}

pc = label0 ();
while (pc=pc()) {}

Globally declared named functions become properties of the javascript
global object so they can be referenced, but still with property
accessors, as members of that object. In a web browser where the
global object is available as a - window - property of the global
object the code would be:-

pc = label0 ();
while (pc=window[pc]()) {}

Actually that is unnecessary, stupid, and will not work. Distracted by
the talk of labels I failed to notice that your functions do not return
strings but instead return function references, so your original is fine
and sticking 'window' in front will break it.

I was also thrown off a bit by the - pc = label0 (); - line. It could
have been - pc = label0; -

Oops. You are right.
(assigning a reference to the function
instead of a result to the first call to the function). Here the outcome
would have been the same, but doing it that way would have allowed the
fist function called to return false and so stop the process after only
one call.


I don't see how that happened. But the - window - reference to the
ECMAScript global object is general to all web browsers (and some other
environments such as W3C standard SVG), it just is not available in all
environments, such as windows scripting host, JScript ASP and probably
stand-alone javascript interpreters.


No, global variables _are_ properties of the global object,

That I knew.
and - window
- is a reference to the global object so the global variable is not
shadowed, it is assigned a new value.

But I hadn't understood this. In the global scope this == this.window.
For an unqualified Identifier the length of scope chain is a factor in
the speed of resolving it to a value or writing a value to it, for a
property accessor the location of the property on the prototype chain of
the object in question is a factor when reading the value (but not when
writing as writing will always assign to the object at the top of the
prototype chain).

Thanks. The standard explains the semantics in the same way, but
I wasn't sure browsers actually implemented variable resolution the
same way. For many programs it ought be possible to do variable
resolution prior to the execution.
 
R

ron.h.hall

I think you are going to be stuck with either this or the switch-case,
and there seems to be much more mileage in your trampoline.

One of the reasons there's more mileage in the trampoline is that the
Javascript "switch" statement is notoriously inefficient, particularly
noticeable the number of case clauses is large. It's not a "branch on
value" type of switch, it's a compare each possibility until a
successful match is found. I like "switch", but I've had to convert to
a trampoline type structure when the overhead became significant.

I think the trampoline is going to be your best option. Agreed.

Globally declared named functions become properties of the javascript
global object so they can be referenced, but still with property
accessors, as members of that object. In a web browser where the
global object is available as a - window - property of the global
object the code would be:-
pc = label0 ();
while (pc=window[pc]()) {}

Actually that is unnecessary, stupid, and will not work.

Don't be so hard on yourself. Vacations (and incarceration, or
whatever the reason for your absence was ;-)) are known to cause small
brain cramps. The references were clear to me, but I missed the
initiation invocation. Perhaps a vacation is in order?

Welcome back!
 
R

Richard Cornford

Jens said:
Richard Cornford wrote:
I think the trampoline is going to be your best option. So the next
question should probably be how to implement it in a way that is
suited to the task. for which a much more concrete example may be
necessary. For example, I am unclear as to how your are going to be
handling the variables in original language (their scoping and so
on), and arguments to your function calls in javascript.

I am using flat closures (so assigned to variables are converted to
boxes) represented as JavaScript objects. A reference to local
variable
number 2 will be eventually become locals[2] in JavaScript, where
locals
is a global JavaScript variable. This is a simple strategy, which
can be improved upon later if neccessary.

I can thus use the switch or the trampoline solution as-is.

You can, but I was wondering whether there may some useful formal
strategies that could be applied here to advantage. For example,
thinking about how yesterday's recursive - sum - function may be handled
without the recession, but with arguments being passed to the function
(in some way/sense) one alternative was:-


/* This function has no formal parameters and is assuming that when
it is called a set of named properties have been assigned to it
(the function object) that it will take as its arguments (and use
as its variables in this case). This becomes too obscure for human
created code but may not be such an issue for machine generated
code:-
*/
function sum(){
if(sum.a1 == 0){
return sum.a2;
}else{
sum.a2 += (sum.a1--);
return sum;
}
};

/* This function is for use with the above function that is expecting
its properties to be its arguments. It must set-up the function
object with the arguments before it calls the function for the first
time:-
*/

function nonRecuseWithArgs(fnc, arg1, arg2, arg3, arg4){
var ret;
fnc.a1 = arg1;
fnc.a2 = arg2;
fnc.a3 = arg3
fnc.a4 = arg4
/* call, and keep calling, the function (fnc) until the
returned value is not a function object:- */
while(typeof (ret = fnc()) == 'function');
return ret;
}
document.write(nonRecuseWithArgs(sum3, 1000, 0)+'<br>');


- which is pretty much how your trampoline example was working, but in
this case with a form of 'argument' to the function calls, and is quite
general as - nonRecuseWithArgs - is not interested in which function it
is passed, whether it gets the same function back from its calls to that
first function, or how many 'arguments' the function(s) are expecting
(so long as it is less than the arbitrary 4 used above).

Thanks. The standard explains the semantics in the same way, but
I wasn't sure browsers actually implemented variable resolution the
same way. For many programs it ought be possible to do variable
resolution prior to the execution.

Because javascript is specified in terms of its behaviour there is
plenty of leeway for complier authors to optimise the execution of the
code; so long as the result appears to behave as specified it does not
matter what it is doing internally. However, two factors get in the way
taking these things too far.

The first is that javascript is distributed as source code and compiled
immediately before it is executed. This means that the time spent
interpreting/compiling the source is a factor in the (user's) perception
of performance. The second is the very dynamic nature of the language.

We have - with -, - eval - and the Function constructor (for good or
ill) and we are loading (importing) code in dribs and drabs (and
possibly executing code from the first import before the browser has
even seen the code in the last). If I can add any arbitrary object to
the scope chain of a function (as I can with - with -) and can add and
remove properties to/from that object (or its prototype(s)) from any
point in the code (including code that has not loaded yet) then I can
shadow (and un-shadow) a variable at any point. This leaves the complier
with little choice but to resolve the variable's Identifier at the point
in the code when it is referenced, or to do quite a lot of work
determining whether the context in question is 'safe' enough to allow
some sort of action to be taken up-front (which comes back to the
question of how much time can be spent compiling the code).

The practical result is that you get the optimisations that are cheep
and easy but nowhere near everything that could be done. And you don't
get the same optimisations in all ECMAScript engines (probably because
what is cheep and easy varies depending on other design decisions).

Richard.
 
R

ron.h.hall

You can, but I was wondering whether there may some useful formal
strategies that could be applied here to advantage. For example,
thinking about how yesterday's recursive - sum - function may be handled
without the recession, but with arguments being passed to the function
(in some way/sense) one alternative was:-

/* This function has no formal parameters and is assuming that when
it is called a set of named properties have been assigned to it
(the function object) that it will take as its arguments (and use
as its variables in this case). This becomes too obscure for human
created code but may not be such an issue for machine generated
code:-
*/
function sum(){
if(sum.a1 == 0){
return sum.a2;
}else{
sum.a2 += (sum.a1--);
return sum;
}

};

/* This function is for use with the above function that is expecting
its properties to be its arguments. It must set-up the function
object with the arguments before it calls the function for the first
time:-
*/

function nonRecuseWithArgs(fnc, arg1, arg2, arg3, arg4){
var ret;
fnc.a1 = arg1;
fnc.a2 = arg2;
fnc.a3 = arg3
fnc.a4 = arg4
/* call, and keep calling, the function (fnc) until the
returned value is not a function object:- */
while(typeof (ret = fnc()) == 'function');
return ret;}

document.write(nonRecuseWithArgs(sum3, 1000, 0)+'<br>');

- which is pretty much how your trampoline example was working, but in
this case with a form of 'argument' to the function calls, and is quite
general as - nonRecuseWithArgs - is not interested in which function it
is passed, whether it gets the same function back from its calls to that
first function, or how many 'arguments' the function(s) are expecting
(so long as it is less than the arbitrary 4 used above).

Perhaps not fully understanding what you're trying to achieve, my
approach would be to use a closure. It seems to me that would be a
much more suitable facility for holding the intermediate values for
repeated non-recursive calls, e.g., such as:

var fncs = function y( n, s ) {
return {
sum : function sum( ) {
return n && ( s += n-- , sum ) ;
},
res : function ( ) {
return s;
}
};
} ( 1000, 0 );

while(fncs.sum()) {}
alert(fncs.res());

It could also be extended to provide more generality and
functionality, as deemed required, without the necessity of
translating arguments to named variables in the process.
 
J

Jens Axel Søgaard

Richard said:
Jens said:
Richard Cornford wrote:
I think the trampoline is going to be your best option. So the next
question should probably be how to implement it in a way that is
suited to the task. for which a much more concrete example may be
necessary. For example, I am unclear as to how your are going to be
handling the variables in original language (their scoping and so
on), and arguments to your function calls in javascript.

I am using flat closures (so assigned to variables are converted to
boxes) represented as JavaScript objects. A reference to local
variable
number 2 will be eventually become locals[2] in JavaScript, where
locals
is a global JavaScript variable. This is a simple strategy, which
can be improved upon later if neccessary.

I can thus use the switch or the trampoline solution as-is.

You can, but I was wondering whether there may some useful formal
strategies that could be applied here to advantage. For example,
thinking about how yesterday's recursive - sum - function may be handled
without the recession, but with arguments being passed to the function
(in some way/sense) one alternative was:-


/* This function has no formal parameters and is assuming that when
it is called a set of named properties have been assigned to it
(the function object) that it will take as its arguments (and use
as its variables in this case). This becomes too obscure for human
created code but may not be such an issue for machine generated
code:-
*/
function sum(){
if(sum.a1 == 0){
return sum.a2;
}else{
sum.a2 += (sum.a1--);
return sum;
}
};

/* This function is for use with the above function that is expecting
its properties to be its arguments. It must set-up the function
object with the arguments before it calls the function for the first
time:-
*/

function nonRecuseWithArgs(fnc, arg1, arg2, arg3, arg4){
var ret;
fnc.a1 = arg1;
fnc.a2 = arg2;
fnc.a3 = arg3
fnc.a4 = arg4
/* call, and keep calling, the function (fnc) until the
returned value is not a function object:- */
while(typeof (ret = fnc()) == 'function');
return ret;
}
document.write(nonRecuseWithArgs(sum3, 1000, 0)+'<br>');

I like the structure of the solution, but it needs a small
modification to avoid a problem with non-tail-calls. The problem
is that the local variables are reused.

Consider this example:

function foo(n) {
if (n<=1) {
document.write("* " +n + "</br>");
return 1;
}else{
document.write( n+" "+foo(n-1)+"<br/>");
return( foo(n-1) );
}
};
foo(3);

There are two recursive calls to foo.
The call in the expression 1+foo(n-1) is not tail recursive.
The call in return( foo(n-1) ) is tail-recursive.

The output of the above is:

* 1
2 1
* 1
3 1
* 1
2 1
* 1

Introducing local variables as properties of the functions
give:

function bar() {
if (bar.n<=1) {
document.write("* " + bar.n + "</br>");
return 1;
}else{
bar.n = bar.n-1;
document.write( "n" +" "+bar()+"<br/>");
bar.n = bar.n-1;
return( bar() );
}
};

bar.n = 3;
bar();

The output is:

* 1
n 1
* 0
n 1
* -1

Allocating new local variables at entry, restores the
behavior of foo:

function baz() {
var n = baz.n;
if (n<=1) {
document.write("* " + n + "</br>");
return 1;
}else{
baz.n = n-1;
document.write( n +" "+baz()+"<br/>");
baz.n = n-1;
return( baz() );
}
};

baz.n = 3;
baz();

Adding the trampoline is now easy:

function trampoline(pc) {
while (typeof (pc) == 'function')
pc = pc();
return pc;
};

function qux() {
var n = qux.n;
if (n<=1) {
document.write("* " + n + "</br>");
return 1;
}else{
qux.n = n-1;
document.write( n +" " + trampoline(qux) + "<br/>");
qux.n = n-1;
return( qux );
}
};

qux.n = 3;
trampoline(qux);

- which is pretty much how your trampoline example was working, but in
this case with a form of 'argument' to the function calls, and is quite
general as - nonRecuseWithArgs - is not interested in which function it
is passed, whether it gets the same function back from its calls to that
first function, or how many 'arguments' the function(s) are expecting
(so long as it is less than the arbitrary 4 used above).

The method seems viable. The idea of the giant switch was to avoid
expensive functions calls, and thus the local variables had to be
held by a global variable. However, if I am forced to use the
trampoline it is worth while to explore alternative solutions.

The next thing to consider is continuation capturing. In the
all-local-variables-are-stored-in-a-global-variable scenario this
is easy to do (since it is easy to determine live local variables).

In the local-variables-are-properties-of-the-function
a general continuation capturing mechanism such as call/cc is harder
to implement. In a straight call to call/cc one can solve the
problem via lexical analysis, but if call/cc is passed around as
a function value, and applied later, then things becomes tricky.

Then again, if the local variables are named l1, ..., ln and
we have a separate property, say, locals_count holding the
number of current local variables, then ... Hmm. This might be
easier than I thought after all.

Actually a hybrid solution might turn out to be the best:
Representing function arguments as above, and keeping the free
variables in a global JavaScript variable.

You have given me food for thought,
Jens Axel Søgaard
 
J

Jens Axel Søgaard

(e-mail address removed) skrev:
Perhaps not fully understanding what you're trying to achieve, my
approach would be to use a closure. It seems to me that would be a
much more suitable facility for holding the intermediate values for
repeated non-recursive calls, e.g., such as:

var fncs = function y( n, s ) {
return {
sum : function sum( ) {
return n && ( s += n-- , sum ) ;
},
res : function ( ) {
return s;
}
};
} ( 1000, 0 );

while(fncs.sum()) {}
alert(fncs.res());

This is nice way to restrict the scope of n and s to
the body of s (and the helper res which belongs to s).

It has the problem is that the local variables are
overwritten in non-tail-recursive calls, but this
could probably be fixed.

The downside of this solution in my situation is the
that creating JavaScript closures are more expensive
than creating ordinary JavaScript objects.
 
R

ron.h.hall

(e-mail address removed) skrev:






This is nice way to restrict the scope of n and s to
the body of s (and the helper res which belongs to s).

Well, actually s is intended to be of type number, so no.
It has the problem is that the local variables are
overwritten in non-tail-recursive calls, but this
could probably be fixed.

As it wasn't intended to be solution for control context constraint
alternative for all recursive functions, and in that it relates
directly to your opening remarks in this thread, that doesn't seem
like a problem under consideration.
The downside of this solution in my situation is the
that creating JavaScript closures are more expensive
than creating ordinary JavaScript objects.

And you reached this conclusion based on what?

I have never looked at the internals of a Javascript implementation,
but it appears to me that Javascript is designed to be implemented in
a prototypal inheritance environment. That would suggest to me, that
in all likelihood, closures are implemented as (internal) objects, and
therefore would be no more expensive to create than an ordinary
Javascript object.

As well, the generation of the closures would be done in an initiation
phase. The "giant switch" alternative you propose is bound to be
inefficient firstly because of its inherent design in Javascript, and
the fact that it would be invoked throughout the execution phase, not
just during initiation.
 
R

Richard Cornford

^
For anyone how noticed; that Identifier should have been - sum -, not -
sum3 -. I wrote a number of variations and this was the third, and I
omitted changing this Identifier when posting this to parallel the
original - sum - function.
I like the structure of the solution, but it needs a small
modification to avoid a problem with non-tail-calls. The problem
is that the local variables are reused.

Yes, I noticed that there would be an issue with this strategy whenever
a function that used it made a call to another function (which might
indirect re-call it) or itself, directly.
Consider this example:

function foo(n) {
if (n<=1) {
document.write("* " +n + "</br>");
return 1;
}else{
document.write( n+" "+foo(n-1)+"<br/>");
return( foo(n-1) );
}
};
foo(3);

There are two recursive calls to foo.
The call in the expression 1+foo(n-1) is not tail recursive.
The call in return( foo(n-1) ) is tail-recursive.

The output of the above is:

* 1
2 1
* 1
3 1
* 1
2 1
* 1

Introducing local variables as properties of the functions
give:

function bar() {
if (bar.n<=1) {
document.write("* " + bar.n + "</br>");
return 1;
}else{
bar.n = bar.n-1;
document.write( "n" +" "+bar()+"<br/>");
bar.n = bar.n-1;
return( bar() );
}
};

bar.n = 3;
bar();

The output is:

* 1
n 1
* 0
n 1
* -1

Allocating new local variables at entry, restores the
behavior of foo:

function baz() {
var n = baz.n;
if (n<=1) {
document.write("* " + n + "</br>");
return 1;
}else{
baz.n = n-1;
document.write( n +" "+baz()+"<br/>");
baz.n = n-1;
return( baz() );
}
};

baz.n = 3;
baz();

This is true, but have you noticed that backing up the properties of the
function to local variables is only relevant in the - else - branch
where - baz - is actually called. Certainly you could have a formal
strategy of passing arguments as properties of the function and then
systematically transferring them to local variables, but you could also
have a strategy where the properties of the function where only
backed-up to local variables if control was to pass out of the function
(prior to calling other functions) and then restoring them once that
function had returned.

function baz() {
var n;
if (baz.n <= 1) {
document.write("* " + baz.n + "</br>");
return 1;
}else{
n = (--baz.n);
document.write( n +" "+baz()+"<br/>");
baz.n = n;
return( baz() );
}
};

(the output is different, but only because the value of - n - is
different in my example due to - baz.n - being decremented once instead
of being assigned the value of (n-1) twice.)

Then there would be the possibility of doing it the other way around; a
function (and so, by implication, all functions) never backs-up its own
properties (except by coincidence) but instead whenever it is going to
call another function it backs up the properties of that function. This
could be formalised into two methods of functions that took, say, an
'empty' object (or array) as an argument, with one method transferring
its 'argument properties onto the object and the other restoring them
form it. So the form would go:-

1. Declare a local variable to refer to the object : var obj;
2. If a function is to be called create and assign the
object : obj = {};
3. Call a method passing in the object : func.backupState(obj);
4. Assign the 'arguments for the call to the properties of the
function to be called.
4. Call the function:
5. Restore the properties from the object : func.resoreState(obj);

- with a general case for each method defined on the -
Function.prototype - and overridden on specific functions where
necessary.

Having written that it occurs to me that the whole lot could be wrapped
up in one prototype method of functions. If the public properties of a
function were always a0, a1, a2 ... an, and the function had a property
called, say, argumentsLength, you could have a prototype method that
took the arguments for the call as real arguments (though not declared
formal parameters):-

Function.prototype.specialCall = function(){
var ret, prop, c, len, ar = [];
/* I suppose this could also be - (len = arguments.length) -
and have the number of arguemnts to the method call
determine the number of function parameters backed-up:-
*/
if((len = this.argumentsLength)){
for(c = 0;c < len;++c){
ar[c] = this[(prop = ('a'+c))];
this[prop] = arguments[c];
}
}
ret = this(); //call the function itself.
if(len){
for(c = 0;c < len;++c){
this[('a'+c)] = ar[c];
}
}
return ret;
};

- and so given a function - func - you would call it as -
func.specialCall(arg1, arg2, etc) - for non-tail recursion and as -
func() - for tail recursion. So - baz - above becomes:-

function baz() {
if (baz.a0 <= 1) {
document.write("* " + baz.a0 + "</br>");
return 1;
}else{
--baz.a0;
document.write( baz.a0 +" "+baz.specialCall((baz.a0))+"<br/>");
return( baz() );
}
};
baz.argumentsLength = 1; //state the number of arguments/parameters.

baz.a0 = 3;
baz();

Now - baz - has no local variable to do the backing-up but instead all
of that goes on inside the function's method and is fully automated.
Adding the trampoline is now easy:

function trampoline(pc) {
while (typeof (pc) == 'function')
pc = pc();
return pc;
};

function qux() {
var n = qux.n;
if (n<=1) {
document.write("* " + n + "</br>");
return 1;
}else{
qux.n = n-1;
document.write( n +" " + trampoline(qux) + "<br/>");
qux.n = n-1;
return( qux );
}
};

qux.n = 3;
trampoline(qux);



The method seems viable. The idea of the giant switch was to
avoid expensive functions calls,

I though it was to avoid stack overflows, which I can entirely
understand given how poorly javascript is specified in the area of stack
overflows, and how unhelpfully they are handled in reality. But given
that javascript is a functional programming language I can see no reason
for avoiding function calls as such.
and thus the local variables had to be
held by a global variable.

I have (there is) a systematic (axiomatic) revulsion at the idea of
using global variable in javascript (or at all). But that is largely a
reaction to the way their over use results in incomprehensible,
un-maintainable code, which is an issue for human authors and probably
not quite the same issue in machine generated code.
However, if I am forced to use the
trampoline it is worth while to explore alternative solutions.

If there is time exploration is often a good idea.
The next thing to consider is continuation capturing. In the
all-local-variables-are-stored-in-a-global-variable scenario this
is easy to do (since it is easy to determine live local variables).

In the local-variables-are-properties-of-the-function
a general continuation capturing mechanism such as call/cc is harder
to implement. In a straight call to call/cc one can solve the
problem via lexical analysis, but if call/cc is passed around as
a function value, and applied later, then things becomes tricky.

Perhaps another situation where coming up with something a bit more
concrete as a starting point may elicit suggestions about how it may be
handled.
Then again, if the local variables are named l1, ..., ln and
we have a separate property, say, locals_count holding the
number of current local variables, then ... Hmm. This might be
easier than I thought after all.

Actually a hybrid solution might turn out to be the best:
Representing function arguments as above, and keeping the free
variables in a global JavaScript variable.

You have given me food for thought,

It is quite refreshing to be having something a little less
run-of-the-mill to talk about on the group.

Richard.
 
R

Richard Cornford

(e-mail address removed) wrote:
On Jul 4, 5:22 am, Jens Axel Søgaard wrote:
The downside of this solution in my situation is the
that creating JavaScript closures are more expensive
than creating ordinary JavaScript objects.

And you reached this conclusion based on what?

I have never looked at the internals of a Javascript implementation,
but it appears to me that Javascript is designed to be implemented in
a prototypal inheritance environment. That would suggest to me, that
in all likelihood, closures are implemented as (internal) objects, and
therefore would be no more expensive to create than an ordinary
Javascript object.
<snip>

I would be inclined to agree, but maybe not for the same reasons. The
objects involved in a closure are the function object, the structure
referred to by its [[Scope]] property and the Variable object for the
execution context in which it was created. The creation of the scope
structure and the Variable object are implied in all function calls so
the effect of forming a closure may be no more than that these objects
that would be created anyway are just not garbage collected following
their use. So all the costs of closures would be in the ongoing memory
consumption needed to accommodate the required objects/structures.

Now there may be implementations where knowing that no closure could be
formed in some contexts allowed optimisations to be applied that could
not be applied where they are created, and so the closures would be more
'expensive' in that environment. But as javascript environments appear
to apply different optimisations, and we are writing code to be exposed
to many different javascript environments (even when restricting
ourselves to web browser-provided environments) we cannot write code
based upon the knowledge (assuming such knowledge) that one particular
environment behaves on one particular whey internally, because the odds
are very good that every step in that direction will be positively
counter-productive in the next environment, or the one after that.

Richard.
 
R

Richard Cornford

(e-mail address removed) wrote:
You can, but I was wondering whether there may some useful formal
strategies that could be applied here to advantage. ...
<snip>
Perhaps not fully understanding what you're trying to achieve, my
approach would be to use a closure.
<snip>

I did consider a variation using closures, but I could not see any great
advantage in encapsulating the variables, and did see some potential
advantages in having them externally accessible in the context of the
original question.

Richard.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top