Just thought to throw some info in here for no reason.

The way Felix implements closures is non-obvious and not efficient
for a subtle reason. When you do this:

fun f(x:int)=>x;
var g = f;
println$ g1;

Felix create an object of C++ class f on the heap, and stores a pointer
to it in variable g. It has a method 

        int f::apply(int x) { return x; }

so when you do the println, Felix calls

        g->apply(1)

right? 

Wrong. Felix calls this:

        g->clone()->apply(1)

Here clone() says:

        return new f(*this);

which creates a self-copy on the heap using the copy constructor,
and returns a pointer to this new object.

This ensures that we always have a virgin function when we call the apply 
method.

The question is why bother? After all, unlike procedures, functions are invoked 
immediately
calling the apply method, which pushes the return value on the stack. The only 
advantage
of the clone() call is that Felix values that didn't get initialised explicitly 
retain their C++
default constructor values, rather than the last value that happened to be 
assigned to them.
Right?

WRONG. (You knew that was coming, eh?)

In the example above, there's no reason to clone() the function. 
Well, what about recursive functions? Wouldn't it be bad if a recursion
got a dirty, half initialised object?

fun f(x:int) => if x == 1 then 1 else x * f (x-1) endif;

Well .. no. You see, this is implemented by calling 

        x * (new (stuff) f)->apply(x-1)

so it created a new object, because the call to f here is a direct call, so the 
closure object (new thing) is created "on the fly". So we actually get a stack
of closures, no problem.

And you see, that's the key to the problem. Read again "direct call".
Now suppose it is an *indirect call*:

fun f(x:int) => if x == 1 then 1 else x * g (x-1) endif;
var g = f;

Now, you can see that f is calling g, but an f object is stored in g.
So half way through executing the f stored in g, g is reused.
In this case probably little harm, but a more complex function ..
well the local variables would be destroyed (remember, the
return address goes on the machine stack so that's safe).

So that's why the object is cloned: to ensure each invocation uses
a fresh "stack frame".

So, what's a generator? 

Answer: its a function where

        clone() { return this; }

i.e. the frame isn't cloned, by a trivial hack to the generated code.
So the state is preserved between calls.


 
--
john skaller
skal...@users.sourceforge.net
http://felix-lang.org




------------------------------------------------------------------------------
Live Security Virtual Conference
Exclusive live event will cover all the ways today's security and 
threat landscape has changed and how IT managers can respond. Discussions 
will include endpoint security, mobile security and the latest in malware 
threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________
Felix-language mailing list
Felix-language@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/felix-language

Reply via email to