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