lua-users home
lua-l archive

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


John McKenna escribió:

(Quoting Peter Shook)
> >I look at lexically scoped and eventtable and I think "WOW, that's
> >great. That will fix a whole bunch of nasty things in my code."  I look
> >at false and I thing "What for?".  I guess false just isn't that useful
> >for me.  I just hope you don't go and add 0, "0" and "" to the list of
> >false values.

I agree with Peter here

> The problem that false is there to solve is that nil is currently trying
> to be two very different things - "false" and "doesn't exist".

Yes. The question is whether it is the right solution, since it is often
not
necessary to solve it.

> Let's say you have a very lengthy computation that returns either "true"
> or "false".  Since it takes such a long time to compute, you decide to
> cache the results in a table.  Look up the parameter in the table - if
> you get nil, then either you've already done the calculation and the
> answer was "false", or you haven't done the calculation yet.

function memoise(fn)
  local false = {}
  local memotag = newtag()

  local getter = function(t, k)
    local rv = rawget(t, k)
    return rv ~= %false and rv
  end

  local indexer = function(t, k)
    local val = %fn(k)
    t[k] = val or %false
    return val
  end

  local caller = function(t, k)
    return t[k]
  end

  settagmethod(memotag, "gettable", getter)
  settagmethod(memotag, "index", indexer)
  settagmethod(memotag, "function", caller)

  return settag({}, memotag)
end

If you know the memoised function really only returns true or false, there
is a
slightly simpler solution, but I find the above quite useful. It's possible
to
avoid the call to rawget in getter with a second level of indirection.
There is
also a solution for functions which might accept nil as an argument.

Memoising functions of more than one argument is a lot trickier, but that
wasn't
your question.

> Or maybe you're implementing an object system with inheritance.  If a
> field isn't in the child's member table, then look it up in the parent.
> How do you store "false"?

The above model works for this, too. I've really got to get around to
posting
my standard tag method library.

> Or there's Markus Huber's example: you want default values for function
> parameters.  If the function gets nil for that parameter, then it can't
> tell if the parameter was missing, or if the caller is trying to pass
> "false".

Define the global false={} and test for its existence. If that doesn't
appeal
to you, use the following:

function with_optional_second_argument(a, ...)
  local b = default
  if arg.n ~= 0 then b = arg[1] end
  -- do whatever you wanted to do
end

> Introducing a real false value means that nil can be "doesn't exist",
> and nothing else.  It eliminates a lot of ambiguity.

But it also creates an often unnecessary differentiation. I'd rather work
around the ambiguity when I recognise it.

Rici