|
| 24 Jul 2014 08:08 AM |
LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else rawset(tab, var, {}) local Nex = nil local Pre = nil for i,v in pairs(tab) do if v == tab[var] then Nex = tab[i + 1] Pre = tab[i - 1] end end local List = {Next = Nex, Prev = Pre, Value = val} rawset(tab, var, List) end end }) end }
X = LinkedList.new() X[1] = {5} X[2] = {10} X[3] = {15}
V1 = X[1]
print(V1.Next.Value)
It outputs;
Runtime Error: LinkedList.lua:32: attempt to index field 'Next' (a nil value)
Any help would be greatly appreciated :D |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 08:30 AM |
You're going to have to update each one after you create a new key, or just use the index metamethod
What's happening is when you do X[1] = {5} Next and Pre will be nil (since there is nothing in X[0] or X[2] and when you append to the table, Next and Pre still are nil since it was already set. |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 08:34 AM |
So something like:
LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else local tbl = {}; setmetatable(tbl, { __index = function(_tab, _var, _val) local Nex = nil local Pre = nil for i,v in pairs(tab) do if v == tab[var] then Nex = tab[i + 1] Pre = tab[i - 1] end end local List = {Next = Nex, Prev = Pre, Value = val} return List[_var]; end; }); rawset(tab, var, tbl); end end }); end }
X = LinkedList.new() X[1] = {5} X[2] = {10} X[3] = {15}
V1 = X[1]
print(V1.Next) |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 08:39 AM |
| Woops made a closure error, 1 second. |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 08:47 AM |
I just tried this;
LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else rawset(tab, var, {}) local List = setmetatable({Value = val}, { __index = function(tab2, val2) local Loc = nil for i, v in pairs(tab) do if v == tab2 then Loc = i end end if val2 == "Next" then return tab[Loc + 1] elseif val2 == "Prev" then return tab[Loc - 1] end end }) rawset(tab, var, List) end end }) end }
X = LinkedList.new() X[1] = {5} X[2] = {10} X[3] = {15}
V1 = X[1]
print(V1.Prev.Value[1])
It works!!!
Oh, and I made this after your first post. I never even saw your example for this.
Are there any potential errors that could happen with mine? |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 08:51 AM |
It should be fine, but you shouldn't put Value directly in the table since they can change it, unless that was intentional? Anyway filter wouldn't let me repost so I'm going to change some variable names, if yours doesn't work properly (which it should):
LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else local tbl = {}; setmetatable(tbl, { __index = function(_tab, _var) local Nex = tab[var + 1]; local Pre = tab[var - 1]; local List = {Next = Nex, Prev = Pre, Value = val[1]}; return List[_var]; end; }); rawset(tab, var, tbl); end end }); end }
X = LinkedList.new() X[1] = {5} X[2] = {10} X[3] = {15}
V1 = X[1] |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 08:52 AM |
| And of course if it wasn't intentional, you should lock the metatable so they can't change it using getmetatable. |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 08:58 AM |
I want a LinkedList to simply be a table of values except using tables to include Next and Prev, so yes, it was intentional for them to be able to change the value.
Although I will be locking the metatable... |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:00 AM |
| 1 question, why x[1] = {3} and not x[1] = 3 and handle it as a table inside the __newindex metamethod? Makes using it "cleaner" I guess |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 09:06 AM |
This is getting complicated XD
When I first started I was thinking to myself "This'll be simple, I'll just make a function that creates a table with tables that have Next and Prev in them.
Now all of a sudden I have this giant function handling everything with __newindex and __index
What I really hate is that table.insert and rawset can both insert values that aren't tables, without triggering __newindex.
If I handled it with __index though I could fix that too right? I'm trying to figure out how I'd do it... |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 09:08 AM |
| I don't suppose you could edit my script so that I could say X[1] = 5 and so table.insert/rawset will be useable? |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:13 AM |
It's possible, there are 2 methods I can think of: -newproxy (slightly slow, only Lua 5.1 (or less?)) -real table hidden in scope (can cause memory leaks since the table will never get GC'd unless you handle that) |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:15 AM |
| I can't see a way how using __index will help |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 09:24 AM |
I could use __index to detect when someone accesses the value, and return a table?
By the way I'm using Lua 5.2 |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:26 AM |
| How would that help in preventing table.insert/rawset, or do you mean using a fake table (the 2nd option I mentioned) |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 09:34 AM |
| Exactly, could you do that? |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:38 AM |
Something like this might work (so they can't insert into the "real table") LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else local tbl = {}; setmetatable(tbl, { __index = function(_tab, _var) local Nex = tab[var + 1]; local Pre = tab[var - 1]; local List = {Next = Nex, Prev = Pre, Value = val[1]}; return List[_var]; end; __metatable = "The metatable is locked."; }); local fake = setmetatable({}, {__index = tbl, __newindex = tbl;}); rawset(tab, var, fake); end end; __metatable = "The metatable is locked."; }); end } |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 09:40 AM |
But since they can still insert into the fake table, they can still mess with the indexing.
The only fool-proof way I can think of is newproxy but you're on Lua 5.2 |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 10:34 AM |
local function newproxy() --I'm just gonna assume you need a metatable attached to it... return setmetatable({}, { __newindex = function(tab, var, val) return error("Attempt to add a value into a userdata", 2) end, __index = function(tab, var) return error("Attempt to index a value in a userdata", 2) end }) end
That could *kind of* mimic newproxy? |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 10:39 AM |
No. The same problem applies: you can table.insert and rawset. Proxies are much like "finalizes" as well, that you can't set properties at all (rawset/table.insert will give you an error, prox[k]=v invokes __newindex
So in Lua 5.1 you could simply do:
local tbl = newproxy(true); local mt = getmetatable(tbl); tbl.__index = blah; tbl.__metatable = blah; |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 02:57 PM |
I just realized I'm using Lua 5.2 not Rblx.Lua.
local rawget = nil local table.insert = function(Tab, Ind, Val) local Ind = Ind local Val = Val or Ind if Val == Ind then Ind = NumOfTab(Tab) + 1 end Tab[Ind] = Val end
Couldn't I just overwrite them? |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 03:00 PM |
You have syntax errors but yes, you can. However you will run into problems replacing rawget/rawset if you use them in your metamethods.
You can do it in Rbx.Lua too, just with a different approach: local table = {}; do local _table = table; table = setmetatable({insert = blah}, {__index = _table;}); end |
|
|
| Report Abuse |
|
|
cntkillme
|
  |
| Joined: 07 Apr 2008 |
| Total Posts: 44956 |
|
|
| 24 Jul 2014 03:00 PM |
Woops:
local _table = table; local table = {}; table = setmetatable({insert = blah}, {__index = _table;}); _table = nil; |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 03:47 PM |
Hmmm
Well I could make something like
local __G = setmetatable({}, { rawset = rawset }) setmetatable(_G, { __metatable = getmetatable(_G), __newindex = function(tab, var, val) __G[var] = val _G = {} end, __index = function(tab, val) if val == "rawset" then --Did I get that right? return nil end end })
Is there a way to make that more secure?
lol this is getting more complicated then I had hoped... |
|
|
| Report Abuse |
|
|
|
| 24 Jul 2014 03:50 PM |
By the way, how'd you indent
Something like this might work (so they can't insert into the "real table") LinkedList = { new = function() return setmetatable({}, { __newindex = function(tab, var, val) if type(val) ~= "table" then error("Attempt to add a value " .. type(val) .. " to a LinkedList", 2) else local tbl = {}; setmetatable(tbl, { __index = function(_tab, _var) local Nex = tab[var + 1]; local Pre = tab[var - 1]; local List = {Next = Nex, Prev = Pre, Value = val[1]}; return List[_var]; end; __metatable = "The metatable is locked."; }); local fake = setmetatable({}, {__index = tbl, __newindex = tbl;}); rawset(tab, var, fake); end end; __metatable = "The metatable is locked."; }); end }
|
|
|
| Report Abuse |
|
|