lua-users home
lua-l archive

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


On Fri, Nov 18, 2011 at 9:01 PM, William C. Bubel <wcbubel@gmail.com> wrote:
>>     On 11/18/2011 11:41 AM, GrayFace wrote:
>>     > What I don't like about 5.2 is that 5.1 is cleaner in many ways. ...
>>     > function definitions always produce a new function
> This seems like a reasonable optimization. Is there a hidden gotcha that
> GrayFace is concerned with that I'm not seeing? I suppose if you were
> doing equality checks between functions to determine object identity,
> you would get tripped up, but I was under the impression that tables
> were the golden standard for objects.

In one of my modules I was using `return function()end` to generate
new unique keys for a table.  I probably did that rather than `return
{}` because it takes a little less memory [1] and the value is more
opaque/immutable, not that it really mattered either way, but why not?
 That code failed in 5.2 testing though.  So I changed it to `local x;
return function() x=nil end` because I saw that on the list.  That's
less comprehensible.  Moreover, in retrospect, although it worked, I'm
not so sure it's even correct.  Although the implementation of Lua
5.2.0-beta does not presently optimize that by caching the closure,
the sections on this from the 5.2.0-beta manual suggest that
implementations might be allowed to:

  "[3.4.3 – Relational Operators] Closures with the same reference are
always equal. Closures with any detectable difference (different
behavior, different definition) are always different."
  "[Changes in the Language] Equality between function values has
changed. Now, a function definition may not create a new value; it may
reuse some previous value if there is no observable difference to the
new function."

I see no "detectable difference", so I infer that my code was wrong,
and thankfully so since writing `return {}` or `return newproxy()` is
more readable (or just using integer keys is the most efficient).
`newproxy()`, which has some slight advantages similar to
`function()end`, is not a standard function in 5.2.0-beta though, so
'{}' would probably be it.


One case I would want to optimize, but where the 5.2.0-beta
implementation does not (but according to the reference manual
apparently could) is where upvalues are constants:

  function f(n)
    local pi = 4  -- approximately
    local function area(r) return pi*r^2 end
    local function perimeter(r) return 2*pi*r end
    for i=1,n do print(area(i), perimeter(i)) end
  end

Another case is where an anonymous closure is immediately consumed by a call:

  local x = 0
  for i=1,1E+7 do
    x = x + (function() local y = i^2; return y/(y+1) end)()
  end
  print(x)

In that last example, it's not necessary safe to reuse the closure as
is, but it would seem valid for an implementation to optimize the code
by first automatically rewriting it as

  local x = 0
  for i=1,1E+7 do
    x = x + (function(i) local y = i^2; return y/(y+1) end)(i)
  end
  print(x)

which does permit reuse of the closure (and in 5.2.0beta is twice as fast).

So, the 5.2 semantics appear to permit greater room for optimization,
though the current standard implementation does not take full
advantage of it.

[1] http://www.wowwiki.com/Lua_object_memory_sizes