So now to test if you have understood, consider this piece of code: fun f (var x:int) (y:int) => x + y;
var a : (int -> int)^5; for var i in 0 upto 4 do a.i = f i; done var y = 100; for i in 0 upto 4 do println$ a.i y; done Here we make an array of closures, then apply each later to the value. note x is a var, so eager evaluation. ~/felix>build/release/host/bin/flx --test=build/release ac 104 104 104 104 104 What, I though you said eager evaluation! That's using the last value of i! That's not eager evaluation! Yes, it is. Let me prove it: fun f (var x:int) (y:int) => x + y; var a : (int -> int)^5; for var i in 0 upto 4 do var k = i; a.i = f k; ++k; done var y = 100; for i in 0 upto 4 do println$ a.i y; done ~/felix>build/release/host/bin/flx --test=build/release ac 104 104 104 104 104 See? k got incremented, but we didn't get a row of 105's did we?? Lets try this (note the x parameter): fun f (x:int) (y:int) => x + y; var a : (int -> int)^5; for var i in 0 upto 4 do var k = i; a.i = f k; ++k; done var y = 100; for i in 0 upto 4 do println$ a.i y; done ~/felix>build/release/host/bin/flx --test=build/release ac 105 105 105 105 105 See? Now we have lazy evaluation. It's clear what is happening: the application f k is inlined, and in the first (var) case it says: var x = k; a .i = fun (y:int) => x + y; and in the val case it is saying a.i = fun (y:int) => k + y; which is lazy. So finally lets look at this: noinline fun f (x:int) (y:int) => x + y; var a : (int -> int)^5; for var i in 0 upto 4 do var k = i; a.i = f k; ++k; done var y = 100; for i in 0 upto 4 do println$ a.i y; done ~/felix>build/release/host/bin/flx --test=build/release ac 100 101 102 103 104 Even though x is a val here, f is a closure because it's marked noinline. The problem here is quite clear, without the noinline, f is inlined, and even though it uses eager evaluation, it evaluates the parameter to i. But then the closure which is ACTUALLY created is referring to the x inlined into the loop. There's only one x in the loop. It holds the value before the closure was created but it isn't an argument to the closure, and the next iteration, x gets a new value. Since all the actual closure just say: fun closure (y:int) => x + y; they all use the same value of x, since the x they're using is the one when the closure is called, which has value 4. The issue here is quite clear: there are 5 closures with 5 copies of y but there's only one copy of x because of the inlining. The "var" is clearly causing eager evaluation. But it doesn't change the fact the closure produced is bound to a single x variable in its context. The x is NOT an argument of the closure. To force a unique copy of x, we make f noinline so even the application f k is the application of a closure f. I really don't like this, but I don't see an alternative. A variable is intrinsically a constant machine address of a storage slot. When you use its name in a r-context you get the current value of the variable store in the slot. The only way to get distinct values is create distinct slots. -- john skaller skal...@users.sourceforge.net http://felix-lang.org ------------------------------------------------------------------------------ Subversion Kills Productivity. Get off Subversion & Make the Move to Perforce. With Perforce, you get hassle-free workflows. Merge that actually works. Faster operations. Version large binaries. Built-in WAN optimization and the freedom to use Git, Perforce or both. Make the move to Perforce. http://pubads.g.doubleclick.net/gampad/clk?id=122218951&iu=/4140/ostg.clktrk _______________________________________________ Felix-language mailing list Felix-language@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/felix-language