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

• Subject: Re: [ANN] Penlight Libraries, First release
• From: steve donovan <steve.j.donovan@...>
• Date: Tue, 12 May 2009 08:46:10 +0200

```On Tue, May 12, 2009 at 5:30 AM, David Manura <dm.lua@math2.org> wrote:
> The relationship between table, tablex and List could be made more clear.

This is true; tablex and List have different historical origins, which
is a less than compelling reason for difference.

> At first glance List appears intended as an ADT with a private
> implementation, whereas tablex is a table of functions that can be
> called on raw tables.  In practice, a list is merely a table with its
> metatable set to List, which itself is a table of functions that
> operate on raw tables.  In fact, calling List:new, doesn't necessarily
> create a new object but may may return the originally provided table
> after altering its metatable.

That is in fact the intention, just to provide a set of convenient
operations borrowed from the Python built-in list type, but otherwise,
just a table.  A true ADT would reduce interoperability, and probably
be slower as well.  In particular, there is no reason why the table
cannot have a map-like part, just that these operations do not operate
on it.  I got bitten by this by trying something clever, so that one
could say List{'one','two'}:upper(), i.e. the mapmethod trick used in
the sequence-wrapper pattern I was discussing. Well, it was a disaster
- suddenly one couldn't expect that 'list is just a table' and the
expected semantics were broken.

In similar manner, a table could have
> its metatable set instead to tablex.  This begs the question of why
> List ~= tablex.  List and tablex are not so different in abstraction
> level as they first appear.

> A main difference I see between tablex and List is that tablex
> operations return a new list (immutable), whereas List operations
> operate in-place (mutable).

But it turns out (as Flemming Masden has suggested) to be very
convenient for list operations to always return their self, to allow
for method chaining (for instance, sort())  The only gotcha would be
that the expression 'l1 = l2:sort()' then creates the expectation that
l1 and l2 are indeed different lists.

> Another difference is that the List function table only includes
> operations on the array part of a table (inspired by thinking in terms
> of a list ADT or the Python data type), wheres tablex includes some
> functions that operate on the array part and some functions that also
> operate on the hash part.  This in effect precludes mutable hash part
> operations.

A good point.  Perhaps to create another metatable, Map, which is used
to wrap the output of tablex functions when they return a map-like
table. This would apply to things like tablex.count_map and also to
List.partition. One could then define an appropriate interface for Map
(at least, keys(), values() and size())

> The recent change to pass the table as the second argument to tablex
> functions goes against the design of the table standard library.

This is true; mostly for the exceptions like map() and reduce().

> I would be tempted
> to use the hash part of a List--after all, existing List operations
> operate in-place and ignore the hash part.

I have gone beyond that temptation; it seems fine to me in practice.

But then we have the question: what is lua-ish? It is a multiparadigm
language (to use a buzzword) and supports the OOP style perfectly
well.  That being said, lists are not compulsory.  As you point out,
List and tablex aren't fundamentally different, just different
interfaces to similar functionality.

> tablex_immutable is perhaps unnecessary.
> tablex_immutable(t):filter(f):map(g) can instead be written more
> generally and more efficiently, and maybe more clearly, as
> tablex(t):copy():filter(f):map(g).

True, but this does not feel like a compelling reason to spell 'List'
as 'tablex'

steve d.

```