lua-users home
lua-l archive

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


Reuben Thomas escribió:

> > newtable = {}
> > for k, v in table do
> >   newtable[k] = v
> > end

> Indeed, and then I want to say

> settag(newtable, tag(table))

> > but you can't because the iteration doesn't work on your table-objects.
> > (At least, that is a problem I run into occasionally.)

> My problem was simply that the above settag is illegal if the table is a
> vanilla one.

Ah, yes, I see the problem. A simple workaround is to never use vanilla
tables.
Make any object table a table with a specific tag, which has no tag
methods. This
only slows things down a tiny bit. Alternatively, you could say:

  if tag(table) ~= tag({}) then settag(newtable, tag(table))

but it would certainly make sense if settag silently did nothing if the tag
was
already what you were trying to set it to.

> How do you make (in Lua) a table type on which foreach
> doesn't work?

The same way I illustrated for making tables for which rawget doesn't work,
I suppose. Why would you want to do that? My interest is in making table
types for which foreach *does* work -- in accordance with the table type.

> > I'm putting together a little library with stuff like this in it, as a
> > sort of tutorial on tag-methods. If you're interested, I could e-mail
> > you a draft.

> Yes, that'd be interesting.

OK, it's at home, of course; I'll try to send it off on Monday.

> >   -- set up keys
> >   return settag(self, %mytag)

> This is precisely the idiom I find confusing. What does the function
> return: the table or the tag? Of course, it's fine once you know...

Well, which order do the arguments go in? Do you have to look that up every
time?

Object functions should always return self if they have nothing better to
return, and self is always the first argument. So that's not hard to
remember. That's not a C-ism; you could say that it's a Smalltalk-ism but I
think it was around as a convention even earlier than Smalltalk. The reason
is that you might want to send the object another message, so returning the
object allows you to chain messages in a readable fashion. At least, most
of us find it readable :-)

Here's another mnemonic: which of the arguments has changed? Obviously not
the tag. But is it guaranteed that the table returned by settag will be the
same table as you gave it? That is, are you *assuming* that this will work:

  a = {theAnswer = 42}
  b = makeOracular(a)
  -- that is, b = settag(a, oracularTag)
  print(a.theQuestion)

It will work, in the current version of Lua, given that the definition of
makeOracular is the indicated settag. But should the definition of the
language say that this is guaranteed to be the case? Or, more importantly,
should your library always guarantee to return the same object,
oracularised? That might not be possible, since the argument might not be a
vanilla table. Really, makeOracular should be implemented as something
like:

  function makeOracular(self)
    if not self then
      self = {}
    elseif tag(self) ~= tag({}) then
      self = CopyAsTable(self)
    end
    -- do whatever it takes to make an oracle
    return settag(self, oracularTag)
  end

That's just an illustration, of course. There are many ways to do this sort
of thing. I tend to use the prototype

  function makeOracular(...)

instead of allowing the caller to give me an explicit table. Alternatively,
one could argue that makeOracular *always* ought to copy its argument, so
that the prototype would correctly be written:

  function makeOracular(other)
    self = other and CopyAsTable(other) or {}
    ...
  end

R.