Problem extending a table

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

Problem extending a table

peterhickman
I have some code that I want to use to add an invert method to tables.

table.invert = function (t)
	local i = {}
	for k in pairs(t) do
		i[t[k]] = true
	end
	return i
end

When I call it as "table.invert(a)" it works fine, but it errors when I call it as "a:invert()"

lua: invert.lua:15: attempt to call method 'invert' (a nil value)

My understanding was that a:invert() was just sugar on table.invert(a), what am I doing wrong?


Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

Matthew Wild
On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]> wrote:
> I have some code that I want to use to add an invert method to tables.
>
> table.invert = function (t)
>        local i = {}
>        for k in pairs(t) do
>                i[t[k]] = true
>        end
>        return i
> end
>
> When I call it as "table.invert(a)" it works fine, but it errors when I call
> it as "a:invert()"
>
> lua: invert.lua:15: attempt to call method 'invert' (a nil value)
>
> My understanding was that a:invert() was just sugar on table.invert(a), what
> am I doing wrong?
>

a:invert(var) is sugar for a.invert(a, var)

Since "invert" isn't a field in a, it won't work. You can set a
metatable however: setmetatable(a, { __index = table }) which will
make it work as you wish, fetching table.invert when a.invert is nil.
Just beware that if you set a.invert yourself, or a.insert, etc. it
will use that instead of table.invert, table.insert, etc.

Matthew.

Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

Duncan Cross
In reply to this post by peterhickman

On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]> wrote:
I have some code that I want to use to add an invert method to tables.

table.invert = function (t)
       local i = {}
       for k in pairs(t) do
               i[t[k]] = true
       end
       return i
end

When I call it as "table.invert(a)" it works fine, but it errors when I call it as "a:invert()"

lua: invert.lua:15: attempt to call method 'invert' (a nil value)

My understanding was that a:invert() was just sugar on table.invert(a), what am I doing wrong?

a:invert() is actually sugar for a.invert(a), which will only be equivalent to table.invert(a) if you have a metatable set on 'a' which looks up the 'table' library when __index is called.

The situation is different with strings because all string values share a common metatable, while tables each individually have their own metatable, which by default is nil. Therefore tables will never inherit any methods as soon as they are created, something has to be done to provide them.
Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

peterhickman
I can see what you are both saying but I came from code like this:

string.fred = function (s)
return s..s
end

a = "xxx"
print(a)
b = a:fred()
print(b)

Which does work. It has added a method to the string object and an instance of a string has picked up the method. I thought that it would also work for tables also

On 14 Feb 2009, at 14:08, Duncan Cross wrote:


On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]> wrote:
I have some code that I want to use to add an invert method to tables.

table.invert = function (t)
       local i = {}
       for k in pairs(t) do
               i[t[k]] = true
       end
       return i
end

When I call it as "table.invert(a)" it works fine, but it errors when I call it as "a:invert()"

lua: invert.lua:15: attempt to call method 'invert' (a nil value)

My understanding was that a:invert() was just sugar on table.invert(a), what am I doing wrong?

a:invert() is actually sugar for a.invert(a), which will only be equivalent to table.invert(a) if you have a metatable set on 'a' which looks up the 'table' library when __index is called.

The situation is different with strings because all string values share a common metatable, while tables each individually have their own metatable, which by default is nil. Therefore tables will never inherit any methods as soon as they are created, something has to be done to provide them.

Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

Kristofer Karlsson
The difference is that strings share a metatable with __index set to the string table as default.
This is not true for generic tables, since individual tables can be set to different metatables.
If you want, you can do:
setmetatable(a, {__index = table}) and get the behaviour you wanted for table a


On Sat, Feb 14, 2009 at 3:35 PM, Peter Hickman <[hidden email]> wrote:
I can see what you are both saying but I came from code like this:

string.fred = function (s)
return s..s
end

a = "xxx"
print(a)
b = a:fred()
print(b)

Which does work. It has added a method to the string object and an instance of a string has picked up the method. I thought that it would also work for tables also

On 14 Feb 2009, at 14:08, Duncan Cross wrote:


On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]> wrote:
I have some code that I want to use to add an invert method to tables.

table.invert = function (t)
       local i = {}
       for k in pairs(t) do
               i[t[k]] = true
       end
       return i
end

When I call it as "table.invert(a)" it works fine, but it errors when I call it as "a:invert()"

lua: invert.lua:15: attempt to call method 'invert' (a nil value)

My understanding was that a:invert() was just sugar on table.invert(a), what am I doing wrong?

a:invert() is actually sugar for a.invert(a), which will only be equivalent to table.invert(a) if you have a metatable set on 'a' which looks up the 'table' library when __index is called.

The situation is different with strings because all string values share a common metatable, while tables each individually have their own metatable, which by default is nil. Therefore tables will never inherit any methods as soon as they are created, something has to be done to provide them.


Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

Peter Cawley
Imagine for a minute what would happen *if* tables automatically had a
{__index = table} metatable:
* Checks like "if getmetatable(t) == nil then" to see if a table has a
metatable would fail
* Tables which contained members like "sort" and "concat" would cause
code which used the t:sort() syntax to fail
* All tables would have fields like "sort" and "concat" by default,
causing code like "t.sort = t.sort or 'ascending'" to fail

In short, it would cause more problems that it would solve.

On Sat, Feb 14, 2009 at 2:40 PM, Kristofer Karlsson
<[hidden email]> wrote:
> The difference is that strings share a metatable with __index set to the
> string table as default.
> This is not true for generic tables, since individual tables can be set to
> different metatables.
> If you want, you can do:
> setmetatable(a, {__index = table}) and get the behaviour you wanted for
> table a
>
>
> On Sat, Feb 14, 2009 at 3:35 PM, Peter Hickman <[hidden email]> wrote:
>>
>> I can see what you are both saying but I came from code like this:
>> string.fred = function (s)
>> return s..s
>> end
>> a = "xxx"
>> print(a)
>> b = a:fred()
>> print(b)
>> Which does work. It has added a method to the string object and an
>> instance of a string has picked up the method. I thought that it would also
>> work for tables also
>> On 14 Feb 2009, at 14:08, Duncan Cross wrote:
>>
>> On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]>
>> wrote:
>>>
>>> I have some code that I want to use to add an invert method to tables.
>>>
>>> table.invert = function (t)
>>>        local i = {}
>>>        for k in pairs(t) do
>>>                i[t[k]] = true
>>>        end
>>>        return i
>>> end
>>>
>>> When I call it as "table.invert(a)" it works fine, but it errors when I
>>> call it as "a:invert()"
>>>
>>> lua: invert.lua:15: attempt to call method 'invert' (a nil value)
>>>
>>> My understanding was that a:invert() was just sugar on table.invert(a),
>>> what am I doing wrong?
>>
>> a:invert() is actually sugar for a.invert(a), which will only be
>> equivalent to table.invert(a) if you have a metatable set on 'a' which looks
>> up the 'table' library when __index is called.
>>
>> The situation is different with strings because all string values share a
>> common metatable, while tables each individually have their own metatable,
>> which by default is nil. Therefore tables will never inherit any methods as
>> soon as they are created, something has to be done to provide them.
>>
>
>

Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

peterhickman
Ah right,

Thanks guys I understand now.

Thanks

On 14 Feb 2009, at 14:45, Peter Cawley wrote:

Imagine for a minute what would happen *if* tables automatically had a
{__index = table} metatable:
* Checks like "if getmetatable(t) == nil then" to see if a table has a
metatable would fail
* Tables which contained members like "sort" and "concat" would cause
code which used the t:sort() syntax to fail
* All tables would have fields like "sort" and "concat" by default,
causing code like "t.sort = t.sort or 'ascending'" to fail

In short, it would cause more problems that it would solve.

On Sat, Feb 14, 2009 at 2:40 PM, Kristofer Karlsson
<[hidden email]> wrote:
The difference is that strings share a metatable with __index set to the
string table as default.
This is not true for generic tables, since individual tables can be set to
different metatables.
If you want, you can do:
setmetatable(a, {__index = table}) and get the behaviour you wanted for
table a


On Sat, Feb 14, 2009 at 3:35 PM, Peter Hickman <[hidden email]> wrote:

I can see what you are both saying but I came from code like this:
string.fred = function (s)
return s..s
end
a = "xxx"
print(a)
b = a:fred()
print(b)
Which does work. It has added a method to the string object and an
instance of a string has picked up the method. I thought that it would also
work for tables also
On 14 Feb 2009, at 14:08, Duncan Cross wrote:

On Sat, Feb 14, 2009 at 2:02 PM, Peter Hickman <[hidden email]>
wrote:

I have some code that I want to use to add an invert method to tables.

table.invert = function (t)
      local i = {}
      for k in pairs(t) do
              i[t[k]] = true
      end
      return i
end

When I call it as "table.invert(a)" it works fine, but it errors when I
call it as "a:invert()"

lua: invert.lua:15: attempt to call method 'invert' (a nil value)

My understanding was that a:invert() was just sugar on table.invert(a),
what am I doing wrong?

a:invert() is actually sugar for a.invert(a), which will only be
equivalent to table.invert(a) if you have a metatable set on 'a' which looks
up the 'table' library when __index is called.

The situation is different with strings because all string values share a common metatable, while tables each individually have their own metatable, which by default is nil. Therefore tables will never inherit any methods as
soon as they are created, something has to be done to provide them.





Reply | Threaded
Open this post in threaded view
|

Re: Problem extending a table

Luiz Henrique de Figueiredo
In reply to this post by peterhickman
> table.invert = function (t)
> 	local i = {}
> 	for k in pairs(t) do
> 		i[t[k]] = true
> 	end
> 	return i
> end

A faster version that avoids double indexing:

  table.invert = function (t)
  	local i = {}
  	for k,v in pairs(t) do
  		i[v] = true
  	end
  	return i
  end