generic image
Processing...
  • Games
  • Catalog
  • Develop
  • Robux
  • Search in Players
  • Search in Games
  • Search in Catalog
  • Search in Groups
  • Search in Library
  • Log In
  • Sign Up
  • Games
  • Catalog
  • Develop
  • Robux
   
ROBLOX Forum » Game Creation and Development » Scripters
Home Search
 

Re: Lua 5 Variadic Functions

Previous Thread :: Next Thread 
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 12:34 AM
What is a variadic function?
A variadic function is "a function of indefinite arity, i.e., one which accepts a variable number of arguments." [1] In short, it is a function that can accept virtually any number of arguments. Plenty of examples of these types of functions can be found in the standard Lua library.
For example, the `print` function accepts any number of arguments. Or the `max` and `min` functions of the `math` library.

How can I define a variadic function?
Set the last parameter of the function to `...`

Example 1:
local function Ex1(...) end
Example 2:
local function Ex2(p1, p2, ...) end

In the first example, there are no fixed parameters but any number can be accepted.
In the second example, there are 2 fixed parameters but any number can be accepted.

A fixed parameter is simply a parameter you explicitly associate with an argument, if none is given then Lua decays the values into `nil`. Also, all fixed parameters are stored and treated as local variables.

How can I use a variadic functions?
In Lua 5.0, all variadic functions were given an implicit local called `arg`. All the values in the `arg` table were all the values that were part of the non-fixed parameters.
For example:
local function Ex(a, b, ...)
print(a, b, arg[2], arg[1])
end
Ex(1, 2, 3, 4)
Would print "1 2 4 3"
However, Lua 5.1 changed the way variadic functions worked. The developers of Lua did decide to create backwards compatibility, meaning if allowed, the above code would also be correct in Lua 5.1. However it is bad practice to use deprecated features as it only works in Lua 5.1 purely for backwards compatibility (and you will find that it won't work in Roblox because they removed this feature). If you own Lua 5.1, you can remove the feature by commenting out the `LUA_COMPAT_VARARG` definition in `luaconf.h`.

In Lua 5.1, the `arg` table was deprecated in favor of passing the arguments on the Lua stack, much like how fixed-parameters were. The `select` function is now meant to be used to fetch the particular (or multiple) arguments from the tuple (the arguments associated with non-fixed parameters).
For example:
local function Ex(a, b, ...)
print(a, b, (select(2, ...)), (select(1, ...)))
end
Ex(1, 2, 3, 4)
Would print "1 2 4 3"
Side-note: the reason for parenthesis around the `select` function call is to restrict the call to return a single value, because `select` will actually return the values at the given position and beyond. That is, calling `select(1, ...)` in the above example would return both 3 and 4.
Furthermore, you can create a table and fill it with these arguments:
local function Ex(a, b, ...)
local arg = { ... }
print(a, b, arg[2], arg[1])
end
As another side-note: you can also pass "#" as the first argument to `select` to get how many values there are in the tuple. So: `select("#", 1, 2, 3)` would return 3.

How are variadic functions implemented in Lua?
In Lua 5.0, all arguments associated with non-fixed parameters were simply put into a table, and the function had access to an 'arg' local variable that held all of these arguments.
In Lua 5.1, the implementation differs. These arguments (the ones associated with non-fixed parameters) were simply passed on the Lua stack just like how regular parameters were.


Now, let's look at all of this from a more technical perspective. Say I have this function:
local function Ex(Param1, Param2, ...)
-- does stuff
end

When we call the function with 0, 1, or 2 arguments, the stack would look the same.
At the base of the area we care about, we'll see the reference to the closure. In the following stack indices, we will see our passed arguments. If we do not pass any, or we just pass 1 of the 2, then the remaining parameters will decay into `nil`.
What is done from Lua's standpoint when we do `Ex(3, 4)`:
CLOSURE 0, 0 (Creates a closure for our 'Ex' function and stores into slot 0 of the stack frame (the base))
LOADK 1, 0 (Argument 1: Loads the constant number 3 into slot 1)
LOADK 2, 1 (Argument 2: Loads the constant number 4 into slot 2)
CALL 0, 3, 1 (Calls the closure in slot 0 with 2 arguments and 0 saved return values)

In Lua 5.1 with the 'arg table' backwards compatibility enabled, you can imagine Lua internally creating a table with all extra arguments (in this case we don't have any) and passing that table as an implied third argument. Regardless, the first argument now becomes the base of the stack frame for the 'Ex' function. So at slot 0 of the 'Ex' function, we have our first argument. At slot 1, we'll have our second. For slots beyond this, we'll have our locals and temporaries for that function.

So this is all fine and dandy, but what happens when we pass more arguments? Say, we call `Ex(3, 4, 5, 6, 7)`?
What is done from Lua's standpoint:
CLOSURE 0, 0
LOADK 1, 0 (Argument 1: 3)
LOADK 2, 1 (Argument 2: 4)
LOADK 3, 2 (Argument 3: 5)
LOADK 4, 3 (Argument 4: 6)
LOADK 5, 4 (Argument 5: 7)
CALL 0, 6, 1 (5 arguments, 0 saved return values)

In Lua 5.0, the arguments 3, 4, and 5 are actually stored in the `arg` table. However in Lua 5.1, the arguments are also passed on the stack. But now we have a problem? What should the base of the new stack frame be? If we set it to argument 1 like before, then the locals and temporaries of the function will overwrite these and we will lose the arguments. Well, to solve this, Lua will actually move the arguments associated with fixed-parameters to the top of the stack and set the base to the first one. Then to fetch one of the non-fixed parameters, the VARARG instruction is used which essentially just fetches the non-fixed parameter(s). So the stack would now look like:
- 'Ex' closure
- "first arg" (nil'd by Lua)
- "second arg" (nil'd by Lua)
- third arg (first vararg)
- fourth arg
- fifth arg
- first arg < BASE
- second arg

So the base of the stack frame would actually be past the 5th argument you past, where the arguments associated with fixed-parameters are cloned. To read one of the other arguments, a VARARG instruction is generated. What this instruction will do is get the value at the stack relative to the base (see above).
The algorithm given is simply: `n = (base - func) - numfixedparams - 1`. This will give the number of varargs there are. base-func will give you the number of values between the base and the stack slot used to store the closure, which is essentially the number of arguments you passed plus one. Then subtract it by the number of fixed parameters and then by 1. This gives you the number of varargs there are, as well as the offset from the first vararg to the base. So the argument is then resolved by doing `base - n + idx` where `idx` is the index of the vararg you want to fetch.


And now, some practical information:
There is a limit on the number of 'locals' you can have per function (that limit is 250), what this limit actually is is the limit of stack slots available per function. That means it's not actually a limit on the number of local variables: it's a combined limit on the number of fixed-parameters, locals, and temporaries. That means the more parameters your function takes, the less locals it can have. Now, on to the juicy part: because the base it beyond the varargs in variadic functions, you can use this to your advantage. You can essentially give yourself a much bigger limit. Your new limit now becomes much larger (give or take). Ignoring the fake limit on parameters, you can have a mixture of fixed-parameters and locals for a total of 250 as well as an additional 200 or so for non-fixed parameters.

The best case: you can have 500 parameters, or 250 parameters and 250 locals (if you raise the parameter limit to 250). Of course this high-end limit is impossible to reach, as the varargs are going to be stored in the caller's stackframe, meaning if there is already slots taken then the extra parameter limit decreases.

Essentially:
maxparams = paramlimit + (stacklimit - (temporaries and locals of callers))
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 12:36 AM
Although of course, you can't actually achieve that maxparams limit because of the stack limit on the caller (being 250). It was just a theoretical thing at the end.
Report Abuse
bosswalrus is not online. bosswalrus
Joined: 04 Jan 2013
Total Posts: 5430
11 Aug 2016 12:39 AM
That's wacky!
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 12:40 AM
So realistically, using varargs you can give yourself:
MAXLOCALS locals and MAXPARAMS params
(usually you'll find this to be realistically a bit less than 400)

Instead of mixing btoh locals and params for a total of 250.
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 12:42 AM
LMFAO my English is bad "The developers of Lua did decide to create backwards compatibility"
The developers of Lua decided to make it backwards compatible***
Report Abuse
Kodran is not online. Kodran
Joined: 15 Aug 2013
Total Posts: 5330
11 Aug 2016 12:53 AM
Developers of lua: We've invented backwards compatibility \o/
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 12:58 AM
That's what happens when you write in notepad and don't reread it :(
Report Abuse
Aethex is not online. Aethex
Joined: 16 Oct 2011
Total Posts: 2193
11 Aug 2016 01:00 AM
#BeGoneWithNotepad
#SublimeTextMasterRace
#NewDefaultWindowsTextEditor
#inb4PeopleTellMeAboutAtom
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 01:48 PM
b
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 01:50 PM
>not using vim
I swear to god you people are hopeless
Report Abuse
Xsitsu is not online. Xsitsu
Joined: 28 Jul 2009
Total Posts: 2921
11 Aug 2016 01:53 PM
Emacs is better
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 01:54 PM
I'd rather be hopeless than a dumb arrogant skid
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 01:54 PM
>emacs is better
Totally
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 01:55 PM
@Flux
What do you like to eat
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 01:57 PM
your mom... and sushi
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 01:58 PM
Joke's on you, we're brothers
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 02:00 PM
Oh god you're that moron RemasteredBlox aren't you, kms.
"Joke's"
Report Abuse
TimeTicks is not online. TimeTicks
Joined: 27 Apr 2011
Total Posts: 27115
11 Aug 2016 02:01 PM
MyFunction = function(...)
local tuple = {...}
for i,v in next, tuple do
print(i,v)
end
end

MyFunction2 = function(a,...)
print(a,unpack(...))
end

MyFunction3 = function(table)
for i,v in next, table do
print(i,v)
end
end

MyWeirdFunction4 = function(a,b,c,d,e,f)
local tab = {a,b,c,d,e,f}
for i,v in next, tab do
print(i,v)
end
end


Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 02:02 PM
You say you have bad English yet you joke about mine?
Wew you're on a roll, let me give you a pity clap.
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 02:04 PM
Nah I'm saying the only person I know who makes that mistake is Remastered (and the other 2 morons "secret6timb1" and "LateralLace")
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 02:06 PM
You're so intelligent, I bet you're enrolled into MIT.
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 02:06 PM
You're so edgy, I bet all you do is use Linux and pretend you're a hacker.
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 02:09 PM
Actually yes, I use Gentoo.
You should install it, instead of using that overpriced Apple or Microcuck software.

No really, I'd just love to see you try and install Gentoo.
Report Abuse
Flux_Capacitor is not online. Flux_Capacitor
Joined: 07 Apr 2008
Total Posts: 45720
11 Aug 2016 02:11 PM
If it's not as simple as mounting the image onto a floppy disk or flash drive and booting from it, it's not an OS worth getting. I'd like to spend my time using the OS, not spend my time learning how to use it. Thank you.
Report Abuse
Monadic is not online. Monadic
Joined: 03 Aug 2016
Total Posts: 731
11 Aug 2016 02:12 PM
In other words, you're incapable of following a guide which basically spoonfeeds you on how to install the OS?

Honestly, you're an idiot.
Report Abuse
Previous Thread :: Next Thread 
Page 1 of 1
 
 
ROBLOX Forum » Game Creation and Development » Scripters
   
 
   
  • About Us
  • Jobs
  • Blog
  • Parents
  • Help
  • Terms
  • Privacy

©2017 Roblox Corporation. Roblox, the Roblox logo, Robux, Bloxy, and Powering Imagination are among our registered and unregistered trademarks in the U.S. and other countries.



Progress
Starting Roblox...
Connecting to Players...
R R

Roblox is now loading. Get ready to play!

R R

You're moments away from getting into the game!

Click here for help

Check Remember my choice and click Launch Application in the dialog box above to join games faster in the future!

Gameplay sponsored by:
Loading 0% - Starting game...
Get more with Builders Club! Join Builders Club
Choose Your Avatar
I have an account
generic image