lua-users home
lua-l archive

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

On 20-Aug-04, at 9:25 AM, Roberto Ierusalimschy wrote:

In my view, tuples are a *big* change to the language, no matter the
size of its implementation (which is "an implementation detail", after

I personally have no problem with discussing implementation details :)

But let me be clear: the tuple proposal I made does not introduce a new datatype. The datatype already exists: tuples are simply a function closure.
The proposed syntactic changes simply allow a conventient way to create
them. So I don't see it as a major change.

The ... syntax, on the other hand, creates an odd sort of pseudo-datatype
which is not a first-class object at all, but seems to require various
methods: count number of elements, slice (or some such), perhaps iterate, etc.

My intuitive objection to ... is that it is not a first-class object, and
so it seems to me inelegant. It doesn't really make the language more
expressive, so as far as I can see it's only point is to make one particular operation more efficient. Since tuples-as-functions do a reasonable job of optimising that particular operation, I see them as a plausible alternative which has the advantage of not introducing a new concept into the language.

That change would add lots of complexity to the language, at least
"hidden" complexity. As soon as we decided to add tuples to Lua, lots of other decisions would follow, with lots of discussions for each of those

Adding tuples as an official datatype, different from function closures,
would raise these issues. I think immutable tuples with equality-by-value
comparison would be a useful addition to the language, and I think some
discussion on this might be helpful. But I am not proposing it at this
time. Nonetheless, let me try to answer some of the questions.

 Among others (without much thinking): are tuples immutable?

Mutable collections already exist in the form of tables. So the only reason
to introduce a new datatype would be to take advantage of immutability.
Immutable vectors already exist in the language, but are restricted to
vectors of octets; in that sense, an immutable tuple could be seen as
a generalisation of (a different) existing datatype.

if so, how should be the semantics of tupple equality?

Immutable objects should be compared by value, I believe. This would be
a key advantage of immutable tuples. For example, it would allow their use as table keys. Currently, the only way to use a complex object as a table
key (in this sense) is to serialise it into a character string, which is
quite awkward. As an example, implementing the LALR construction algorithm
requires tables whose keys are essentially pairs of <state, item>.

Do tuples have metatables? Why not?

Do functions have metatables? No. Why not? I don't know. Should they?
Well, it would be useful from time to time, but I don't know that it is
a big deal. It would be nice to have some way to define binary operators on
functions (compose, for example), but I've lived without it so far.
It might be nice to be able to __index or even __newindex a function, but
you can (almost) always wrap it into a table to do that.

Should we have a "foreach" function for tuples? A "pair" iterator?

If there is some way of getting the length of the tuple, these are
very easy to write in Lua. A new tuple datatype would probably have some
primitive or library function which returned its length; but the
tuple-as-function implementation relies on the tuple function; one possibility
would be the following tuple-function:

  tuple()       -- returns all values
  tuple(j[, k]) -- returns the slice starting with j (default 1) and
                   and continuing to k (default end)
tuple(true) -- special case, returns length of tuple. (Could be tuple(0))

Then the implementations of tuple.foreach and tuple.ipairs are quite

However, I don't actually like "returns the length of the tuple". A better interface, imho, would be one which tells you whether the tuple was at least
a particular length. Just a matter of taste, though.

Weak tuples?

If tuples are immutable, weak tuples are semantically questionable. Two tuples might suddenly become equal-by-value because different object members became unreachable and were turned into nil. Again, tables provide this functionality.

Each of these subjects (and many many
others) would eventually emerge in the list; several times, probably.

Debate is good, no?

If the argument about efficiency is valid (the one about three
allocations versus one), I don't see why we cannot simply implement
tables more efficiently for those particular uses. First, as long as we
do not use a ".n" field, we are down to two allocations. (Would that
simple change give a 1/3 speedup?) Second, we could allocate tables with
a variable tail where it would keep its original array part (the one
specified in its constructor, if smaller than some [small] limit). That
would be enough to use only one block for those tables. (The main point
here is: how frequently we add new integer indices to tables created
with list constructors?)

All very true. I think tables could be optimised even more... but of course it is possible that such optimisations would be counterproductive in other

About the "... hack", I do not see it as a hack at all (but of course
this is a matter of taste). It is a local change to the language, and it
solves at least two problems: it allows an easy way to pass parameters
to main chunks and it eliminates the magic name "arg" (or is it "args"?
I can't remember ;).

Indeed, it is a matter of taste. And of course it is your taste which is
most important.

I don't see passing parameters to main chunks being particular difficult now; the only issue is that it is a trifle inefficient. And personally, I would
prefer a syntax which allows for named varargs, which is why I proposed:

  function foo(a, b, [rest])

Of course, if rest were going to be a vararg-table-as-currently-implemented,
that should be:

  function foo(a, b, {rest})

Extending that to assignment statements is a very small step (and actually
quite easy to implement in 5.0.2, at least.)