getn

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

getn

Nick Trout-2
Is there any chance that the table entry used to store the number of elements,
ie. n, can be renamed to something less likely to cause a name clash with user
code?

eg. _n or __n__


getn (table)
Returns the ``size'' of a table, when seen as a list. If the table has an n
field with a numeric value, this value is the ``size'' of the table. Otherwise,
the ``size'' is the largest numerical index with a non-nil value in the table.
This function could be defined in Lua:
       function getn (t)
         if type(t.n) == "number" then return t.n end
         local max = 0
         for i, _ in t do
           if type(i) == "number" and i>max then max=i end
         end
         return max
       end


Nick

---
Criminal: A person with predatory instincts who has not sufficient capital to
form a corporation.
 - Howard Scott




Reply | Threaded
Open this post in threaded view
|

RE: getn

John Passaniti-4
> Is there any chance that the table entry used to
> store the number of elements, ie. n, can be
> renamed to something less likely to cause a name
> clash with user code?
>
> eg. _n or __n__

How about not giving it a name at all, but rather making it a hidden
property of a table?  Then, if you want to get to the value, one would call
a function like getn(table).  I wonder how much existing code that would
break-- that is, how many people use table.n as a rough synonym for getn()?

No matter what name you pick, *someone* will eventually toss data in a table
that's the same name as this variable.  I love Lua, but this is one of my
pet peeves of the language.  The size of a table should be an intrinsic
property of the table-- not a member of the table.  I can see the value of
making it optional-- but not the value of making it a member.


Reply | Threaded
Open this post in threaded view
|

RE: getn

Reuben Thomas-4
> How about not giving it a name at all, but rather making it a hidden
> property of a table?  Then, if you want to get to the value, one would call
> a function like getn(table).  I wonder how much existing code that would
> break-- that is, how many people use table.n as a rough synonym for getn()?

I sometimes do, but I don't think there's any good reason to except when
you want to set it; you could always add setn(t, e), but this seems too
much like adding a special case.

> No matter what name you pick, *someone* will eventually toss data in a table
> that's the same name as this variable.  I love Lua, but this is one of my
> pet peeves of the language.  The size of a table should be an intrinsic
> property of the table-- not a member of the table.  I can see the value of
> making it optional-- but not the value of making it a member.

It'd be nicer though if this could be a property just like any other in an
object-oriented way, as it pretty much is at the moment, and not a "magic"
property as you seem to be proposing. I'm not sure what the answer is;
there's a tension between the use of tables as objects and as simple
tables.

I think that if you're likely to want a key called "n", then you shouldn't
be putting it in a getn-able table (which is generally a list). It's
sometimes nice to be able to put a list and other elements in the same
table, but unnecessary.

What would be nice is some way of protecting objects a bit, so you
couldn't overwrite an n field by mistake. Then, you would have to use
accessor methods to get at the underlying fields.


Reply | Threaded
Open this post in threaded view
|

Re: getn

RLak-2
In reply to this post by John Passaniti-4
But the "n" is not the size of the table. It's a key in a particular type of
table which is used to provide the functionality of vectors.

The specification of that type of table is somewhat incomplete; it does not say
whether non-integer keys will be tolerated or perhaps used in an
implementation-dependent way. Although I too have been guilty of combining
vectors and other information in tables, it's probably not good programming
style.

The actual implementation does not handle non-integer keys or negative keys in
an intuitive way. If there is no key "n" in the table, getn returns the integer
cast of the largest non-negative numeric key in the table.

    Lua 4.0  Copyright (C) 1994-2000 TeCGraf, PUC-Rio
    > t = {3, 4; [99.7]=2}
    > print(getn(t))
    99
    >

I don't regard this as a bug, though. The table t in the above example is an
incorrectly formed vector.

Good programming style probably would be to limit yourself to the vector
primitives (tinsert, tremove, etc.) when using vectors.

It is an interesting fact that "n" is simply a key with a value. It provides the
interesting ability to "shrink" a vector by setting the key "n" to some value,
and later "expand" the vector back to its original values. That ability does
seem to be guaranteed by the language specification.

If you want to hide all the implementation details of vectors, write a
class-wrapper around the Lua implementation.

Just my S/0.02

Rici
-----------

P.S.

The lack of a primitive which actually tells you the size of a table is a little
annoying, but it is easy enough to define:

function howmany(t)
  local i = 0
  for k, v in t do i = i + 1 end
  return i
end


John Passaniti wrote:

> > Is there any chance that the table entry used to
> > store the number of elements, ie. n, can be
> > renamed to something less likely to cause a name
> > clash with user code?
> >
> > eg. _n or __n__
>
> How about not giving it a name at all, but rather making it a hidden
> property of a table?  Then, if you want to get to the value, one would call
> a function like getn(table).  I wonder how much existing code that would
> break-- that is, how many people use table.n as a rough synonym for getn()?
>
> No matter what name you pick, *someone* will eventually toss data in a table
> that's the same name as this variable.  I love Lua, but this is one of my
> pet peeves of the language.  The size of a table should be an intrinsic
> property of the table-- not a member of the table.  I can see the value of
> making it optional-- but not the value of making it a member.


Reply | Threaded
Open this post in threaded view
|

RE: getn

Luiz Carlos de Castro Silveira Filho
In reply to this post by Nick Trout-2
> But the "n" is not the size of the table. It's a key in a
> particular type of
> table which is used to provide the functionality of vectors.



The computation time saved by the usage of this .n field in my programs is surely much less than the time that it took me to
discover some very-hard-to-find bugs caused by this field.

I believe that everyone would agree that it would be better if this .n field wasn't there. (If I remember correctly, the only
purpose of a .n field was to speed up the insertion operation, wasn't it?)

I don't know too much about garbage collection issues, but a nearly perfect solution would be if these 3 functions could share a
table. Something like this:

N_TABLE = {}
function getn(t)
	if (N_TABLE[t] == nil) then
		N_TABLE[t] = count_elements(t)
	end
	return N_TABLE[t]
end

and equivalent for tinsert and tremove.


Possibly, to ease flexibility, another function might have to be introduced: setn(t)

The question is: none of the tables stored in the N_TABLE could be collected, could them?


Reply | Threaded
Open this post in threaded view
|

Re: getn

RLak-2
In 4.1 you can use tables with weak keys to memoise functions of arbitrary objects (this would be an example of a memoised function,
albeit not strictly a function in the functional programming sense). I think that's a highly appropriate use of weak tables.

However, in 4.0 this facility doesn't exist, so your only alternative would be to write it in C using weak references. If you were
going to do that, you could write your own vector type (it's easy enough if you don't worry too much about garbage collection
problems -- unfortunately, there is no way that a userdata can participate in Lua garbage collection. Well, that's not true -- I
have a proposed solution -- but out of the box and compliant with the published API there's no way of doing it.) Putting glue around
your vectors is probably a better idea.

I banged up a little example of that, if anyone wants to see it. I left it at <http://lua-users.org/wiki/VectorGlue>

The thing to remember is that Lua doesn't have lists (or vectors). It has tables. You can emulate a list (or vector) using a table
with restricted keys. As in any implementation of a vector, you need somewhere to put the size of the vector, and since the building
block of Lua is tables, they use a key.

I still think that putting non-integer keys in a table emulating a vector is poor programming style (although I have already
confessed to doing it.)

Luiz Carlos Silveira wrote:

> > But the "n" is not the size of the table. It's a key in a
> > particular type of
> > table which is used to provide the functionality of vectors.
>
> The computation time saved by the usage of this .n field in my programs is surely much less than the time that it took me to
> discover some very-hard-to-find bugs caused by this field.
>
> I believe that everyone would agree that it would be better if this .n field wasn't there. (If I remember correctly, the only
> purpose of a .n field was to speed up the insertion operation, wasn't it?)
>
> I don't know too much about garbage collection issues, but a nearly perfect solution would be if these 3 functions could share a
> table. Something like this:
>
> N_TABLE = {}
> function getn(t)
>         if (N_TABLE[t] == nil) then
>                 N_TABLE[t] = count_elements(t)
>         end
>         return N_TABLE[t]
> end
>
> and equivalent for tinsert and tremove.
>
> Possibly, to ease flexibility, another function might have to be introduced: setn(t)
>
> The question is: none of the tables stored in the N_TABLE could be collected, could them?


Reply | Threaded
Open this post in threaded view
|

Re: getn

Jay Carlson
In reply to this post by Nick Trout-2
> Is there any chance that the table entry used to store the number of
elements,
> ie. n, can be renamed to something less likely to cause a name clash with
user
> code?
>
> eg. _n or __n__

Why not go all the way?

n_entry = {}  -- new tables are never ==, right?

l = {1,2,3,nil,5}
l[n_entry] = 5

or

l = {1,2,3,nil,5; [n_entry]=5}

BTW, I think I figured out why there's resistance to adding the "fori"
syntax.  Base Lua has no concept of lists/vectors at all; everything that
treats tables this way is in liblualib.a, not liblua.a.

This still leaves Lua without syntax for ordered table iteration, and IMO
makes things that are simple and pretty in other scripting languages ugly
and annoying in Lua.

If there was a way to set a tag method for iteration, I would be happy with
that, or perhaps a for syntax that allowed a user-specified iterator
function in some non-ugly way.  (for i,v in t in numeric_order, where
numeric_order is a global function that gives me 1,2,3,4..getn behavior.)

Jay


Reply | Threaded
Open this post in threaded view
|

Re: getn

John Belmonte-2
> BTW, I think I figured out why there's resistance to adding
> the "fori" syntax.  Base Lua has no concept of lists/vectors
> at all; everything that treats tables this way is in liblualib.a,
> not liblua.a.

This is not entirely true.  The VM deals with lists for the vararg stuff.
It doesn't know how to compute n for an arbitrary table however.

> If there was a way to set a tag method for iteration, I would be
> happy with that, or perhaps a for syntax that allowed a
> user-specified iterator function in some non-ugly way.
>  (for i,v in t in numeric_order, where numeric_order is a global
> function that gives me 1,2,3,4..getn behavior.)

See http://python.sourceforge.net/peps/pep-0234.html for some ideas.

-John



Reply | Threaded
Open this post in threaded view
|

RE: getn

Roberto Ierusalimschy-5
In reply to this post by Luiz Carlos de Castro Silveira Filho
On Fri, 24 Aug 2001, Luiz Carlos Silveira wrote:

> The question is: none of the tables stored in the N_TABLE could be collected, could them?
>

Now they can, with weak references.

-- Roberto


Reply | Threaded
Open this post in threaded view
|

Iternation syntax. Was Re: getn

RLak-2
In reply to this post by Jay Carlson
Jay Carlson wrote:
> 
> Why not go all the way?
> 
> n_entry = {}  -- new tables are never ==, right?
> 
> l = {1,2,3,nil,5}
> l[n_entry] = 5

Yep, that's a standard way of putting private data in tables. But it
still
leaves you with this annoying problem:

   for k,v in l do
     -- do something which assumes k is a number
   end

> This still leaves Lua without syntax for ordered table iteration, and IMO
> makes things that are simple and pretty in other scripting languages ugly
> and annoying in Lua.

What's wrong with:

   for i = 1, getn(l) do
      -- do something with l[i]
   end

Is that uglier than
   for k, v in l using numerical_order do
      -- do something with k and v
   end
?

I personally like the syntax I illustrate in
<http://lua-users.org/wiki/VectorGlue>,
which uses functionals. I didn't give the illustration of simple
iteration over a
vector, but it should be clear how I do it... maybe I'll add it at some
point.
However, you can do simple iteration by using map and having the
function return
nil, which will return an almost empty table which you can then throw
away. (I know
that's not very efficient but it's not that bad. It's at least a way to
play around
with possible syntaxes.)

Eg:
	function Do() end
	Do(print^ l)
	-- or, if you prefer:  Do(l ^print)

I think that's pretty expressive, but there are some other examples in
the
aforementioned page.

You need the Do function because Lua doesn't allow the evaluation of
expressions
for side-effects, except for function calls. You could just as well use
an
assignment statement:

	local _ = print^ l

but I find the Do syntax less ugly.

R.

Reply | Threaded
Open this post in threaded view
|

Re: getn

Nick Trout-2
In reply to this post by Reuben Thomas-4
| It'd be nicer though if this could be a property just like any other in an
| object-oriented way, as it pretty much is at the moment, and not a "magic"
| property as you seem to be proposing. I'm not sure what the answer is;
| there's a tension between the use of tables as objects and as simple
| tables.

I agree with your observation. Tables are multipurpose in Lua and need not be an
array/vector or an associative array, they can be both at once. This is the
reason why I would like "n" renamed or replaced with setn(). I'm not sure what
the better solution is either. I think I'm starting to come down on the side of
setn(). If "n" is renamed there is still potential for a clash. As far as I can
see "n"/lua_getn() is used as an optimisation and should probably be better
hidden.

| I think that if you're likely to want a key called "n", then you shouldn't
| be putting it in a getn-able table (which is generally a list). It's
| sometimes nice to be able to put a list and other elements in the same
| table, but unnecessary.

The functionality is there to mix it and it is often convenient to use. It's
almost encouraged! eg. FnBlah{ 1,2,3 ; n="bill" } . Why should I have to design
round a clumsily named table member variable?

N




Reply | Threaded
Open this post in threaded view
|

Re: getn

Reuben Thomas-5
> | I think that if you're likely to want a key called "n", then you shouldn't
> | be putting it in a getn-able table (which is generally a list). It's
> | sometimes nice to be able to put a list and other elements in the same
> | table, but unnecessary.
> 
> The functionality is there to mix it and it is often convenient to use. It's
> almost encouraged! eg. FnBlah{ 1,2,3 ; n="bill" } . Why should I have to design
> round a clumsily named table member variable?

Equally, why should the number of number-keyed items in a table be
special? I think it's probably better not to encourage this form of
programming (perhaps by dropping support for the syntax you give
above; I've certainly never used it).

-- 
http://sc3d.org/rrt/
Si hoc legere scis nimium eruditionis habes (Anon)

Reply | Threaded
Open this post in threaded view
|

Re: getn

Nick Trout-2
| > | I think that if you're likely to want a key called "n", then you shouldn't
| > | be putting it in a getn-able table (which is generally a list). It's
| > | sometimes nice to be able to put a list and other elements in the same
| > | table, but unnecessary.
| >
| > The functionality is there to mix it and it is often convenient to use. It's
| > almost encouraged! eg. FnBlah{ 1,2,3 ; n="bill" } . Why should I have to
design
| > round a clumsily named table member variable?
|
| Equally, why should the number of number-keyed items in a table be
| special? I think it's probably better not to encourage this form of
| programming (perhaps by dropping support for the syntax you give
| above; I've certainly never used it).


Are we moving onto a discussion about programming style now? :-) The fact is the
language supports this syntax, and from the look of other postings today it is
used. I dont have a problem with this mixed functionality really, all I would
like is for "n" to be renamed (eg. "__n__" better but not perfect) or setn() to
be added (probably better).

N


Reply | Threaded
Open this post in threaded view
|

Re: getn (poll)

Nick Trout-2
Hi, this is just an experiment really. It may not produce any meaningful results
(I imagine through lack of interest ;-). Yahoo groups can manage polls. I have
started one wrt the table.n question, perhaps you would like to cast a vote.
Please visit:

http://groups.yahoo.com/group/lua-l/polls

Nick