lua-users home
lua-l archive

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


On Tue, Feb 21, 2012 at 3:47 PM, Axel Kittenberger <axkibe@gmail.com> wrote:

> Immutable, but with lazy evaluation would be my ideal (that is some
> values are calculated only when needed, but stored as cache. But since
> the table is immutable, and the function obviously should not depend
> on side-effects, the result is constant as well).

I see two interesting and broadly applicable patterns, and I'd
probably use them both if I had them close at hand:

Immutable tables: ft = final{k=2}

"final" is not the best word but I've clearly done too much Java
programming lately. This can't just set a metatable on its input; it
must create a new empty proxy. Have I mentioned lately how much I miss
Lua 4.0's "intercept everything" semantics?

Memoizing final tables: mft = lazy_final(m, {k=2})

where m is a table of pure functions on the underlying table t. Let's
imagine we trust them not to scribble on t's state; the implementation
is then pretty simple. Start with the final proxy's metatable. Set
__index such that if t[k] does not exist, m[k](t) is called and its
value is stored in t. So you'd have function m:double_k() return
self.k*2 end. If you write mutually recursive functions, well, you
lose.

Again, the mft itself must stay empty because we don't want people
blundering along and setting mft.double_k = 7, so all mft[k] involve
an __index call. Have I mentioned lately how much I...oh, I have.

To make (non-checking) factories, Point = bind1(lazy_final, m).

So Lua 5.2 finally fixes the pairs/ipairs problem for final tables,
but there are not good semantics for the memoizing final table. You
can

  a) loop over whatever values have been memoized,
  b) remember your initializer, and only iterate over those, or
  c) force the evaluation of everything remaining in m so you can
return the key/value pair.

Choices a) and b) are JavaScript hell, which leaves c). In the
presence of a lot of lazy tables, you'd probably want a keys(t)--or
better, lazypairs(t) returning k,nil for functions not yet evaluated.

> Anyway, I'm just restructering a larger project into immutables,
> because I had a long debug session, because I did something in a loop,
> that did something, which effected something, which changed the array
> the loop was running over. Of course it's easy to make a copy of it,
> before looping over it, but that highlights only the other problem I
> had, I had to make copies of everything all the time, because the
> caller might change it later on, or the callee might change it, or
> something else might change it.

This is why I had shallow_copy on my shortlist of common functions. I
don't trust other people's code to have obeyed my mental invariants,
and I've forgotten so much of my own code I don't trust it much
either.

Jay