Quest: real world "Lua array with holes" usage

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

Quest: real world "Lua array with holes" usage

Rodrigo Azevedo
In face of recent (long) discussion about "Lua arrays", I would request a simple few lines of real world examples where the use of "Lua arrays with holes" is significant.
I known that, intuitively, the length operator # should return the "size" of the array, but I'm not able to find significant use cases where "holes" are, in fact, a real problem other than a *simple* algorithm redesign.

For my particular use case I made heavy use of "sparse things", from which Lua tables are awesome, where all computations are based on the keys, namely, with pairs() or indexing the relevant key. Also, I use "proper sequences" with Lua tables. In this case, table.pack and table.unpack are symmetric, and the relevant computation is given by the "order" of the keys, namely, with table.insert, table.remove, table.move etc that is by default, in this case, simple to understand. I never ever used a "Lua array with holes", where the ordering, or existence, of the keys is indeed relevant for computation. Precluding the use of __len or misbehaviour of  #.

Could you help me giving a (real world) counterexample?

--
Rodrigo Azevedo Moreira da Silva
Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Roberto Ierusalimschy
> For my particular use case I made heavy use of "sparse things", from which
> Lua tables are awesome, where all computations are based on the keys,
> namely, with pairs() or indexing the relevant key. Also, I use "proper
> sequences" with Lua tables. In this case, table.pack and table.unpack are
> symmetric, and the relevant computation is given by the "order" of the
> keys, namely, with table.insert, table.remove, table.move etc that is by
> default, in this case, simple to understand. I never ever used a "Lua array
> with holes", where the ordering, or existence, of the keys is indeed
> relevant for computation. Precluding the use of __len or misbehaviour of  #.
>
> Could you help me giving a (real world) counterexample?

The only real-world case that bothers me is when you want to collect all
the results from a function call, something like {f()}. If there is an
error, the standard protocol is to return (nil, msg), which would create
an array with holes. (Currently I think the correct way to fix this
would be to return (false, msg), not to change the behavior of lists.)

-- Roberto

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Daurnimator
In reply to this post by Rodrigo Azevedo
On 21 July 2016 at 08:13, Rodrigo Azevedo <[hidden email]> wrote:

> In face of recent (long) discussion about "Lua arrays", I would request a
> simple few lines of real world examples where the use of "Lua arrays with
> holes" is significant.
> I known that, intuitively, the length operator # should return the "size" of
> the array, but I'm not able to find significant use cases where "holes" are,
> in fact, a real problem other than a *simple* algorithm redesign.
>
> For my particular use case I made heavy use of "sparse things", from which
> Lua tables are awesome, where all computations are based on the keys,
> namely, with pairs() or indexing the relevant key. Also, I use "proper
> sequences" with Lua tables. In this case, table.pack and table.unpack are
> symmetric, and the relevant computation is given by the "order" of the keys,
> namely, with table.insert, table.remove, table.move etc that is by default,
> in this case, simple to understand. I never ever used a "Lua array with
> holes", where the ordering, or existence, of the keys is indeed relevant for
> computation. Precluding the use of __len or misbehaviour of  #.
>
> Could you help me giving a (real world) counterexample?
>
> --
> Rodrigo Azevedo Moreira da Silva

The place it usually comes up for me is when keeping arguments across
a callback-style api:

local function foo(...)
    local args = {...}
    do_something_async(function()
        -- called when done
        my_other_function(x, table.unpack(args))
    end)
end

If the argument list contains a `nil` then the above will fail for some inputs.
Hence you end up needing to use `table.pack` or `select("#", ...)`

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Jorge Visca
In reply to this post by Roberto Ierusalimschy


On 21/07/16 14:09, Roberto Ierusalimschy wrote:
> The only real-world case that bothers me is when you want to collect
> all the results from a function call, something like {f()}. If there
> is an error, the standard protocol is to return (nil, msg), which
> would create an array with holes.
Yes, that's the only way I get holes in arrays. OTOH, that's happening a
lot less since I decided to assert  all functions that can return
nil,... unless I specifically know what to do in that case. Anyway, it's
pretty easy to check ret[1]==nil to see if the call was successful.

> (Currently I think the correct way to fix this would be to return
> (false, msg), not to change the behavior of lists.) -- Roberto

I have doubts on this, because false is a reasonable value to get from a
function... Returning nil is clearer because the meaning is "could not
produce a value to return". Otherwise you end using a explicit return
for status pcall-like, all the time.

I believe the main problem with nil in arrays stems not from the
language, but from the design of programs: there is a tendency to use
nil for nil-like concepts in the business logic, and that's when things
get broken. A database NULL is not nil, is a singleton {}. The same for
"free_slot", "nodataacquired" and whatever. Nil should be reserver for
language-level concepts, like "the function failed to get a result" or
"this variable has no value assigned".


Jorge


Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

William Ahern
In reply to this post by Rodrigo Azevedo
On Thu, Jul 21, 2016 at 12:13:40PM -0300, Rodrigo Azevedo wrote:
> In face of recent (long) discussion about "Lua arrays", I would request a
> simple few lines of real world examples where the use of "Lua arrays with
> holes" is significant.

The first use case that came to mind was JSON deserializers, where the
obvious mapping of null to nil causes problems with arrays.

But I think that's irritating mostly because superficially it _seems_ like
such a trivial (and trivially fixable) mismatch between Lua and JavaScript
type semantics, but as the thread has shown it's not trivial at all. I
wouldn't use this case to argue for change in Lua.


Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Oliver Kroth
Hi

there is really a significant difference:

Whatever you assign to an array (or object) member in JavaScript, it
stays in the array/object.
Assign null, or even undefined, doesn't matter; it's there and you can
enumerate it.
You need to explicitly delete() it.

This is kind f confusing if you come from C++, in JavaScript delete()
does not kill the data, it kills the variable; the data may be
referenced else where and survive.
I do not really like the doubled feature undefined - null either.

--
Oliver


Am 21.07.2016 um 21:28 schrieb William Ahern:

> On Thu, Jul 21, 2016 at 12:13:40PM -0300, Rodrigo Azevedo wrote:
>> In face of recent (long) discussion about "Lua arrays", I would request a
>> simple few lines of real world examples where the use of "Lua arrays with
>> holes" is significant.
> The first use case that came to mind was JSON deserializers, where the
> obvious mapping of null to nil causes problems with arrays.
>
> But I think that's irritating mostly because superficially it _seems_ like
> such a trivial (and trivially fixable) mismatch between Lua and JavaScript
> type semantics, but as the thread has shown it's not trivial at all. I
> wouldn't use this case to argue for change in Lua.
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Luiz Henrique de Figueiredo
In reply to this post by William Ahern
> The first use case that came to mind was JSON deserializers, where the
> obvious mapping of null to nil causes problems with arrays.

That's the whole point: one probably shouldn't not force the semantics
of one language into another. In this case, and others, it's simpler
and clearer to define
        null = {}
once and use it where needed. if you must skip over these when traversing
a table, then that's what your semantics dictates and you must do it.
Just do not try to do this with nil, which has its own, clear semantics
in Lua.

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Jonathan Goble
On Thu, Jul 21, 2016 at 6:08 PM, Luiz Henrique de Figueiredo
<[hidden email]> wrote:

>> The first use case that came to mind was JSON deserializers, where the
>> obvious mapping of null to nil causes problems with arrays.
>
> That's the whole point: one probably shouldn't not force the semantics
> of one language into another. In this case, and others, it's simpler
> and clearer to define
>         null = {}
> once and use it where needed. if you must skip over these when traversing
> a table, then that's what your semantics dictates and you must do it.
> Just do not try to do this with nil, which has its own, clear semantics
> in Lua.

I think part of the reason people try to use Lua's `nil` in ways like
JSON's `null` or Python's `None` is because, in a context where you
know you won't get the Boolean `false`, `if var then ...` is an easy
way to check if `var` is a useful value or not, as `nil`, `null`, and
`None` all evaluate to false in a Boolean context.

The problem arises when one tries to create a singleton to represent
this lack of a useful value. Python provides the `__bool__` method (in
3.x; `__nonzero__` in Python 2.x) to customize the behavior of an
object when used in a Boolean context. Lua does not provide any such
metamethod, for either tables or userdata, so any user-created
singleton is automatically true in a Boolean context. This means that
the idiom `if var then ...` no longer works, and an explicit
(in)equality check against the singleton is required, creating uglier
code.

Perhaps what Lua *really* needs to solve this problem, then, is a
__bool metamethod that, if present, is called when the object is used
in a boolean context (such as `if`, `and`, and `or`) and returns
either true or false, replacing the default true. Then one can take
these `null` singletons and slap a `{__bool = function(t) return false
end}` metatable on them, allowing them to gain the benefits of `nil`
without the drawback of `nil`.

What does everyone else think about a __bool metamethod?

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Tim Hill
In reply to this post by Roberto Ierusalimschy

> On Jul 21, 2016, at 10:09 AM, Roberto Ierusalimschy <[hidden email]> wrote:
>
>> For my particular use case I made heavy use of "sparse things", from which
>> Lua tables are awesome, where all computations are based on the keys,
>> namely, with pairs() or indexing the relevant key. Also, I use "proper
>> sequences" with Lua tables. In this case, table.pack and table.unpack are
>> symmetric, and the relevant computation is given by the "order" of the
>> keys, namely, with table.insert, table.remove, table.move etc that is by
>> default, in this case, simple to understand. I never ever used a "Lua array
>> with holes", where the ordering, or existence, of the keys is indeed
>> relevant for computation. Precluding the use of __len or misbehaviour of  #.
>>
>> Could you help me giving a (real world) counterexample?
>
> The only real-world case that bothers me is when you want to collect all
> the results from a function call, something like {f()}. If there is an
> error, the standard protocol is to return (nil, msg), which would create
> an array with holes. (Currently I think the correct way to fix this
> would be to return (false, msg), not to change the behavior of lists.)
>
> -- Roberto
>

But that would still leave the general case of {f()} unsolved :(

—Tim
Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Sean Conner
In reply to this post by Jonathan Goble
It was thus said that the Great Jonathan Goble once stated:

> On Thu, Jul 21, 2016 at 6:08 PM, Luiz Henrique de Figueiredo
> <[hidden email]> wrote:
> >> The first use case that came to mind was JSON deserializers, where the
> >> obvious mapping of null to nil causes problems with arrays.
> >
> > That's the whole point: one probably shouldn't not force the semantics
> > of one language into another. In this case, and others, it's simpler
> > and clearer to define
> >         null = {}
> > once and use it where needed. if you must skip over these when traversing
> > a table, then that's what your semantics dictates and you must do it.
> > Just do not try to do this with nil, which has its own, clear semantics
> > in Lua.
>
> I think part of the reason people try to use Lua's `nil` in ways like
> JSON's `null` or Python's `None` is because, in a context where you
> know you won't get the Boolean `false`, `if var then ...` is an easy
> way to check if `var` is a useful value or not, as `nil`, `null`, and
> `None` all evaluate to false in a Boolean context.

  In my CBOR [1] library [2], it returns nil for 'null' and 'undefined' by
default, but that can be overridden by the user (in fact, just about
everything can be overridden by the user) so to me, that's more a limitation
of the JSON module than of actual problems with semantics.  If you care
enough, you'll make the distinction.

> The problem arises when one tries to create a singleton to represent
> this lack of a useful value. Python provides the `__bool__` method (in
> 3.x; `__nonzero__` in Python 2.x) to customize the behavior of an
> object when used in a Boolean context. Lua does not provide any such
> metamethod, for either tables or userdata, so any user-created
> singleton is automatically true in a Boolean context. This means that
> the idiom `if var then ...` no longer works, and an explicit
> (in)equality check against the singleton is required, creating uglier
> code.
>
> Perhaps what Lua *really* needs to solve this problem, then, is a
> __bool metamethod that, if present, is called when the object is used
> in a boolean context (such as `if`, `and`, and `or`) and returns
> either true or false, replacing the default true. Then one can take
> these `null` singletons and slap a `{__bool = function(t) return false
> end}` metatable on them, allowing them to gain the benefits of `nil`
> without the drawback of `nil`.
>
> What does everyone else think about a __bool metamethod?

  A __boolean metamethod was mentioned?  Proposed?  I'm not sure, but in any
case, one was mentioned here:

        http://lua-users.org/lists/lua-l/2011-12/msg00621.html

but it seems like it was for something else.

  -spc (Keeper of the metamethod proposals ... )

[1] Concise Binary Object Representation, RFC-7049

[2] https://github.com/spc476/CBOR

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

steve donovan
In reply to this post by Tim Hill
On Fri, Jul 22, 2016 at 1:54 AM, Tim Hill <[hidden email]> wrote:
> But that would still leave the general case of {f()} unsolved :(

We always have table.pack(f()) ...

Especially when pack/unpack become symmetrical.

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Rodrigo Azevedo
table.pack is very good, but I use ".n" field for other purposes. Then, I'm (seldom) using something like

pack_len = function(...)
        local len = select('#',...)
        return setmetatable({...},{
                        __len = function() return len end,
                        __newindex = function(t,k,v)
                                if math.type(k) == 'integer' then
                                        len = math.max(len,k)
                                        rawset(t,k,v)
                                end
                        end
                })
end

t = pack_len(nil,3,nil)

print(#t, table.unpack(t))

t[10] = 3.1415
print(#t, table.unpack(t))

t[3] = 5
t[1] = 2
t[2] = 7
print(#t, table.unpack(t))

t[#t+1] = 0.5772
for i=1,#t do print(i,t[i]) end

return

3    nil    3    nil
10    nil    3    nil    nil    nil    nil    nil    nil    nil    3.1415
10    2    7    5    nil    nil    nil    nil    nil    nil    3.1415
1    2
2    7
3    5
4    nil
5    nil
6    nil
7    nil
8    nil
9    nil
10    3.1415
11    0.5772

as expected.

This keep symmetry with table.pack, as well as others table.something, and give me an unbounded "sparse array" with well defined length.

There is something wrong with this implementation?



2016-07-22 4:06 GMT-03:00 steve donovan <[hidden email]>:
On Fri, Jul 22, 2016 at 1:54 AM, Tim Hill <[hidden email]> wrote:
> But that would still leave the general case of {f()} unsolved :(

We always have table.pack(f()) ...

Especially when pack/unpack become symmetrical.




--
Rodrigo Azevedo Moreira da Silva
Reply | Threaded
Open this post in threaded view
|

Re: __bool / __false (was: Quest: real world "Lua array with holes" usage)

nobody
In reply to this post by Jonathan Goble
On 2016-07-22 00:33, Jonathan Goble wrote:
> Perhaps what Lua *really* needs to solve this problem, then, is a
> __bool metamethod that, if present, is called when the object is used
> in a boolean context (such as `if`, `and`, and `or`) and returns
> either true or false, replacing the default true. Then one can take
> these `null` singletons and slap a `{__bool = function(t) return false
> end}` metatable on them, allowing them to gain the benefits of `nil`
> without the drawback of `nil`.
>
> What does everyone else think about a __bool metamethod?

Yes!!1!  I have built & used that before (as __false).

Experience report: (I loved it!)



How can it be done?

What I did was (IIRC) turn luaO_isfalse(x) from a macro in lobject.h(?)
to a function luaV_isfalse(L,x) in lvm.c, adjust what needs adjusting
(ORDER TM, add decl. to lvm.h, add the L arg in all (2 or 3) use sites,
remove no-longer-valid short circuitry in lcode.c ("" or x, 0 and x,
...)) and then defined __false/luaV_isfalse to:

 - handle nil, false, true as currently (false,false,true)
otherwise, check metavalue:
 - a boolean or nil: __false is true -> value is false
                     __false is false (or nil) -> value is true
(The true/false order was chosen such that you're not jumping around in
the truth table: (__false = nil) ~ (__false = false) whereas it would
probably be (__bool = nil) !~ (__bool = false).)
 - a function: call it, check result for truth (recursively if needed)
 - a value: is it rawequal()? then it's false, else true.

This was surprisingly easy (but I seem to have botched some strange
case, because rarely I got a segfault... but it worked well enough for
experiments, the standard Lua tests & my extension checking __false also
ran cleanly.)



Why did I use this definition?

 -  function, because meta_method_
      -  recursion: so it's possible to experiment & see if it's needed
 -  boolean: _all_ values of this "metatype" are true/false
             (e.g. Null, False, ...)
 -  rawequal: there's one canonical falsish value, e.g. (if you like C)

        getmetatable"".__false = ""
        debug.setmetatable(0,{__false = 0})

        (or similar stuff for custom types)

I found that the boolean/rawequal cases got rid of >=95% of all uses,
and I personally found '__false = true' instead of '__false = function()
return true end' and '__false = Null' instead of '__false = function(x)
return rawequal(Null,x) end' to be more readable.

The function version was only necessary for lazy evaluation (trigger
evaluation (which changes the metatable), then check the result with the
new value('s contents) (& new metatable/-method) – this needs(?)
recursion as well), or shoving some complex predicate (that I can't
remember anymore) into the metamethod & out of view, or for really silly
stuff like

 coin=setmetatable({},{__false=function() return math.random(2)==1 end})

(where 'coin(0.5)' or 'coin()' would arguably be clearer than 'coin' at
use site... it's only nice to confuse people.)



What's possible?

Boxed values are a lot nicer to handle.  If you're gluing (or building)
some other system with its own notion of truth, you're probably boxing
all values in some form(*).  The cleanest way so far was to either not
use Lua's control structures or to have some predicate p(x) --> bool and
wrap that around all expressions in control structures (and never forget
it or else  while False do end  runs forever etc.).

By extension of that, language-wide lazy evaluation becomes a lot more
usable/invisible.

Custom truth values (True/False/FileNotFound) or other markers can be
made.  An error value can be false, yet still contain extensive error
information (Think Haskell's Either with Left/Right or Coq's sum/inl/inr
etc.).

(And probably much more that I didn't try.)



How does other (non __false-aware) code cope?

It depends.

If you change primitive type's __false, all bets are off.  (Doing that
is awesome when gluing stuff - suddenly both languages behave the same
in that aspect, you no longer have to mentally switch around as much.
But you'll be rewriting/adjusting any libraries you're using - a
trade-off that's worth it IMHO.)

If you leave primitive types alone, then it mostly depends on what your
falsish values are used for.  Stuff that never leaves your library /
never gets passed to another library is safe.  Alternate error/"absence"
values (like null) get replaced by 'x or "foo"' and miss 'if x then ...'
branches, which _tends_ to be the "right thing".  For other things,
that's probably wrong.

Storage (tables & other data structures) works just fine if the check in
that library is 'x ~= nil' but breaks (and is already broken) if the
check is just 'x' (which already fails to handle plain 'false').

In general, library code probably needs some small adjustments to
clarify what's checked for (which tends to make the code state more
precisely what's the relevant property).  Some things might be
completely broken, but I didn't run into such a case.



Any other disadvantages?

The three one-line code snippets above.  Eeek!  I don't want something
like that done to me from a library.  (But if I'm changing Lua to behave
more like some other system I'm gluing/building, that's totally cool!)

Every truth check has to check for metamethod presence & gets a tiny bit
slower.  (I did not notice any slowdown, even for large programs not
using this feature at all, but didn't benchmark.)

(And probably more that I didn't run into.)

"Complexity"? -- debatable.  The patch is simple, and it gets rid of
_a lot_ of translation logic in the code (if you need it).  It makes
control structures configurable, which increases their utility, but also
increases (if only perceived) "uncertainty".



Any notable non-solution alternatives?

An operator '?x': Seems like it might get the job done but actually
doesn't -- only code that knows of the presence of non-standard values
and checks '?x' instead of 'x' will be compatible, and it's not much
shorter than 'p(x)'.  Tried it, doesn't improve on what we have.



-----

[For my long-term goal (i.e. years, if I ever get there) of building
some dependently-typed system in Lua (to finally get rid of the
hard-to-port several-hundred-MB monsters that are Haskell and Coq), I
will almost certainly use this whether it's part of the language or not.
 Not using __false and having p(x)-es all over the place would be
madness...]


(*) - Using the same function for several type's __eq is communicating
clearly that this comparison function can handle both types.  Yet, __eq
refuses checking equality across "primitive types" even if that was
useful within a "logical type" built across several "primitive types".
So if you have e.g. mixed table/userdata (or table/boolean etc.)
"logical types", you must convert or box values to get equality.
Compare Eq/JMeq if you've heard of that before.  (I'll write some more
on that once I find the time... soon, hopefully.)

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Matthias Kluwe
In reply to this post by Rodrigo Azevedo

Am 21.07.2016 17:13 schrieb "Rodrigo Azevedo" <[hidden email]>:
>
> [...]
>
> Could you help me giving a (real world) counterexample?

No. :-)

I've been bitten *once* by # doing something unexpected (and debugging for some hours then) but that was due to a logical error further down in the call stack.

I tend to skip all the threads regarding the "issue" with a smile.

Matthias

PS. Sorry for this unhelpful reply, but I really like Lua the way it is...

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Hisham
In reply to this post by Jorge Visca
On 21 July 2016 at 14:58, Jorge <[hidden email]> wrote:

>
>
> On 21/07/16 14:09, Roberto Ierusalimschy wrote:
>>
>> The only real-world case that bothers me is when you want to collect all
>> the results from a function call, something like {f()}. If there is an
>> error, the standard protocol is to return (nil, msg), which would create an
>> array with holes.
>
> Yes, that's the only way I get holes in arrays. OTOH, that's happening a lot
> less since I decided to assert  all functions that can return nil,... unless
> I specifically know what to do in that case. Anyway, it's pretty easy to
> check ret[1]==nil to see if the call was successful.
>
>> (Currently I think the correct way to fix this would be to return (false,
>> msg), not to change the behavior of lists.) -- Roberto
>
> I have doubts on this, because false is a reasonable value to get from a
> function... Returning nil is clearer because the meaning is "could not
> produce a value to return". Otherwise you end using a explicit return for
> status pcall-like, all the time.

I agree with Jorge. Also, sometimes when returning multiple things,
one of these things might be nil, so it's not only the error situation
that produces a nil value upon return, although it is of course the
most common. So, unfortunately just changing the policy from
nil-on-error to false-on-error still wouldn't allow us to just forget
about table.pack().

-- Hisham

Reply | Threaded
Open this post in threaded view
|

Re: __bool / __false (was: Quest: real world "Lua array with holes" usage)

Rena
In reply to this post by nobody

On Jul 22, 2016 10:11 AM, "nobody" <[hidden email]> wrote:
>
>  - a boolean or nil: __false is true -> value is false
>                      __false is false (or nil) -> value is true
> (The true/false order was chosen such that you're not jumping around in
> the truth table: (__false = nil) ~ (__false = false) whereas it would
> probably be (__bool = nil) !~ (__bool = false).)

While I understand the reasoning, the double negation here is confusing. I'd find __bool much easier to understand: if it's a boolean, that's the truth value; if it's a function, call it to determine the truth value; if it's nil, the standard logic applies (anything that isn't `false` or `nil` is true).

If we were designing a new language, I'd be tempted to say it should raise an error when comparing a value which is not a boolean to one that is (where having __bool counts as being a boolean).

Reply | Threaded
Open this post in threaded view
|

Re: Quest: real world "Lua array with holes" usage

Roberto Ierusalimschy
In reply to this post by Hisham
> I agree with Jorge. Also, sometimes when returning multiple things,
> one of these things might be nil, so it's not only the error situation
> that produces a nil value upon return, although it is of course the
> most common. So, unfortunately just changing the policy from
> nil-on-error to false-on-error still wouldn't allow us to just forget
> about table.pack().

Of course any function can return nil among its returns, but maybe
that might be considered a bad practice.

My point is that, if nil is representing the absence of a value, it
is weird not to have a third value but to have a fourth one. If nil
is representing something else, probably it shouldn't be (as pointed
out by others already).

("is weird" ~ "it might be considered weird")

-- Roberto

Reply | Threaded
Open this post in threaded view
|

The Undefined Country (was Re: Quest: real world "Lua array with holes" usage)

Sean Conner
It was thus said that the Great Roberto Ierusalimschy once stated:

> > I agree with Jorge. Also, sometimes when returning multiple things,
> > one of these things might be nil, so it's not only the error situation
> > that produces a nil value upon return, although it is of course the
> > most common. So, unfortunately just changing the policy from
> > nil-on-error to false-on-error still wouldn't allow us to just forget
> > about table.pack().
>
> Of course any function can return nil among its returns, but maybe
> that might be considered a bad practice.
>
> My point is that, if nil is representing the absence of a value, it
> is weird not to have a third value but to have a fourth one. If nil
> is representing something else, probably it shouldn't be (as pointed
> out by others already).

  Javascript has an "undefined" state, in addition to a "null" state.
Perhaps Lua should have one as well.  To me, "nil" means "the absence of a
value" while "undef" means "this never had a value to begin with".

  Proposal:  undef.  It works just like nil does now, but "nil" (the new nil
behavior) is that it *is* allowed in sequences.  

        t = {}
        x = t.one -- x is "undef"
        local zork -- zork is "undef"
        t = { 1 , 2 , nil , 4 }
        y = #t -- 4, because there are four items in t
        z = t[5] -- z is "undef", falls outside sequence

        function foo(...)
          local args = table.pack(...) -- no 'n' field to worry about
          local a,b,c,d,e = table.unpack(t)
          -- a is 1
          -- b is 2
          -- c is nil
          -- d is 4
          -- e is undef

          if e then
            print(e)
          elseif e == nil then
            print("e is nil")
          elseif e == undef then
            print("e never had a chance")
          end
        end

  It seems, to me, to solve all the current issues Lua has with arrays.

  -spc (There's probably stuff I'm missing though ... )

Reply | Threaded
Open this post in threaded view
|

Re: The Undefined Country (was Re: Quest: real world "Lua array with holes" usage)

Gregg Reynolds-2

On Jul 24, 2016 3:27 PM, "Sean Conner" <[hidden email]> wrote:
>
> It was thus said that the Great Roberto Ierusalimschy once stated:
> > > I agree with Jorge. Also, sometimes when returning multiple things,
> > > one of these things might be nil, so it's not only the error situation
> > > that produces a nil value upon return, although it is of course the
> > > most common. So, unfortunately just changing the policy from
> > > nil-on-error to false-on-error still wouldn't allow us to just forget
> > > about table.pack().
> >
> > Of course any function can return nil among its returns, but maybe
> > that might be considered a bad practice.
> >
> > My point is that, if nil is representing the absence of a value, it
> > is weird not to have a third value but to have a fourth one. If nil
> > is representing something else, probably it shouldn't be (as pointed
> > out by others already).
>
>   Javascript has an "undefined" state, in addition to a "null" state.
> Perhaps Lua should have one as well.  To me, "nil" means "the absence of a
> value" while "undef" means "this never had a value to begin with".
>
howsabout NaV (Not a Value) by analogy to NaN?  "Undefined value" seems kind of an oxymoron to me.  NaV could mean sth like "its a value, kinda sorta, but one that cannot be represented,  not even by nil".

Reply | Threaded
Open this post in threaded view
|

Re: The Undefined Country (was Re: Quest: real world "Lua array with holes" usage)

Soni "They/Them" L.


On 24/07/16 05:45 PM, Gregg Reynolds wrote:

>
> On Jul 24, 2016 3:27 PM, "Sean Conner" <[hidden email]
> <mailto:[hidden email]>> wrote:
> >
> > It was thus said that the Great Roberto Ierusalimschy once stated:
> > > > I agree with Jorge. Also, sometimes when returning multiple things,
> > > > one of these things might be nil, so it's not only the error
> situation
> > > > that produces a nil value upon return, although it is of course the
> > > > most common. So, unfortunately just changing the policy from
> > > > nil-on-error to false-on-error still wouldn't allow us to just
> forget
> > > > about table.pack().
> > >
> > > Of course any function can return nil among its returns, but maybe
> > > that might be considered a bad practice.
> > >
> > > My point is that, if nil is representing the absence of a value, it
> > > is weird not to have a third value but to have a fourth one. If nil
> > > is representing something else, probably it shouldn't be (as pointed
> > > out by others already).
> >
> >   Javascript has an "undefined" state, in addition to a "null" state.
> > Perhaps Lua should have one as well.  To me, "nil" means "the
> absence of a
> > value" while "undef" means "this never had a value to begin with".
> >
> howsabout NaV (Not a Value) by analogy to NaN?  "Undefined value"
> seems kind of an oxymoron to me.  NaV could mean sth like "its a
> value, kinda sorta, but one that cannot be represented, not even by nil".
>
Well JSON can't store NaNs so you could repurpose NaNs for null.

Only wish NaNs were falsey...

--
Disclaimer: these emails may be made public at any given time, with or without reason. If you don't agree with this, DO NOT REPLY.


1234