lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]

Eike Decker wrote:
> Another pitfall is the variable scoping, which is horrible in JavaScript:

It's not *horrible* as such. It's just *really different*. One of my pet
peeves with Javascript is that it lies to you; the syntax makes it look
like an algol-alike, and it's nothing like that under the hood. In
particular, var variables are always *function scoped*, not block
scoped. var declarations are always hoisted to the head of the function. So:

> function valueofx () {
>   alert(x);
> }
> var x = 4;
> valueofx(); // 4 because it's treated as:

var x
function valueofx() {
x = 4


> var funcs = [];
> for (var i=0;i<10;i++) funcs[i] = function(){return i;};


var i
var funcs = [];
for (i=0;i<10;i++) funcs[i] = function(){return i;};

The really unpleasant scoping issue is with(), which allows to user to
insert an arbitrary object into the top of the scope stack.

a = {}
with (a) { x=1 }
assert(a.x == 1)

...which, of course, completely blows away any chance of doing lexically
scoped variables inside the with() block!

Luckily they've realised that var variables are vile, and the newer
Javascript specs have introduced proper lexically scoped variables via
the let keyword. I don't know of any real-life Javascript
implementations that implement it yet.

> In JavaScript, this is a bit different - and I haven't yet understood it
> completely - it seems to me like there are special cases I haven't yet
> figured out (or it works differently).

'this' is treated as a hidden function parameter that is passed in *by
the caller*. There are three cases:

foo()                  -> foo(this)              ->
new foo()              -> temp = {}; foo(temp); return temp

The second case here is a pig, because:              ->
(            ->; a()         -> foo(this)             // !!!!

> I think JavaScript has some concepts in common - but some things are
> quite different.

In fact, the *semantics* look relatively manageable (using Lua
metatables and some really foul code-generation hacks). What I'm finding
is that the most significant issue is that the app is using a
significant number of continues, multilevel breaks etc, and Lua with its
single 'break' keyword doesn't support any of that. There's a limit to
how much I can rearrange the code, and when I have stuff like:

label: while()
                break label;

...converting it into Lua is rather harder than it first appears. This
would be <hobbyhorse> yet another classic example of why languages
should have a 'goto' statement </hobbyhorse>.

I'm dynamically generating my code, which is why changing the order is
tougher than it looks. If I'm going to have to start emitting code in a
different order, I'm actually wondering whether it might be better to
start producing code like this:

function basicblock1(a, b, c)
  if a then return basicblock2(a, b, c) else
    return basicblock3(a, b, c) end

function basicblock2(a, b, c)
  return basicblock1(a, b, c)

Here I'm using tail calling as a form of sanitised goto, passing control
from one basic block to another. This frees me completely from the need
to convert the code structure to something that will fit Lua, but at the
expense of quite a lot of overhead. How much overhead *is* a tail call
in Lua, anyway? What about in LuaJIT, where I'd imagine the trace
recorder should do a good job at making most of it go away? Would I be
better off creating closures and using upvalues instead of passing all
my parameters into every function?

┌─── ───── ─────
│ "People who think they know everything really annoy those of us who
│ know we don't." --- Bjarne Stroustrup

Attachment: signature.asc
Description: OpenPGP digital signature