Thread Tools Display Modes
01-23-14, 05:05 PM   #1
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Getting the number of indexes in an array.

Has anyone else noticed that since the most recent update, using the select function with the first arg "#" always results in a return value of 1?

Lua Code:
  1. self.Events = {"PLAYER_ENTERING_WORLD", "PLAYER_REGEN_DISABLED", "PLAYER_REGEN_ENABLED"};
  2.  
  3. for i = 1, select("#", self.Events) do
  4.   self:RegisterEvent(self.Events[i]);
  5. end

I've had to change to this instead.

Lua Code:
  1. #self.Events
__________________
__________________
  Reply With Quote
01-23-14, 05:08 PM   #2
Resike
A Pyroguard Emberseer
AddOn Author - Click to view addons
Join Date: Mar 2010
Posts: 1,290
You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.
  Reply With Quote
01-23-14, 05:14 PM   #3
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Isn't that what you should be doing anyway?

I mean, this is the documentation I found on using "#" with select, anyway" of wowpedia.
Lua Code:
  1. local num = select('#', ...) -- Returns the number of arguments in the ellipsis.

You have a table there instead of a vararg. The number of arguments there in that case would be one.

I always had an aversion to using select() anyway. I would do that this way:
Lua Code:
  1. local events = {
  2.      "EVENT_ONE",
  3.      "EVENT_TWO",
  4.      "EVENT_THREE"
  5. }
  6.  
  7. for k,v in pairs(events) do
  8.      myFrame:RegisterEvent(v)
  9. end
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
01-23-14, 05:27 PM   #4
semlar
A Pyroguard Emberseer
 
semlar's Avatar
AddOn Author - Click to view addons
Join Date: Sep 2007
Posts: 1,060
In this particular case I would just call RegisterEvent 3 times because it's shorter, easier to read, and would use less resources.

Otherwise, pairs or ipairs would be better than getting the length of the table to loop over it.
  Reply With Quote
01-23-14, 05:43 PM   #5
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Using "#" to get the number of indices of an array was not limited to varargs. It could be used for any array. It just so happens that a vararg expression is an array.

In the example provided, the event list will change depending on several factors which means that I'm unable to just register 3 events. I would do just that, if that wasn't the case.

I think it to be good practice to avoid using pairs/ipairs wherever possible. Especially when the function isn't just called once during set-up.

Anyone know the better of these two? getn(self.Events) vs #self.Events? I expect it's probably negligible to the point of being irrelevant.

Thanks for your input.
__________________
__________________
  Reply With Quote
01-23-14, 05:45 PM   #6
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Resike View Post
You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.
?

That's not true.
__________________
__________________
  Reply With Quote
01-23-14, 05:52 PM   #7
Torhal
A Pyroguard Emberseer
 
Torhal's Avatar
AddOn Author - Click to view addons
Join Date: Aug 2008
Posts: 1,196
Originally Posted by Aanson View Post
<snip>

Anyone know the better of these two? getn(self.Events) vs #self.Events? I expect it's probably negligible to the point of being irrelevant.
<snip>
The table.getn method was actually deprecated in Lua 5.1 in favor of the unary length operator (#). You should also be using pairs for dictionary-style tables. For array-style tables, you can use either ipairs or the (slightly faster) incremental loop.
__________________
Whenever someone says "pls" because it's shorter than "please", I say "no" because it's shorter than "yes".

Author of NPCScan and many other AddOns.
  Reply With Quote
01-23-14, 06:05 PM   #8
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Torhal View Post
The table.getn method was actually deprecated in Lua 5.1 in favor of the unary length operator (#). You should also be using pairs for dictionary-style tables. For array-style tables, you can use either ipairs or the (slightly faster) incremental loop.
Yeah, I always prefer incremental loops as opposed to ipairs. Cheers
__________________
__________________
  Reply With Quote
01-23-14, 07:14 PM   #9
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Resike View Post
You need to use select as (select("#", self.Events)) but don't get why would you want to use select in that function.
No. Please, stop posting misinformation. If you are not absolutely sure that what you are posting is valid for Lua programming in the WoW environment, preface it with an "I think" or don't post it at all.

The only thing wrapping a select call in parentheses does is truncate the list of returns to a single value (the first one returned) but when you're only assigning one variable -- eg. local var = select("#", ...) -- there is absolutely no benefit to or effect from doing that. The only reason to do wrap a select call in parentheses would be to something other than the first returned value, without assigning it to a variable, and in a context where the values passed after the one you wanted would cause problems. For example, if you have the following function:

Code:
function GetSomeNumbers()
     return 1, 2, 3, 4, 5
end
... and you wanted to loop from 1 to 3 using the return value from this function, you can do it two ways:

Code:
local _, _, n = GetSomeNumbers()
for i = 1, n do ...
Code:
for i = 1, (select(3, GetSomeNumbers())) do ...
Here in this highly contrived example, if you used the second (far less efficient) method, and did not add the extra parentheses (highlighted above in orange) around the select call, you would effectively be writing:

Code:
for i = 1, 3, 4, 5 do ...
... which would (a) be passing 4 as the increment value for the loop (so i would be 1, then 5, then 9, and so on) and (b) be passing 5 as a 4th value that for doesn't know what to do with and would trigger an error.

Originally Posted by Aanson View Post
Using "#" to get the number of indices of an array was not limited to varargs. It could be used for any array. It just so happens that a vararg expression is an array.
I think you're confused. In your example:

Code:
local events = { "one", "two", "three }
local num = select("#", events)
... num should be 1, since you are passing only one value -- your table. If you want to get the length of the table, you need to use the # operator, not the special string "#" with select:

Code:
local events = { "one", "two", "three }
local num = #events
That's how it's always worked.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
01-23-14, 07:42 PM   #10
Seerah
Fishing Trainer
 
Seerah's Avatar
WoWInterface Super Mod
Featured
Join Date: Oct 2006
Posts: 10,860
Originally Posted by semlar View Post
In this particular case I would just call RegisterEvent 3 times because it's shorter, easier to read, and would use less resources.
Ah, yes. And this. I honestly didn't scroll to see how many events you had in your table.
__________________
"You'd be surprised how many people violate this simple principle every day of their lives and try to fit square pegs into round holes, ignoring the clear reality that Things Are As They Are." -Benjamin Hoff, The Tao of Pooh

  Reply With Quote
01-23-14, 08:04 PM   #11
Aanson
A Flamescale Wyrmkin
Join Date: Aug 2009
Posts: 124
Originally Posted by Seerah View Post
Ah, yes. And this. I honestly didn't scroll to see how many events you had in your table.
See my other post in this thread.
__________________
__________________
  Reply With Quote
01-24-14, 04:14 AM   #12
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
In case it's still unclear:
Code:
for i = 1, select("#", unpack(self.Events)) do
will result in what you seem to have expected from select. Don't do it that way though
  Reply With Quote
01-24-14, 07:14 AM   #13
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
I'm sorry but this makes me cringe.

After I saw 'for i = 1, select("#", unpack(self.Events)) do' I had to write back!

Why not use the standard way of writing a table loop?

Code:
local events = {"A", "B", "C"}
for i = 1, #events do
  self:RegisterEvent(events[i])
end
The select function is great when fetching a specific argument returned from a function that returns a list of arguments, and using "#" returns how many arguments were returned.

Code:
function Events()
  return "A", "B", "C"
end

for k, v in ipairs({Events()}) do
  self:RegisterEvent(v)
end
Also this one works, not ideal but works. You encapsulate the returned arguments in a table and it will return the same table as in the first example. You then iterate it directly using ipairs.

In any case I find this to be a much better approach than unpacking the table to then use select "#" on it to iterate just over the index.
__________________
Profile: Curse | Wowhead
  Reply With Quote
01-24-14, 01:16 PM   #14
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
It seems 3 lines are too much to read, Vlad. What the TE seemed to expect select to return is actually the result of the code snippet I posted. Knowing how unpack works, helps understanding how select works. That was the point of my previous point. Maybe I failed at it, maybe not. I also stated (s)he should not use it like that. So please read before you criticize.
  Reply With Quote
01-24-14, 05:55 PM   #15
Vlad
A Molten Giant
 
Vlad's Avatar
AddOn Author - Click to view addons
Join Date: Dec 2005
Posts: 793
To be honest I couldn't quite tell the purpose at first, so I hastily posted what my first gut feeling told me was the right response - sorry if I made you feel bad in any way!
__________________
Profile: Curse | Wowhead
  Reply With Quote
01-24-14, 06:11 PM   #16
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by Rainrider View Post
It seems 3 lines are too much to read, Vlad. What the TE seemed to expect select to return is actually the result of the code snippet I posted. Knowing how unpack works, helps understanding how select works. That was the point of my previous point. Maybe I failed at it, maybe not. I also stated (s)he should not use it like that. So please read before you criticize.
The problem with posting "bad" examples and saying "don't use this" is that -- as you yourself are complaining -- people don't actually read the "don't use this" part, and end up using your cringe-worthy anti-example as real code in their real addon. I make a habit of never posting functional code that should not actually be used, and I strongly recommend you (and everyone else) adopt this habit, too. If you want to show how something works, make up an example that wouldn't make you want to gouge your eyes out if you saw it in a real addon.
__________________
Retired author of too many addons.
Message me if you're interested in taking over one of my addons.
Don’t message me about addon bugs or programming questions.
  Reply With Quote
01-25-14, 01:44 PM   #17
Rainrider
A Firelord
AddOn Author - Click to view addons
Join Date: Nov 2008
Posts: 454
If a person comes to a medium for written communication to ask questions, I assume they do read. If they don't, it's all their fault.
  Reply With Quote

WoWInterface » Developer Discussions » General Authoring Discussion » Getting the number of indexes in an array.

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off