What is the convention to document types used in Lua? - lua

I come from the strongly typed world and I want to write some Lua code. How should I document what type things are? What do Lua natives do? Hungarian notation? Something else?
For example:
local insert = function(what, where, offset)
It's impossible to tell at a glance whether we're talking about strings or tables here.
Should I do
local sInsert = function(sWhat, sWhere, nOffset)
or
-- string what, string where, number offset, return string
local insert = function(what, where, offset)
or something else?
What about local variables? What about table entries (e.g. someThing.someProperty)?

For a reference on thoughts and opinions on Lua style in the community (or a particular community?), read this: LuaStyleGuide.
The closest one could get to an enforced style would be the format used by LuaDoc, as it's a fairly popular documentation generator used by high profile projects such as LuaFileSystem.

There are only seven types in Lua.
Here are some conventions (some of them might sound a bit obvious; sorry):
Anything that sounds like a string, should be a string: street_address, request_method. If you are not sure you can add _name (or any other suffix that makes clear it's a substantive) to it: method_name
Anything that sounds like a number, should be a number: mass, temperature, percentage. When in doubt, add number, amount, coefficient, or whatever fits : number_of_children, user_id. The names n and i are usually given to numbers. If a number must be positive or natural, make assertions at the top of the function.
Boolean parameters are either an adjective (cold, dirty) or is_<adjective> (is_wet, is_ready).
Anything that sounds like a verb should be a function: consume, check. You can add _function, _callback or _f if you need to clarify it further: update_function, post_callback. The single letter f represents a function quite often. And usually you should only have one parameter of type function (recommended to put it at the end)
Anything that sounds like a collection should be a table: children, words, dictionary. People typically don't differentiate between array-like tables and dictionary-like tables, since both can be parsed with pairs. If you need to specify that a table is an array, you could add _array or _sequence at the end of the name. The letter t typically means table.
Coroutines are not used quite often; you can follow the same rules as with functions, and you can also add _cor to their names.
Any value can be nil.
If it's an optional value, initialize it at the top of the function: options = options or {}
If it's a mandatory value, make an assertion (or return error): assert(name, "The name is mandatory")

Related

How can I indicate an error during a parse operation?

Within the scripting language I am implementing, valid IDs can consist of a sequence of numbers, which means I have an ambiguous situation where "345" could be an integer, or could be an ID, and that's not known until runtime. Up until now, I've been handling every case as an ID and planning to handle the check for whether a variable has been declared under that name at runtime, but when I was improving my implementation of a particular bit of code, I found that there was a situation where an integer is valid, but any other sort of ID would not be. It seems like it would make sense to handle this particular case as a parsing error so that, e.g., the following bit of code that activates all picks with a spell level tag greater than 5 would be considered valid:
foreach pick in hero where spell.level? > 5
pick.activate[]
nexteach
but the following which instead compares against an ID that can't be mistaken for an integer constant would be flagged as an error during parsing:
foreach pick in hero where spell.level? > threshold
pick.activate[]
nexteach
I've considered separate tokens, ID and ID_OR_INTEGER, but that means having to handle that ambiguity everywhere I'm currently using an ID, which is a lot of places, including variable declarations, expressions, looping structures, and procedure calls.
Is there a better way to indicate a parsing error than to just print to the error log, and maybe set a flag?
I would think about it differently. If an ID is "just a number" and plain numbers are also needed, I would say any string of digits is a number, and a number might designate an ID in some circumstances.
For bare integer literals (like 345), I would have the tokenizer return maybe a NUMBER token, indicating it found an integer. In the parser, wherever you currently accept ID, change it to NUMBER, and call a lookup function to verify the "NUMBER" is a valid ID.
I might have misunderstood your question. You start by talking about "345", but your second example has no integer strings.

How can I Read the file with Lua doing search filter and store the entries as a variable

So I want to read a text file with the following format:
Bob, G92f22f, Fggggfdff32
Rob, f3h9123, fdsgfdsg3
Sally, f2g4g, g3g3hgdsd
I want a simple Lua program that can filter out say "bob" and then say throw the data into a variable to use in a program.
a = Bob
b = G92f22f
c = Fggggfdff32
I assume then I could do
print(a,b,c)
Still quite new to Lua having a heck of a time with anything read / variable though.
You'll want to look at the io and string modules; they handle things like reading from / writing to files and doing pattern matching on strings.
Luas pattern matching is a bit simple compared to the regular expressions most modern languages use, but from what I see in your example, you could probably match a "word" as [^, ]+, that is, one or more characters that aren't a comma or a space

Lua Terminology related to OOP

To be to the point; I've done Lua for awhile, but never quite got the terminology down to specifics, so I've been Googling for hours and haven't come up with a definitive answer.
Related to OOP in Lua, the terminology used include:
Object
Class
Function
Method
Table
The question is, when are these properly used? Such as in the example below:
addon = { }
function addon:test_func( )
return 'hi'
end
Q: From my understanding with Lua and OOP, addon is a table, however, I've read that it can be an object as well -- but when it is technically an object? After a function is created within that table?
Q: test_func is a function, however, I've read that it becomes a "Method" when it's placed within a table (class).
Q: The entire line addon:test_func( ), I know the colon is an operator, but what is the term for the entire line set of text? A class itself?
Finally, for this example code:
function addon:test_func( id, name )
end
Q: What is id and name, because I've seen some people identify them as arguments, but then other areas classify them as parameters, so I've stuck with parameters.
So in short, what is the proper terminology for each of these, and when do they become what they are?
Thanks
From my understanding with Lua and OOP, addon is a table, however, I've read that it can be an object as well -- but when it is technically an object? After a function is created within that table?
Object is not a well-defined term. I've seen it defined (in C) as any value whatsoever. In Lua, I would consider it synonymous with a table. You could also define it as an instance of a class.
test_func is a function, however, I've read that it becomes a "Method" when it's placed within a table (class).
You're basically right. A method is any function that is intended to be called with the colon notation. Metamethods are also methods, because, like regular methods, they define the behavior of tables.
The entire line addon:test_func( ), I know the colon is an operator, but what is the term for the entire line set of text? A class itself?
There's no name for that particular piece of code. It's just part of a method definition.
Also, I wouldn't call the colon an operator. An operator would be the plus in x + y where x and y both mean something by themselves. In addon:test_func(), test_func only has meaning inside the table addon, and it's only valid to use the colon when calling or defining methods. The colon is actually a form of syntactic sugar where the real operator is the indexing operator: []. Assuming that you're calling the method, the expansion would be: addon['test_func'](addon).
What is id and name, because I've seen some people identify them as arguments, but then other areas classify them as parameters, so I've stuck with parameters.
They're parameters. Parameters are the names that you declare in the function signature. Arguments are the values that you pass to a function.

Lua if A==1 or 2 or 3 then

I have a lot of music chords that can have alternate names, rather than having to create longer lines with a lot of == and or's for each alternate name, and if chord=="Maj" or "maj" or.. don't work with Lua:
if chord=="Maj9" or chord="maj9" or chord=="M9" or chord=="Maj7(add9)" or chord=="M7(add9)" then notes="0,4,7,11,14" end
I need a simpler way to do it, maybe just reformat the lines in Notepad++ to use an array,
at the moment each of the 200+ chords on one line each:
if chord=="Maj9,maj9,M9,Maj7(add9),M7(add9)" then notes="0,4,7,11,14" end
if chord=="mMaj7,minmaj7,mmaj7,min/maj7,mM7,m(addM7),m(+7),-(M7)" then notes="0,3,7,11" end
The correct way is to normalize your input. For example, take whatever chord value comes in and use Lua’s string.lower() function to make the string all lowercase. By normalizing your input, you simplify the logic you need to write to work with that data. Consider other ways as well to normalize the data. You might, for example, write a method that converts all notes into an enumerated list (C = 1, C# = 2, etc.). That way equivalent notes get the same in-memory values.
Those are just a few ideas to get you on track. You should not try to think up and then hard-code every possible way a user may input a chord name.

Duh? help with f# option types

I am having a brain freeze on f#'s option types. I have 3 books and read all I can but I am not getting them.
Does someone have a clear and concise explanation and maybe a real world example?
TIA
Gary
Brian's answer has been rated as the best explanation of option types, so you should probably read it :-). I'll try to write a more concise explanation using a simple F# example...
Let's say you have a database of products and you want a function that searches the database and returns product with a specified name. What should the function do when there is no such product? When using null, the code could look like this:
Product p = GetProduct(name);
if (p != null)
Console.WriteLine(p.Description);
A problem with this approach is that you are not forced to perform the check, so you can easily write code that will throw an unexpected exception when product is not found:
Product p = GetProduct(name);
Console.WriteLine(p.Description);
When using option type, you're making the possibility of missing value explicit. Types defined in F# cannot have a null value and when you want to write a function that may or may not return value, you cannot return Product - instead you need to return option<Product>, so the above code would look like this (I added type annotations, so that you can see types):
let (p:option<Product>) = GetProduct(name)
match p with
| Some prod -> Console.WriteLine(prod.Description)
| None -> () // No product found
You cannot directly access the Description property, because the reuslt of the search is not Product. To get the actual Product value, you need to use pattern matching, which forces you to handle the case when a value is missing.
Summary. To summarize, the purpose of option type is to make the aspect of "missing value" explicit in the type and to force you to check whether a value is available each time you work with values that may possibly be missing.
See,
http://msdn.microsoft.com/en-us/library/dd233245.aspx
The intuition behind the option type is that it "implements" a null-value. But in contrast to null, you have to explicitly require that a value can be null, whereas in most other languages, references can be null by default. There is a similarity to SQLs NULL/NOT NULL if you are familiar with those.
Why is this clever? It is clever because the language can assume that no output of any expression can ever be null. Hence, it can eliminate all null-pointer checks from the code, yielding a lot of extra speed. Furthermore, it unties the programmer from having to check for the null-case all the same, should he or she want to produce safe code.
For the few cases where a program does require a null value, the option type exist. As an example, consider a function which asks for a key inside an .ini file. The key returned is an integer, but the .ini file might not contain the key. In this case, it does make sense to return 'null' if the key is not to be found. None of the integer values are useful - the user might have entered exactly this integer value in the file. Hence, we need to 'lift' the domain of integers and give it a new value representing "no information", i.e., the null. So we wrap the 'int' to an 'int option'. Now, if there is no integer value we will get 'None' and if there is an integer value, we will get 'Some(N)' where N is the integer value in question.
There are two beautiful consequences of the choice. One, we can use the general pattern match features of F# to discriminate the values in e.g., a case expression. Two, the framework of algebraic datatypes used to define the option type is exposed to the programmer. That is, if there were no option type in F# we could have created it ourselves!

Resources