# Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

35 messages
12
Open this post in threaded view
|

## Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 Lua is memory efficient for huge but sparse multi-dimensional arrays, since nil values aren't stored in the tables. However, reading and writing to such sparse multi-dimensional arrays can be quite a hassle.  If I want to access the value of t[a][b][c][d][e], I first have to check whether t[a] is a table, t[a][b] is a table, t[a][b][c] is a table etc, otherwise Lua throws an error "Attempt to index a nil value". For example, to read the value at t[a][b][c][d][e], I cannot simply use: v = t[a][b][c][d][e] Instead, the code must look something like: v = t and t[a] and t[a][b] and t[a][b][c] and t[a][b][c][d] and t[a][b][c][d][e] Or, to write a value to t[a][b][c][d][e], I cannot simply use: t[a][b][c][d][e] = v Instead, the code must look something like: if not t then t = {[a] = {[b] = {[c] = {[d] = {[e] = v}}}}} elseif not t[a] then t[a] = {[b] = {[c] = {[d] = {[e] = v}}}} elseif not t[a][b] then t[a][b] = {[c] = {[d] = {[e] = v}}} elseif not t[a][b][c] then t[a][b][c] = {[d] = {[e] = v}} elseif not t[a][b][c][d] then t[a][b][c][d] = {[e] = v} else t[a][b][c][d][e] = v end I suggest that it would be more useful -- and more consistent -- if the "Attempt to index a nil value" error is deprecated and, instead, the indexing of undefined variables does the following: When reading: simply return nil.  Given that undefined variables and non-existent table entries both return nil, I think it would be more consistent if an attempt to index an undefined variable also simply returns nil.  (The Lua FAQ states that: "In many languages, trying to access a non-existent key in a list or dictionary causes an exception; in Lua the result is simply nil. This is unambiguous because nil cannot be usefully put into tables.")  If t is nil, then t[a] should also simply be nil, as should t[a][b][c][d][e]. When writing: automatically assign a single-entry table to each undefined variable, with the given index the sole entry.  For example, if t is an undefined variable, then t[a] = v would be syntactic sugar for t = {[a] = v}.  Similarly, if t[a][b] is already declared as a table but t[a][b][c] is nil, then t[a][b][c][d][e] = v would mean t[a][b][c] = {[d] = {[e] = v}}. -- Anton
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On Fri, Feb 28, 2020 at 3:59 PM Anton Jordaan <[hidden email]> wrote:Lua is memory efficient for huge but sparse multi-dimensional arrays, since nil values aren't stored in the tables. However, reading and writing to such sparse multi-dimensional arrays can be quite a hassle.  If I want to access the value of t[a][b][c][d][e], I first have to check whether t[a] is a table, t[a][b] is a table, t[a][b][c] is a table etc, otherwise Lua throws an error "Attempt to index a nil value". For example, to read the value at t[a][b][c][d][e], I cannot simply use: v = t[a][b][c][d][e] Instead, the code must look something like: v = t and t[a] and t[a][b] and t[a][b][c] and t[a][b][c][d] and t[a][b][c][d][e] Or, to write a value to t[a][b][c][d][e], I cannot simply use: t[a][b][c][d][e] = v Instead, the code must look something like: if not t then t = {[a] = {[b] = {[c] = {[d] = {[e] = v}}}}} elseif not t[a] then t[a] = {[b] = {[c] = {[d] = {[e] = v}}}} elseif not t[a][b] then t[a][b] = {[c] = {[d] = {[e] = v}}} elseif not t[a][b][c] then t[a][b][c] = {[d] = {[e] = v}} elseif not t[a][b][c][d] then t[a][b][c][d] = {[e] = v} else t[a][b][c][d][e] = v end I suggest that it would be more useful -- and more consistent -- if the "Attempt to index a nil value" error is deprecated and, instead, the indexing of undefined variables does the following: When reading: simply return nil.  Given that undefined variables and non-existent table entries both return nil, I think it would be more consistent if an attempt to index an undefined variable also simply returns nil.  (The Lua FAQ states that: "In many languages, trying to access a non-existent key in a list or dictionary causes an exception; in Lua the result is simply nil. This is unambiguous because nil cannot be usefully put into tables.")  If t is nil, then t[a] should also simply be nil, as should t[a][b][c][d][e]. When writing: automatically assign a single-entry table to each undefined variable, with the given index the sole entry.  For example, if t is an undefined variable, then t[a] = v would be syntactic sugar for t = {[a] = v}.  Similarly, if t[a][b] is already declared as a table but t[a][b][c] is nil, then t[a][b][c][d][e] = v would mean t[a][b][c] = {[d] = {[e] = v}}. -- AntonThis comes up very, very frequently.This is absolutely a non-starter for inclusion in stock Lua, but for your own programs there are a number of solutions that have been proposed and/or implemented.The very simplest thing you can do is to implement something like Lodash's get and set methods:function get(tbl, k, ...)  if tbl == nil or tbl[k] == nil then return nil end  if select('#', ...) == 0 then return tbl[k] end  return get(tbl[k], ...)endfunction set(tbl, k, maybeValue, ...)  if select('#', ...) == 0 then    -- this will throw if the top-level tbl is nil, which is the desired behavior    tbl[k] = maybeValue    return  end  if tbl[k] == nil then tbl[k] = {} end  set(tbl[k], maybeValue, ...)endThen t[a][b][c][d] can be expressed as `get(t, a, b, c, d)` and t[a][b][c][d] = e can be expressed as `set(t, a, b, c, d, e)`.If you want the syntax you've given, then this will work for read-only:debug.setmetatable(nil, { __index = function(t, k) return nil end })After this, `(nil).a.b.c` will simply return nil. This may break existing code, so be judicious where you use it.Automatically creating nested tables is quite a bit more controversial and I really do recommend the set() function above for that. I'm not sure if you can implement this in vanilla Lua without a patch.If you really do want to modify Lua, http://lua-users.org/wiki/LuaPowerPatches has a "safe table navigation" patch for 5.2 that may give you some insight./s/ Adam
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by Anton Jordaan On Sat, Feb 29, 2020 at 12:59 AM Anton Jordaan wrote:If I want to access the value of t[a][b][c][d][e] I suggest that it would be more useful -- and more consistent -- if the "Attempt to index a nil value" error is deprecated and, instead, the indexing of undefined variables does the following: When reading: simply return nil.See solution #3 When writing: automatically assign a single-entry table to each undefined variable, with the given index the sole entry.Creating a table would better be explicit.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On 2020-02-28 10:05 p.m., Egor Skriptunoff wrote: > On Sat, Feb 29, 2020 at 12:59 AM Anton Jordaan wrote: > >     If I want to access the value of t[a][b][c][d][e] > >     I suggest that it would be more useful -- and more consistent -- >     if the >     "Attempt to index a nil value" error is deprecated and, instead, the >     indexing of undefined variables does the following: > >     When reading: simply return nil. > > > > http://lua-users.org/lists/lua-l/2017-02/msg00308.html> See solution #3 > > >     When writing: automatically assign a single-entry table to each >     undefined variable, with the given index the sole entry. > > > Creating a table would better be explicit. mktable -p (table, a, b, c, d, e, f, g, ...).with = value (this is valid lua fwiw, but good luck making it work :v)
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On 2020-02-28 10:10 p.m., Soni "They/Them" L. wrote: > > > On 2020-02-28 10:05 p.m., Egor Skriptunoff wrote: >> On Sat, Feb 29, 2020 at 12:59 AM Anton Jordaan wrote: >> >>     If I want to access the value of t[a][b][c][d][e] >> >>     I suggest that it would be more useful -- and more consistent -- >>     if the >>     "Attempt to index a nil value" error is deprecated and, instead, the >>     indexing of undefined variables does the following: >> >>     When reading: simply return nil. >> >> >> >> http://lua-users.org/lists/lua-l/2017-02/msg00308.html>> See solution #3 >> >> >>     When writing: automatically assign a single-entry table to each >>     undefined variable, with the given index the sole entry. >> >> >> Creating a table would better be explicit. > > mktable -p (table, a, b, c, d, e, f, g, ...).with = value > > (this is valid lua fwiw, but good luck making it work :v) correction, this is valid lua: (mktable -p (table, a, b, c, d, e, f, g, ...)).with = value oh well .-.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 Perl has auto-vivification and it creates way more problems than it solves. Also agree this should not be part of the language and the error when trying to index a null value is a good thing.On Sat, Feb 29, 2020, 02:12 Soni "They/Them" L. <[hidden email]> wrote: On 2020-02-28 10:10 p.m., Soni "They/Them" L. wrote: > > > On 2020-02-28 10:05 p.m., Egor Skriptunoff wrote: >> On Sat, Feb 29, 2020 at 12:59 AM Anton Jordaan wrote: >> >>     If I want to access the value of t[a][b][c][d][e] >> >>     I suggest that it would be more useful -- and more consistent -- >>     if the >>     "Attempt to index a nil value" error is deprecated and, instead, the >>     indexing of undefined variables does the following: >> >>     When reading: simply return nil. >> >> >> >> http://lua-users.org/lists/lua-l/2017-02/msg00308.html >> See solution #3 >> >> >>     When writing: automatically assign a single-entry table to each >>     undefined variable, with the given index the sole entry. >> >> >> Creating a table would better be explicit. > > mktable -p (table, a, b, c, d, e, f, g, ...).with = value > > (this is valid lua fwiw, but good luck making it work :v) correction, this is valid lua: (mktable -p (table, a, b, c, d, e, f, g, ...)).with = value oh well .-.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote:the error when trying to index a null value is a good thing.Let's assume the statementv = t[a][b][c][d][e]Each of 5 indexing steps might result in nil.Sometimes you want to raise "Attempt to index a nil value" exception, sometimes you want to ignore the exception.If nil is indexable, then it's pretty easy to raise the exceptionv = assert(t[a][b][c][d])[e]But if nil is non-indexable, it's not easy to ignore the exceptionv = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e]Indexable nil looks like a better alternative.Would indexable nil reduce runtime error detection?   No.Almost always another exception will be raised soon:"Attempt to perform arithmetic on a nil value" and the like.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On 2020-02-29 1:31 p.m., Egor Skriptunoff wrote: > On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote: > >     the error when trying to index a null value is a good thing. > > > > Let's assume the statement > v = t[a][b][c][d][e] > Each of 5 indexing steps might result in nil. > Sometimes you want to raise "Attempt to index a nil value" exception, > sometimes you want to ignore the exception. > > If nil is indexable, then it's pretty easy to raise the exception > v = assert(t[a][b][c][d])[e] > > But if nil is non-indexable, it's not easy to ignore the exception > v = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e] > > Indexable nil looks like a better alternative. > > Would indexable nil reduce runtime error detection?   No. > Almost always another exception will be raised soon: > "Attempt to perform arithmetic on a nil value" and the like. > v = (pcall(function() t[a][b][c][d][e] end) or nil) and t[a][b][c][d][e] slightly cleaner.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 I see no value at all in adding "or nil" (except that you'll change a "false" stored value, returned without exception, into an "nil"). Then why do you need "and t[a][b][c][d][e]" ? Wouldn' this be enough?:  _, v = pcall(function() return t[a][b][c][d][e] end) i.e. discard (_) the false/true status in the 1st return value of the pcall, use the second value which is explicitly returned and will be nil if the function does not return but throws an exception. Le sam. 29 févr. 2020 à 17:43, Soni "They/Them" L. <[hidden email]> a écrit : > > > > On 2020-02-29 1:31 p.m., Egor Skriptunoff wrote: > > On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote: > > > >     the error when trying to index a null value is a good thing. > > > > > > > > Let's assume the statement > > v = t[a][b][c][d][e] > > Each of 5 indexing steps might result in nil. > > Sometimes you want to raise "Attempt to index a nil value" exception, > > sometimes you want to ignore the exception. > > > > If nil is indexable, then it's pretty easy to raise the exception > > v = assert(t[a][b][c][d])[e] > > > > But if nil is non-indexable, it's not easy to ignore the exception > > v = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e] > > > > Indexable nil looks like a better alternative. > > > > Would indexable nil reduce runtime error detection?   No. > > Almost always another exception will be raised soon: > > "Attempt to perform arithmetic on a nil value" and the like. > > > > v = (pcall(function() t[a][b][c][d][e] end) or nil) and t[a][b][c][d][e] > > slightly cleaner. >
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On 2020-02-29 1:56 p.m., Philippe Verdy wrote: > I see no value at all in adding "or nil" (except that you'll change a > "false" stored value, returned without exception, into an "nil"). Then > why do you need "and t[a][b][c][d][e]" ? Wouldn' this be enough?: > >   _, v = pcall(function() return t[a][b][c][d][e] end) > > i.e. discard (_) the false/true status in the 1st return value of the > pcall, use the second value which is explicitly returned and will be > nil if the function does not return but throws an exception. actually it'll be the string "attempt to index a nil value" > > Le sam. 29 févr. 2020 à 17:43, Soni "They/Them" L. <[hidden email]> a écrit : > > > > > > > > On 2020-02-29 1:31 p.m., Egor Skriptunoff wrote: > > > On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote: > > > > > >     the error when trying to index a null value is a good thing. > > > > > > > > > > > > Let's assume the statement > > > v = t[a][b][c][d][e] > > > Each of 5 indexing steps might result in nil. > > > Sometimes you want to raise "Attempt to index a nil value" exception, > > > sometimes you want to ignore the exception. > > > > > > If nil is indexable, then it's pretty easy to raise the exception > > > v = assert(t[a][b][c][d])[e] > > > > > > But if nil is non-indexable, it's not easy to ignore the exception > > > v = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e] > > > > > > Indexable nil looks like a better alternative. > > > > > > Would indexable nil reduce runtime error detection?   No. > > > Almost always another exception will be raised soon: > > > "Attempt to perform arithmetic on a nil value" and the like. > > > > > > > v = (pcall(function() t[a][b][c][d][e] end) or nil) and t[a][b][c][d][e] > > > > slightly cleaner. > > >
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 Hmmm.. yes, but still "or nil" is not needed. For such situation, where you expect a function to return a value or an exception to catch in order to use an alternate (nil) value, I'd use a utility function to use pcall(): function onerror(func, alt)   local ok, value = pcall(func)   if ok then return value end   return alt end then: v = onerror(function() return t[a][b][c][d][e] end, nil) where you can choose which alternate value to use (not necessarily nil, could be 0 or an empty string or anything else) Le sam. 29 févr. 2020 à 19:07, Soni "They/Them" L. <[hidden email]> a écrit : > > > > On 2020-02-29 1:56 p.m., Philippe Verdy wrote: > > I see no value at all in adding "or nil" (except that you'll change a > > "false" stored value, returned without exception, into an "nil"). Then > > why do you need "and t[a][b][c][d][e]" ? Wouldn' this be enough?: > > > >   _, v = pcall(function() return t[a][b][c][d][e] end) > > > > i.e. discard (_) the false/true status in the 1st return value of the > > pcall, use the second value which is explicitly returned and will be > > nil if the function does not return but throws an exception. > > actually it'll be the string "attempt to index a nil value" > > > > > Le sam. 29 févr. 2020 à 17:43, Soni "They/Them" L. <[hidden email]> a écrit : > > > > > > > > > > > > On 2020-02-29 1:31 p.m., Egor Skriptunoff wrote: > > > > On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote: > > > > > > > >     the error when trying to index a null value is a good thing. > > > > > > > > > > > > > > > > Let's assume the statement > > > > v = t[a][b][c][d][e] > > > > Each of 5 indexing steps might result in nil. > > > > Sometimes you want to raise "Attempt to index a nil value" exception, > > > > sometimes you want to ignore the exception. > > > > > > > > If nil is indexable, then it's pretty easy to raise the exception > > > > v = assert(t[a][b][c][d])[e] > > > > > > > > But if nil is non-indexable, it's not easy to ignore the exception > > > > v = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e] > > > > > > > > Indexable nil looks like a better alternative. > > > > > > > > Would indexable nil reduce runtime error detection?   No. > > > > Almost always another exception will be raised soon: > > > > "Attempt to perform arithmetic on a nil value" and the like. > > > > > > > > > > v = (pcall(function() t[a][b][c][d][e] end) or nil) and t[a][b][c][d][e] > > > > > > slightly cleaner. > > > > > > >
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by Soni "They/Them" L. I’ve used some strongly typed languages that have a “try operator”. I think lua could use something similar.In this case something like t?[a]?[b]?[c]?[d]?[e], would be equivalent to t[a][b][c][d][e], but if any evaluation preceded by a ? has a false value (false or nil), the result of the entire expression is that value (short circuiting). This only short circuits out of chains of index expressions (of all forms), and function calls. Would that be something that would work in lua?On Sat, Feb 29, 2020 at 13:07 Soni "They/Them" L. <[hidden email]> wrote: On 2020-02-29 1:56 p.m., Philippe Verdy wrote: > I see no value at all in adding "or nil" (except that you'll change a > "false" stored value, returned without exception, into an "nil"). Then > why do you need "and t[a][b][c][d][e]" ? Wouldn' this be enough?: > >   _, v = pcall(function() return t[a][b][c][d][e] end) > > i.e. discard (_) the false/true status in the 1st return value of the > pcall, use the second value which is explicitly returned and will be > nil if the function does not return but throws an exception. actually it'll be the string "attempt to index a nil value" > > Le sam. 29 févr. 2020 à 17:43, Soni "They/Them" L. <[hidden email]> a écrit : > > > > > > > > On 2020-02-29 1:31 p.m., Egor Skriptunoff wrote: > > > On Sat, Feb 29, 2020 at 5:42 PM Italo Maia wrote: > > > > > >     the error when trying to index a null value is a good thing. > > > > > > > > > > > > Let's assume the statement > > > v = t[a][b][c][d][e] > > > Each of 5 indexing steps might result in nil. > > > Sometimes you want to raise "Attempt to index a nil value" exception, > > > sometimes you want to ignore the exception. > > > > > > If nil is indexable, then it's pretty easy to raise the exception > > > v = assert(t[a][b][c][d])[e] > > > > > > But if nil is non-indexable, it's not easy to ignore the exception > > > v = (((((t or {})[a] or {})[b] or {})[c] or {})[d] or {})[e] > > > > > > Indexable nil looks like a better alternative. > > > > > > Would indexable nil reduce runtime error detection?   No. > > > Almost always another exception will be raised soon: > > > "Attempt to perform arithmetic on a nil value" and the like. > > > > > > > v = (pcall(function() t[a][b][c][d][e] end) or nil) and t[a][b][c][d][e] > > > > slightly cleaner. > > >
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On Sat, Feb 29, 2020 at 9:26 PM connor horman wrote:I’ve used some strongly typed languages that have a “try operator”.t?[a]?[b]?[c]?[d]?[e] would be equivalent to t[a][b][c][d][e], but if any evaluation preceded by a ? has a false value (false or nil), the result of the entire expression is that value (short circuiting). This only short circuits out of chains of index expressions (of all forms), and function calls.What about adding "try-version" of every Lua operator?   t?[index]   = indexing: return nothing if t is nil   t?.field    = indexing: return nothing if t is nil   t?:method() = invoking a method, return nothing if t is nil   func?(arg1,arg2,..) = calling a function: return all the arguments if func is nil   a ?+ b = adding: (a or 0)+(b or 0)     ?- a = negating: -(a or 0)   a ?~ b = XORing: (a or 0)~(b or 0)   a ?& b = ANDing: (a or -1)&(b or -1)   a ?* b = multiplying: (a or 1)*(b or 1)   a ?/ b = dividing: (a or 0)/(b or 1)   a ?% b = taking modulo: (a or 0)%(b or infinity)   a ?^ b = raising to power: (a or 0)^(b or 1)   a ?< b = comparing: nil is replaced with the minimal possible value of the datatype   a ?== b = comparing: nil is replaced with 0 or empty string depending on the datatype   a ?.. b = concatenating: (a or '')..(b or '')      ?# a = taking length: return 0 if a is nil
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On Sat, Feb 29, 2020 at 14:29 Egor Skriptunoff <[hidden email]> wrote:On Sat, Feb 29, 2020 at 9:26 PM connor horman wrote:I’ve used some strongly typed languages that have a “try operator”.t?[a]?[b]?[c]?[d]?[e] would be equivalent to t[a][b][c][d][e], but if any evaluation preceded by a ? has a false value (false or nil), the result of the entire expression is that value (short circuiting). This only short circuits out of chains of index expressions (of all forms), and function calls.What about adding "try-version" of every Lua operator?   t?[index]   = indexing: return nothing if t is nil   t?.field    = indexing: return nothing if t is nil   t?:method() = invoking a method, return nothing if t is nil   func?(arg1,arg2,..) = calling a function: return all the arguments if func is nil   a ?+ b = adding: (a or 0)+(b or 0)     ?- a = negating: -(a or 0)   a ?~ b = XORing: (a or 0)~(b or 0)   a ?& b = ANDing: (a or -1)&(b or -1)   a ?* b = multiplying: (a or 1)*(b or 1)   a ?/ b = dividing: (a or 0)/(b or 1)   a ?% b = taking modulo: (a or 0)%(b or infinity)   a ?^ b = raising to power: (a or 0)^(b or 1)   a ?< b = comparing: nil is replaced with the minimal possible value of the datatype   a ?== b = comparing: nil is replaced with 0 or empty string depending on the datatype   a ?.. b = concatenating: (a or '')..(b or '')      ?# a = taking length: return 0 if a is nilMany of these, excluding ?# don’t have sensible defaults with operator overloading (which we get from metatables). All forms of indexing and function calls are easy: evaluate the expression if the root (t in this case) is neither false nor nil, otherwise, return the root.  Adding the rest would complicate things greatly.
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by connor horman In this case something like t?[a]?[b]?[c]?[d]?[e], would be equivalent to t[a][b][c][d][e], but if any evaluation preceded by a ? has a false value (false or nil), the result of the entire expression is that value (short circuiting). This only short circuits out of chains of index expressions (of all forms), and function calls. Would that be something that would work in lua?Back in 2013, I added both "safe navigation" and "required field" shorthands to my Lua parser.  So t?[a]?.b will evaluate as nil if any of the component expressions are nil, while t![a]!.b will instead throw an error message like " is missing required field 'b'", if, say, t[a].b==nil.  Safe navigation, in various forms, is pretty easy to add to Lua.  A "required field" semantic is harder to mod in, and it's really just a slightly terser way of writing boilerplate asserts, but I think it's still useful to have around.Since I wrote that patch, Apple's Swift has become quite popular, and while it's a strongly typed compiled language, Swift's syntax for optional and required fields is fairly similar to what I did inside my Lua parser.  Thanks to Swift, a lot more programmers have become used to '?' and '!' semantics.  That said, the details of how, exactly, the semantics of either ought to work in the context of Lua remain highly debatable (and those details have been debated on this list in the past).-Sven
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by connor horman On Sat, Feb 29, 2020 at 10:35 PM connor horman wrote:Many of these, excluding ?# don’t have sensible defaults with operator overloading (which we get from metatables).Overloaded operators should receive unmodified nil.If obj has addition overloaded in its metatable thenobj ?+ nilshould be the same asobj + nil
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by Anton Jordaan Wouldn't it be enough to write a function to do this type-checking for you instead of having the language *always* do it? ‣ Doing this would make debugging harder, as error messages wouldn't tell you what's missing, but just that somewhere in the chain of values there's a nil ‣ I assume the additional condition might have a negative impact on performance, though this might be very small and irrelevant ‣ Ruby does this with the safe navigation operator `nil&.do_stuff`; maybe something similar would be a better choice (though I personally don't think it's necessray) You could easily use something like this: local function index(object, idx, ...)     if idx then         if object[idx] then             return index(object, ...)         end     else         return object     end end local value = index(some_4d_table, x, 20, z, "foobar") To traverse a list of nested tables until the end of a list of keys or a missing key in some subtable (which would then return nil). Similarly, you could write a function like this to insert missing tables according to a chain of indices: local function insert(object, value, idx, ...)     if ... then         if not object[idx] then             object[idx] = {}         end         insert(object, value, ...)     else         object[idx]  = value     end end insert(some_4d_table, "Hello, World!", 'foo', 'bar', 'baz', 'message') On 28/02/2020 22:59, Anton Jordaan wrote: > Lua is memory efficient for huge but sparse multi-dimensional arrays, > since nil values aren't stored in the tables. > > However, reading and writing to such sparse multi-dimensional arrays > can be quite a hassle.  If I want to access the value of > t[a][b][c][d][e], I first have to check whether t[a] is a table, > t[a][b] is a table, t[a][b][c] is a table etc, otherwise Lua throws an > error "Attempt to index a nil value". > > > For example, to read the value at t[a][b][c][d][e], I cannot simply use: > v = t[a][b][c][d][e] > Instead, the code must look something like: > v = t and t[a] and t[a][b] and t[a][b][c] and t[a][b][c][d] and > t[a][b][c][d][e] > > > Or, to write a value to t[a][b][c][d][e], I cannot simply use: > t[a][b][c][d][e] = v > > Instead, the code must look something like: > > if not t then t = {[a] = {[b] = {[c] = {[d] = {[e] = v}}}}} > elseif not t[a] then t[a] = {[b] = {[c] = {[d] = {[e] = v}}}} > elseif not t[a][b] then t[a][b] = {[c] = {[d] = {[e] = v}}} > elseif not t[a][b][c] then t[a][b][c] = {[d] = {[e] = v}} > elseif not t[a][b][c][d] then t[a][b][c][d] = {[e] = v} > else t[a][b][c][d][e] = v > end > > I suggest that it would be more useful -- and more consistent -- if > the "Attempt to index a nil value" error is deprecated and, instead, > the indexing of undefined variables does the following: > > When reading: simply return nil.  Given that undefined variables and > non-existent table entries both return nil, I think it would be more > consistent if an attempt to index an undefined variable also simply > returns nil.  (The Lua FAQ states that: "In many languages, trying to > access a non-existent key in a list or dictionary causes an exception; > in Lua the result is simply nil. This is unambiguous because nil > cannot be usefully put into tables.")  If t is nil, then t[a] should > also simply be nil, as should t[a][b][c][d][e]. > > When writing: automatically assign a single-entry table to each > undefined variable, with the given index the sole entry.  For example, > if t is an undefined variable, then t[a] = v would be syntactic sugar > for t = {[a] = v}.  Similarly, if t[a][b] is already declared as a > table but t[a][b][c] is nil, then t[a][b][c][d][e] = v would mean > t[a][b][c] = {[d] = {[e] = v}}. > > > -- Anton > > signature.asc (849 bytes) Download Attachment
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 In reply to this post by Anton Jordaan It was thus said that the Great Anton Jordaan once stated: > > When writing: automatically assign a single-entry table to each > undefined variable, with the given index the sole entry.  For example, > if t is an undefined variable, then t[a] = v would be syntactic sugar > for t = {[a] = v}.  Similarly, if t[a][b] is already declared as a table > but t[a][b][c] is nil, then t[a][b][c][d][e] = v would mean t[a][b][c] = > {[d] = {[e] = v}}.   Let's assume for a second this exists.  Here are some of the issues that need to be addressed for this to work. 1) t[a] = v         This is syntactic sugar for t = { [a] = v }.  Then does that mean:                 local t[a] = v         is legal?  Otherwise, this may lead to a proliferation of unintended         globals.  Also, what about:                 t[a],t[b],t[c] = 1,2,3         How does this play out, syntactic surgar wise?  Because as it is,                 local t[a],t[b],t[c] = 1,2,3         is similar to:                 local a,a = 1,2 print(a)         and it's the second declaration that survives (Lua 5.3).  Weirder,         in the following:                 a,a = 1,2 print(a)         it's the first declaration that survives.  This may require more of         a change to Lua than expected. 2) t[a][b][c][d][e] = v -- when t[a][b] exists         An asusmption being made is that a,b,c,d,e are all tables.  They         don't have to be.  It could be a userdata that responds to both         __index and __newindex to act like a table.  Then this is fine, but         what if b *doesn't* respond to __newindex?  You either throw an         error, which is unexpected in this construct or replace b with a         table, which can cause extended debugging issues trying to figure         out why the code is failing (most likely in an area far from where         the bug actually exists!). 3) v = t[a][b][c][d][e]         v ends up nil.  Which index is nil? 4) t[a] [ t[B] ] [c][d][e] = v         If t doesn't exist, then what do we end up with?  If B doesn't         exist, what do we end up with?  It's hard to think about.  The         assumption is that a,b,c,d,e are all either strings or numbers, but         in reality, the index can be any value but nil or NaN.  If tables         are created for missing values, then you end up with a unique table         as an index in a. 5) t[a][0/0][c][d][e] = v         The previous question brings this up---what if the index is NaN?         Rare, but possible.  Treat it as nil?  Error?   I know a reaction is "don't do that!" or "it's for the case when they are all tables" but I contend that typos happen, bugs exist, people don't read the manual closely enough and these issues *will* come up, and need to be addressed (even if to detect and throw an error).   -spc
Open this post in threaded view
|

## Re: Suggestion: Deprecate "Attempt to index a nil value" error; instead, return nil or create table

 On Mon, Mar 2, 2020 at 2:22 AM Sean Conner wrote:                local a,a = 1,2 print(a)         and it's the second declaration that survives (Lua 5.3).  Weirder,         in the following:                 a,a = 1,2 print(a)         it's the first declaration that survives.  The order in a multiple assignment in Lua is UB, so your program's behavior must not depend on the order.  3) v = t[a][b][c][d][e]         v ends up nil.  Which index is nil?The whole point of the proposal is to not bother user with such details.An expression should "just work".   I contend that typos happen, bugs exist  Yes, the expression t[a][b][c][d][e] will not detect a mistake.But returned nil would probably raise an error on the next line of your code(if the logic of your program expects non-nil value). The point is that we need "silent" version of t[a][b][c][d][e] much more frequently than "error-raising" version.We can easily convert "silent" version to "error-raising" by applying assign() to the result.But the reverse conversion is significantly harder.