This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
Swith's profile picture

Accessing the second of multiple returned variables

Started by Swith, 03 April 2013 - 04:58 AM
Swith #1
Posted 03 April 2013 - 06:58 AM
I was experimenting with the rednet API, and I found a problem.
rednet.receive()
returns three values, id, message, distance.

So, if you don't care what the id or the distance is, and you just want the message, you have to do something like:
local id, message = rednet.receive()

As distance is further down the 'list' (I'm not exactly sure how they are stored in terms of data structure) of values than message, you don't need to create an unneeded variable for it. However, this still creates a completely unnecessary variable, 'id'. Is there a way of accessing the second value directly?

If there is a solution to this specific to rednet then I would very much appreciate it, however, I would really like to know if there is a way you can do this directly in lua.

Many thanks!
– Swith
BigSHinyToys #2
Posted 03 April 2013 - 07:23 AM
Using the select function you can do this example

local function test()
return "one","two","three","four","five","six","seven","eight","nine"
end
local third,fourth = select(3,test())
print(third)
print(fourth)
Swith #3
Posted 03 April 2013 - 07:27 AM
Thank you SO much, this is exactly what I was looking for.

Do I need to close the thread?
BigSHinyToys #4
Posted 03 April 2013 - 07:44 AM
Thank you SO much, this is exactly what I was looking for.

Do I need to close the thread?
Changing the title to [Solved] is best practice but you don't need close it or rename it just let it drift down with the rest.
remiX #5
Posted 03 April 2013 - 07:52 AM
Another you could do this is just use _ or something to replace the variables you don't want:

local function test()
return "one","two","three","four","five","six","seven","eight","nine"
end
local _, _, third,fourth = test()
print(third)
print(fourth)

But I guess select function will work too (first time i've ever seen it, so i've learnt something new today :P/> )
JokerRH #6
Posted 03 April 2013 - 07:56 AM
However, this still creates a completely unnecessary variable, 'id'.

Select works, but still, it creates an unnecessary variable as far as I know, because it should look something like that:

function select(ind, ...)
  local arg = {...}
  return arg[ind]
end

Alternatively, many people use _ as an indikator for an unnecessary variable.
local _, id = rednet.receive()

Edit: Already to slow…That happends definetly too often :D/>
BigSHinyToys #7
Posted 03 April 2013 - 08:07 AM
Select works, but still, it creates an unnecessary variable as far as I know, because it should look something like that:

function select(ind, ...)
  local arg = {...}
  return arg[ind]
end

Alternatively, many people use _ as an indikator for an unnecessary variable.
local _, id = rednet.receive()

Edit: Already to slow…That happends definetly too often :D/>
Another you could do this is just use _ or something to replace the variables you don't want:

local function test()
return "one","two","three","four","five","six","seven","eight","nine"
end
local _, _, third,fourth = test()
print(third)
print(fourth)

But I guess select function will work too (first time i've ever seen it, so i've learnt something new today :P/> )
I don't think select is lua side i think it is in the java implementation of the lua environment so some over head's may be saved there i think it is for when you have a lot of returned variables like 15 or 20 and using "_" would be difficult. the table methods JokerRH uses is personally the one i use didn't for fill the specifications of the question so i didn't mention it.
JokerRH #8
Posted 03 April 2013 - 08:10 AM
I don't think select is lua side i think it is in the java implementation of the lua environment so some over head's may be saved there i think it is for when you have a lot of returned variables like 15 or 20 and using "_" would be difficult. the table methods JokerRH uses is personally the one i use didn't for fill the specifications of the question so i didn't mention it.

But still, since the returned values should be put to the stack they'll use memory anyway…
Engineer #9
Posted 03 April 2013 - 11:19 AM
You can also do:

function test
    return 'random', 'heey'
end

local x = {test()}
print(x[2])
PixelToast #10
Posted 03 April 2013 - 03:56 PM
You can also do:

function test
	return 'random', 'heey'
end

local x = {test()}
print(x[2])
you dont need to declare a variable, just wrap the table in perenthesis and index it
it still works but its allways good to save memory ;)/>
Brandhout #11
Posted 04 April 2013 - 01:13 AM
On a distant but related subject. I have also seen people using _variable notation for some variables. Is this a convention for certain variables? I believe i saw them used as variables that were given to a function.

Also does _ throw away the data? Or is it simply stored in the variable _?
JokerRH #12
Posted 04 April 2013 - 02:14 AM
Wow, funny to watch how everything is repeated after a few posts…
But _ is a valid name and lua doesn't care about it.
Brandhout #13
Posted 04 April 2013 - 05:48 AM
Wow, funny to watch how everything is repeated after a few posts…
But _ is a valid name and lua doesn't care about it.

Maybe i wasn't clear, i do not mean the variable _. But a variable name of e.g. _number. This is of course some aesthetic choice, but when and why is it used?
theoriginalbit #14
Posted 04 April 2013 - 05:53 AM
Maybe i wasn't clear, i do not mean the variable _. But a variable name of e.g. _number. This is of course some aesthetic choice, but when and why is it used?
ok so _ is actually a variable that you can reuse later if you wish, i cant speak for everyone on the forums, but personally I use the _ identifier to indicate to myself a variable that I do not care about and/or never use…

as for variable names that begin with an _, these are in programming commonly referred to as properties, and you will see quite common in Object-Oriented programs. These are again just a developers choice and are not required, it just helps us a programmers know and quickly see what are the internals of our objects and/or programs, and what we really shouldn't be messing with, and if we do, could cause some unexpected results.


I don't think select is lua side i think it is in the java implementation of the lua environment so some over head's may be saved there i think it is for when you have a lot of returned variables like 15 or 20 and using "_" would be difficult. the table methods JokerRH uses is personally the one i use didn't for fill the specifications of the question so i didn't mention it.

But still, since the returned values should be put to the stack they'll use memory anyway…
Really when the values are returned they go onto the heap then the way Lua deals with it the variable _ gets the first return, then it gets overridden with the second, then the third, etc, etc, etc… so while the objects are put onto the programs heap, they wouldn't last too long taking up memory, LuaJ would clean them up. Really memory isn't something to worry about in this sense anyways. we have heaps of memory for Lua programs. if this was something like a proper Java program or something for a mobile device, then yes, memory is expensive and we should reduce its usage, but in this case, meh.

EDIT: With the select function it must not be a table. you must use unpack on tables… as shown here
Also just for a bit of diversity, here is another way to get the second or so return value from a function. Not saying its a good way, actually select is better, however, this still works :)/>


local msg = ({rednet.receive()})[2]
this packs the values into a table and then gets the second value from that table…

first time i've ever seen it, so i've learnt something new today :P/>
yeh i didn't know about it until about a month ago when I saw it in one of the CC Devs programs and was like "WHAT IS THAT?!" then I googled and found the above link…
Edited on 04 April 2013 - 04:09 AM
Lyqyd #15
Posted 04 April 2013 - 08:45 AM
It makes absolutely no sense whatsoever to incur the overhead of a function call, grab all of the return values, put them into a table, then return the desired value from it rather that simply accepting and ignoring the (undesired) first return value. This is the opposite of optimization; you're actively seeking to make your program slower and use more memory.
Engineer #16
Posted 04 April 2013 - 08:57 AM
It makes absolutely no sense whatsoever to incur the overhead of a function call, grab all of the return values, put them into a table, then return the desired value from it rather that simply accepting and ignoring the (undesired) first return value. This is the opposite of optimization; you're actively seeking to make your program slower and use more memory.
But how would you do it efficiently then?

I see, and I personally use, everywhere:

local evt = {os.pullEvent()}
--Stuff with that
faubiguy #17
Posted 04 April 2013 - 11:00 AM
Time-wise, using a placeholder variable is best, as shown by this code
SpoilerCode to determine how long it takes to each 1 million times:
local function yield()
  os.queueEvent('.')
  coroutine.yield('.')
end

local func = function() return 1, 2, 3 end
local result;
local _;

local start = os.clock();
for i = 1,1000000 do
  result = select(2,func());
end
print('Select: ', os.clock()-start, ' seconds')
yield()

start = os.clock();
for i = 1,1000000 do
  local tempTable = {func()}
  result = tempTable[2];
end
print('Temporary table: ', os.clock()-start, ' seconds')
yield()

start=os.clock();
for i = 1,1000000 do
  result = ({func()})[2];
end
print('Anonymous table: ',os.clock()-start, ' seconds')
yield()

start=os.clock();
for i = 1,1000000 do
  local _;
  _, result = func();
end
print('Placeholder variable (Declared each time): ',os.clock()-start, ' seconds')
yield()

start=os.clock();
for i = 1,1000000 do
  _, result = func();
end
print('Placeholder variable (Declared once): ',os.clock()-start, ' seconds')
yield()

Output (in CC-Emulator):
Select: 2.0 seconds
Temporary table: 1.1 seconds
Anonymous Table: 1.0 seconds
Placeholder variable (Declared each time): 0.7 seconds
Placeholder variable (Declared once): 0.6 seconds

Of course, if you're not calling it hundreds of thousands times, the difference will be negligible (besides which, rednet.receive yields until it gets a message or timeout, so that will take much longer than getting the second return value) :P/>
Lyqyd #18
Posted 04 April 2013 - 01:18 PM
I use a placeholder throwaway variable when I only want the second or later parameter. For handling events, I'll usually catch the parameters in a table, but that has more to do with there being a variable number of parameters than anything else. It's a lot easier to use the fourth index of the table than it is to have to go back and make sure you added param3 to catch it.