Thread Tools Display Modes
08-16-14, 07:37 PM   #1
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
Return outside a function?

Looking at the basic example for using LibStub (http://www.wowace.com/addons/libstub/#w_basic-example), I've encountered a return statement that I don't quite understand, as it is outside of any function.

Lua Code:
  1. local lib = LibStub:NewLibrary("MyLibrary-1.0", 1)
  2.  
  3. if not lib then
  4.   return    --HERE, NOTICE ME
  5. end

This leads me to think that addons are run as functions, and this return statement will terminate the addon.
I wrote a little test to confirm this theory:
load order: file1, file2

file1:
Lua Code:
  1. print("zero")
  2.  
  3. --Removing this if statement causes something called a Tail Call (this is new to me as well), which will result in "zero" and "one" getting output, but not file2.
  4. if 1 == 1 then
  5.     return
  6. end
  7.  
  8. print("one")

file2:
Lua Code:
  1. print("two")

After running this code, only "zero" gets output, confirming my suspicion.

However, I'm not sure if my suspicion covers everything here and the addon simply gets terminated, or there are implications for using this that I don't understand. I would appreciate if anyone could elaborate, since my googling haven't been helpful.
  Reply With Quote
08-16-14, 07:54 PM   #2
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
This isn't restricted to just WoW. The entire file, known as the main chunk, is seen by Lua as a function. After compiling into its own binary format, Lua immediately runs the function generated. This is for each addon file, so if you need to stop your addon from loading, you need to put checks like this in all of the .lua files.

There are some restrictions to using return that follow the same rules as if they were in a function. They are required to be at the end of a scope. Note chunks are blocks of code in which locals defined within are isolated. This includes function definitions, conditional blocks, and loops. You may also force a chunk to be defined by using the do ... end block.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)

Last edited by SDPhantom : 08-18-14 at 01:09 PM. Reason: Corrected terminology
  Reply With Quote
08-16-14, 08:01 PM   #3
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
Thanks for the info. =)

Originally Posted by SDPhantom View Post
This is for each addon file, so if you need to stop your addon from loading, you need to put checks like this in all of the .lua files.
This seems to not be the case though, going by the test I made. In the case of LibStub, I guess it's good practice, as always, to check the return values anyway.

EDIT: Ehh... disregard this. Seems I made a typo in the filename in my .toc

Last edited by Malakahh : 08-16-14 at 08:05 PM.
  Reply With Quote
08-16-14, 09:00 PM   #4
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by SDPhantom View Post
This isn't restricted to just WoW. The entire file, known as the main chunk, is seen by Lua as a function. After compiling into its own binary format, Lua immediately runs the function generated.
To add to this, in WoW, the function receives two arguments. The first argument is a string containing the addon's folder/TOC name, and the second argument is a table. The same string and table are passed to each file within the same addon, so you can use the table to share data between your files without putting it in the global namespace. This is what's happening when you see things like this at the top of files:

Code:
local ADDON_NAME, private_table = ...
This line simply captures the variables passed into the file, and assigns them to whatever named variables the author prefers.
__________________
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
08-17-14, 08:49 PM   #5
myrroddin
A Pyroguard Emberseer
 
myrroddin's Avatar
AddOn Author - Click to view addons
Join Date: Oct 2008
Posts: 1,240
Let's break this down, line by line.
Code:
local lib = LibStub:NewLibrary("MyLibrary-1.0", 1)
When creating a new library, it needs to be registered with LibStub. To do so, you need MAJOR, MINOR. The MAJOR is a string value, always the full name of the library you are creating. MINOR is a number, incremented each time a non-breaking, fully backwards compatible, change is implemented.

It is author preference to start the MINOR at 1; I've seen authors start at 90000 + tonumber(repository commit number [ie:// v46]) which would become 90046. Both methods are fine.

As Phanx said, this would be equivalent to
Code:
local ADDON_NAME, private_table = ...
Although LibStub looks for a number value instead of private_table, the MAJOR and MINOR get converted into a table and returned to lib.

If LibStub rejects lib, it is usually because a library with that MAJOR name and MINOR version or higher already exists in LibStub's internal table structure.
Code:
if not lib then
    return    --HERE, NOTICE ME
    -- LibStub has rejected this library with the same MAJOR, MINOR; it exists already
end
You will notice I said "or higher" just above. Let's say MyAddOn and YourAddOn both load SomeLib. During the load process, regardless of which AddOn calls SomeLib in whatever order, LibStub will dump the lower MINOR version if a higher version is found.

Presuming alphabetical load order (not a guarantee, btw), if MyAddOn loads SomeLib (MINOR 1), it will stay in LibStub's structure. Then YourAddOn loads SomeLib (MINOR 2), and SomeLib (MINOR 1) gets unloaded.

If both MINOR versions of SomeLib are the same (1 == 1) then when YourAddOn loads SomeLib, LibStub reports back "already loaded and here it is".

Keep in mind that the only reason to load two version of the same library is because they are not truly the same; there has been breaking changes between versions. In that case, the MAJOR is incremented by the author, and by convention, the MINOR would be reset by the author. The original version of the library could continue wholly on its own, completely independently.

"SomeLib-1.0" =/= "SomeLib-1.1" =/= "SomeLib-2.0". All these MAJORs would be loaded by LibStub concurrently, and each AddOn that needs a particular version would work fine. When such a case exists (LibDataBroker-1.0 and LibDataBroker-1.1 for example) it is highly recommended that the author of MyAddOn update their code to use the newer version.

Hopefully this helps!
  Reply With Quote
08-17-14, 09:56 PM   #6
Malakahh
An Aku'mai Servant
AddOn Author - Click to view addons
Join Date: Jun 2009
Posts: 30
Great to know the conventions, thanks for the help!
  Reply With Quote
08-18-14, 05:15 AM   #7
Phanx
Cat.
 
Phanx's Avatar
AddOn Author - Click to view addons
Join Date: Mar 2006
Posts: 5,617
Originally Posted by myrroddin View Post
Code:
local lib = LibStub:NewLibrary("MyLibrary-1.0", 1)
As Phanx said, this would be equivalent to
Code:
local ADDON_NAME, private_table = ...
What? That's absolutely not what I said, nor is it correct. Other than both assigning values to variables, those two lines of code have nothing at all in common. LibStub does not do anything with the variables passed into files.
__________________
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
08-18-14, 12:47 PM   #8
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
This has gotten derailed a bit. The OP was posting a question about how return could be used to stop execution of a Lua file. Now it's gotten into how LibStub works.
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote
08-18-14, 01:07 PM   #9
SDPhantom
A Pyroguard Emberseer
 
SDPhantom's Avatar
AddOn Author - Click to view addons
Join Date: Jul 2006
Posts: 2,323
Originally Posted by Malakahh View Post
Code:
--Removing this if statement causes something called a Tail Call (this is new to me as well), which will result in "zero" and "one" getting output, but not file2. 
if 1 == 1 then
	return
end
I didn't notice the comment before, but it's incorrect. Following my explanation earlier, removing the conditional surrounding the return statement will cause Lua to throw a syntax error since the return is no longer appearing at the end of a chunk.



Also using a conditional that always evaluates as true can be replaced with the following code for faster execution.
Code:
do
	return
end
Forcing return into a do ... end bypasses the syntax error since it is at the end of the chunk.


Note whitespace is irrelevant to Lua, so the previous code could be written as this to make it better to read.
Code:
do return end
__________________
WoWInterface AddOns
"All I want is a pretty girl, a decent meal, and the right to shoot lightning at fools."
-Anders (Dragon Age: Origins - Awakening)
  Reply With Quote

WoWInterface » Developer Discussions » Lua/XML Help » Return outside a function?

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