Issue
While trying to learn lua I accidentally found out that if
a = {"a"}
b = a
than this produces (no surprise):
a
{"a"} --[[table: 0x046bde18]]
b
{"a"} --[[table: 0x046bde18]]
but then if:
a[2] = "b"
why is a == b still true?
a
{"a", "b"} --[[table: 0x046bde18]]
b -- this is a surprise
{"a", "b"} --[[table: 0x046bde18]]
This seem to work both ways: if a new value is assigned to b then it will be also assigned to a.
On the other hand if I assign a a value (example: a = 1) and b = a then if a value is changed (a = 2) then b retains the original value (still b = 1).
Questions
Why is this behaviour different depending on wheather a is an array/table or a value? Is it due to built-in metatables (__newindex)?
What is the purpose of such behaviour of arrays/tables?
What if I wanted/needed to somehow seperate a and b (or what to do if I wanted to store the values of a before changing b)?
(I read Lua Assignment and Metatables and Metamethods chapters of the Lua Reference Manual but still have no clue why such behaviour occures.)
In your example, a and b are just references to the same table. In Lua, tables are objects, and you created a table and assigned it to a with the first statement, and then you created a second reference to the same table with the second assignment. So, both a[2] = "b" and b[2] = "b" are acting on the same underlying table (table: 0x046bde18).
A table is not a value, it is an object. a = {"a"} constructs a table and assigns a reference to the table to a. b = a assigns the same reference to b. But, x = 10 assigns the value 10 to x. If y = 10 and you could change the underlying value of 10, I suppose that this change would be reflected in both x and y, but I know of no obvious way to do this. In this code:
x = 10
y = 10
y = y + 1
the resulting values will be x = 10, and y = 11. The underlying value of 10 has not changed, but y was reassigned to the value 11.
If you want to work with two copies of the table that can change independently, you would need to write a function that copies the members of a into b = {}. Here is a question that discusses making copies of tables.
Related
When creating an element in the table, I need to use another element that I created before in the same table. please help me with this.
local table = {
distance = 30.0,
last_distance = table.distance-10.0
}
I want to do the above operation but I can't, I think I need to use self or setmetatable but I don't know how to do it. and please don't give me answers like first create a value outside and then use it in the table, I don't want to do that.
Basic life advice
First of all: Don't call your table table. That will shadow the global table library. Call it t, tab, tabl, Table, table_, or actually give it a useful name, but don't call it table, or there'll be a big surprise when you try to access any table.* methods. Ideally, your linter should warn you about this.
Implementing it using hacks
Table constructors are equivalent to creating a table on the stack - there is no named local variable self or the like. It is likely possible that there is a hidden local variable accessible using debug.getlocal however:
$ lua
Lua 5.4.4 Copyright (C) 1994-2022 Lua.org, PUC-Rio
> function getlocals()
>> local i = 1; repeat local k, v = debug.getlocal(2, i); i = i + 1; print(k, v) until not k
>> t = {a = getlocals(), b = ()}
stdin:3: unexpected symbol near ')'
> function getlocals()
local i = 1; repeat local k, v = debug.getlocal(2, i); i = i + 1; print(k, v) until not k end
> t = {a = getlocals(), b = 2}
(temporary) table: 0x55e9181302d0
nil nil
> t
table: 0x55e9181302d0
Indeed, from basic testing it appears that this is even the first local inside the table constructor! However, it isn't quite as easy:
> local a = 1; local b = a; t = {a = getlocals(), b = 2}; print(b)
a 1
b 1
(temporary) table: 0x55e918130160
nil nil
1
Using extensive hacks, you might be able to write something that returns the currently constructed table most of the time (probably relying on the fact that it will usually be the last local). The following works:
function lastlocal()
local i = 0
local last
::next:: -- you could (and perhaps should) use a loop instead
i = i + 1
local k, v = debug.getlocal(2, i)
if v then
last = v
goto next
end
return last
end
from my basic testing, this works fine to obtain the table currently being constructed:
> function lastlocal()
local i = 0
local last
::next:: -- you could (and perhaps should) use a loop instead
i = i + 1
local k, v = debug.getlocal(2, i)
if v then
last = v
goto next
end
return last
end
> t = {a = 1, b = lastlocal().a}
> t.a
1
> t.b
1
Why you should not implement this using hacks
With all of this in mind: Don't ever do this. The purpose of this merely is to lead this ad absurdum. There are multiple reasons why this is horribly unreliable:
The order of execution of table constructor assignments is undefined. An optimizing interpreter like LuaJIT (and the PUC Lua implementation just as well) is free to reorder {a = 1, b = 2} to {b = 2, a = 1}.
Likewise, how table constructors are implemented internally is entirely undefined. There is no guarantee that the local variable actually exists and is the last one.
It is horribly inefficient and relies on the debug library for something other than debugging.
What's a metatable?
Metatables serve an entirely different purpose; you could dynamically generate derived fields like last_distance using them, but you can't use them to reference a table using a table constructor. Here's a basic example:
local t = {distance = 30}
setmetatable(t, {__index = function(self, k)
if k ~= "last_distance" then return nil end
return t.distance - 10 -- calculate `last_distance` & return it
end})
print(t.last_distance) -- 20
t.distance = 10
print(t.last_distance) -- 0
Back to the question
When creating an element in the table, I need to use another element that I created before in the same table.
The proper way to do this is to either (1) create a value outside of the table
local distance = 30
local last_distance = distance - 10
local tab = {distance = distance, last_distance = last_distance}
Perfectly readable, perfectly fine.
Or (2) first create a table with some properties, then add derived properties:
local tab = {distance = 30}
tab.last_distance = tab.distance - 10
as readable, as fine.
Both will be highly efficient; only micro-optimizations would be debatable (could (1) choose a better layout for the hashes by choosing the right insertion order? does it pre-allocate the right size (likely yes)? does (2) incur a penalty since it indexes tab to obtain tab.distance?), but none of this will likely ever matter.
I want to do the above operation but I can't, I think I need to use self or setmetatable but I don't know how to do it.
I have shown you:
How you can do it using egregious hacks and why you shouldn't.
How you can do something similar (derived attributes) using a metamethod.
and please don't give me answers like first create a value outside and then use it in the table, I don't want to do that.
This is the correct, idiomatic way to do this in Lua though. Your restriction seems arbitrary.
hi I'm trying to convert this python code to Lua
names=['Deepak','Reema','John','Deepak','Munna','Reema','Deepak','Amit','John','Reema']
d={}
for i in range(len(names)-1):
x=names[i]
c=0
for j in range(i,len(names)):
if names[j]==names[i]:
c=c+1
count=dict({x:c})
if x not in d.keys():
d.update(count)
print (d)
I got all the other parts working from top but I couldn't figure out how to convert this part into Lua
if x not in d.keys():
d.update(count)
would be really great if someone can help me make sense of this conversion
if x not in d.keys():
d.update(count)
x is the name currently indexed in that loop cycle
d is a dictionary that is used to store the count of each name
c is a dictionary with a single entry, the count c of x in names
So that line basically says:
if the current name x has not been counted yet (is not in our dictionary), add its count c to d using the name in x as key.
This code is not very efficient as it counts the names every time, even if that name has already been counted. The order should be changed so you only count if there is no count in d, yet.
There is also no need to iterate over the whole array for each entry. That nested loop is nonsense. You can count that in one go.
You shouldn't learn from whatever resource that is.
In Lua the snippet above would look something like:
if not d[x] then d[x] = c end
or simply
d[x] = d[x] or c
This is how you could implement it in Lua efficiently.
local names= {'Deepak','Reema','John','Deepak','Munna','Reema','Deepak',
'Amit','John','Reema'}
local counts = {}
for _, v in ipairs(names) do
counts[v] = counts[v] and counts[v] + 1 or 1
end
When creating a graph of calculations using delayed I'm trying to assign names so that if I visualize the graph it's readable. However, for delayed variables that are dependent on functions the name parameter doesn't seem to affect the key. Here's a toy example:
def calc_avg(a, b):
return pd.concat([a, b], axis=1).mean(axis=1)
def calc_ratio(a, b):
return a / b
a = delayed(pd.Series(np.random.rand(10)), name='a')
b = delayed(pd.Series(np.random.rand(10)), name='b')
c = delayed(pd.Series(np.random.rand(10)), name='c')
x = delayed(calc_avg, name='avg_result')(a,b)
y = delayed(calc_ratio, name='ratio_result')(x,c)
y.visualize()
You can see the visualization here (I can't embed images), but rather than seeing 'avg_result' I see 'calc_avg-#0' and rather than see 'ratio_result' I see 'calc_ratio-#1'. If I look at x.key or y.key they do not match the names that I provided. Is this the expected behavior?
The key of a dask result needs to be unique for every combination of the function that was delayed, and the inputs you give it. What you see above is the expected behaviour: you are naming the function, but a call with different inputs would expect a different output, so the key must be different.
You can specify the key you'd like associated not when you define the delayed function, but when you call it:
x = delayed(calc_avg)(a, b, dask_key_name='avg_result')
y = delayed(calc_ratio)(x, c, dask_key_name='ratio_result')
I have simplified my code so you can have a better understanding:
x = {}
x["foo"]=1
a = {}
a[1]=x
x["foo"]=2
a[2]=x
print(a[1]["foo"])
print(a[2]["foo"])
The result is:
2
2
Or I was expecting:
1
2
I understant that a[1] is directing at the adress of the table x["foo"]. Then, when I change the value of this table, the variable a[1] points to the new value.
How can I tell Lua that I want to assign the VALUE and not link to and adress?
And just another thing: if x is a "simple" variable, not an array, the value is passed:
y = {}
x = 1
a = {}
a[1] = x
x = 2
a[2] = x
print(a[1])
print(a[2])
returns
1
2
The Lua manual, last but one paragraph of §2.1, says:
Tables, functions, threads, and (full) userdata values are objects: variables do not actually contain these values, only references to them. Assignment, parameter passing, and function returns always manipulate references to such values; these operations do not imply any kind of copy.
a = b = c = d = 5
puts (a) >> 5
puts (b) >> 5
puts (b) >> 5
puts (b) >> 5
a= a+1
puts (a) >> 6
puts (b) >> 5
I found there is no problem with the assigning of values like this. My question is should one assign like the one given above or like this?
a , b, c, d = 5, 5, 5, 5
The thing to be aware of here is that your case only works OK because numbers are immutable in Ruby. You don't want to do this with strings, arrays, hashes or pretty much anything else other than numbers, because it would create multiple references to the same object, which is almost certainly not what you want:
a = b = c = d = "test"
b << "x"
=> "testx"
a
=> "testx"
Whereas the parallel form is safe with all types:
a,b,c,d = "test","test","test","test"
=> ["test", "test", "test", "test"]
b << "x"
=> "testx"
a
=> "test"
There's nothing wrong with assigning it that way (a = b = c = d = 5). I personally prefer it over multiple assignment if all the variables need to have the same value.
Here's another way:
a, b, c, d = [5] * 4
If it feels good, do it.
The language allows it, as you discovered, and it behaves as you'd expect. I'd suggest that the only question you should ask yourself regards expressiveness: is the code telling you what its purpose is?
Personally, I don't particularly like using this construct for much other than initialisation to default values, preferably zero. Ideally the variables so initialised would all have a similar purpose as well, counters, for example. But if I had more than a couple of similarly-purposed variables I might very well consider declaring them to be a form of duplicate, to be refactored out into, for example, a Hash.
These two initializations express different meaning. The a = b = c = d = 5 means "all my variables should be initialized to the same value, and this value is 5". The other one, a, b, c, d = 5, 5, 5, 5, means "I have a list of variables, and corresponding list of init values".
Is your logic such that all the variables should always be the same? Then the first one is better. If not, the second one might be better. Another question: is your list of 4 variables comprehensive? is it likely that you will add or remove another variable to this group? If so, I'd suggest yet another variant instead:
a = 5
b = 5
c = 5
d = 5
I once got bitten with that one. It may save you a few keystrokes today but come to bite you later. As #glenn mentioned, it creates multiple references to the same object.
Example: This applies to both ruby 1.8 and 1.9
> a = b = Array.new
=> []
> a.object_id == b.object_id
=> true
> a << 1
=> [1]
> b << 2
=> [1, 2]
I don't use ruby at all, so that might be an acceptable idiom, but a = b = c = d = 5 looks pretty ugly to me. a , b, c, d = 5, 5, 5, 5 looks much nicer, IMO.