What does ":" mean in Lua [duplicate] - lua

This question already has answers here:
Difference between . and : in Lua
(3 answers)
Closed 7 years ago.
I'm new to Lua and I have work on project, I have an issue unterstanding what ":" I didn't found it on the manual for example how should interpret this piece of code :
res:template{
main = 'functionform.html',
functionjs = '_functionform.js',
functionform = '_functionform.html'
}

The colon operatorPIL in Lua is a little syntatic sugar. It's used in object oriented Lua, to make a regular function call look more like a method call. What it does is pass the object as the self parameter when you call a function. Take this example:
a.myFunction(a, 'foo')
It's equivalent to:
a:myFunction('foo')
In your example, the method call is omiting the parentheses because its only argument is a tablePIL, so your function call without the colon operator would be somthing like:
res.template(res, {
main = 'functionform.html',
functionjs = '_functionform.js',
functionform = '_functionform.html'
})
So as you can see, this little syntatic sugar is pretty handy

From the manual in section 2.5.8:
A function call in Lua has the following syntax:
functioncall ::= prefixexp args
In a function call, first prefixexp and args are evaluated. If the
value of prefixexp has type function, then this function is called
with the given arguments. Otherwise, the prefixexp "call" metamethod
is called, having as first parameter the value of prefixexp, followed
by the original call arguments (see §2.8).
The form
functioncall ::= prefixexp `:´ Name args
can be used to call "methods". A call v:name(args) is syntactic sugar
for v.name(v,args), except that v is evaluated only once.
So res:template{} is the same as res.template(res, {}).

The colon operator adds an additional 'hidden' parameter in method definition and argument in method call. (e.g. this / self)
http://www.lua.org/pil/16.html
So a call to your template function provides the hidden argument 'self' through which you can access the object on which the function is defined.

Related

How to store a table method in a different table?

I would like to store methods that are associated with a table, so that I can randomly select one of the function using math.random. Storing functions in a table and calling those functions is straight forward, as shown below:
function funcA()
print("A")
end
functionTable = {funcA}
functionTable[1]()
However, I cannot store a function from a table (a method?) in a new table. The following code will return in an Error (Lua 5.4): function arguments expected near '}'
local functionStore = {}
function functionStore:funcA()
print("A")
end
functionStore:funcA()
functionTable = {functionsStore:funcA}
functionTable[1]()
I think the colon (:) means that I'm already calling the function?, and then the error would make sense, but I would like to store the function in the table.
What Am I doing wrong here?
The problem is that the colon is a special syntactic sugar for function calls to pass the variable / expression preceding it as first argument to the function; it can not be used as an expression. You can however write yourself a function that "curries" the self argument, creating a closure:
local function curry_self(self, methodname)
return function(...) return self[methodname](self, ...) end
end
then you can use this as follows:
functionStore:funcA()
functionTable = {curry_self(functionsStore, "funcA")}
functionTable[1]()
Alternatively, you may pass self as you invoke the function:
functionStore:funcA()
functionTable = {functionStore.funcA}
functionTable[1](functionStore) -- pass functionStore as `self`
In your case, you don't need the colon at all though - you don't even use self in your function! Thus, you may use:
local functionStore = {}
function functionStore.funcA()
print("A")
end
functionStore.funcA()
functionTable = {functionsStore.funcA}
functionTable[1]()
you can put functions in a table without using the colon, using just the dot to assign them to table fields.

Are instance methods closures?

In the book, "Swift Programming Language 3.0", it mentioned that types of closure include:
Global functions are closures that have a name and do not capture
any values
Nested function are closures that have a name and can
capture values from their enclosing function
Closure expression are
unnamed closure written in a lightweight syntax that can capture
values from their surrounding context
I was just wondering does a function that exist in class scope count as a closure? One can certainly pass around such function as an argument to other function, but is it a closure?
Yes! Absolutely! Here's an example that uses the lowercased() method of String.
let aClosure: (String) -> () -> String = String.lowercased
let anUpperCasedString = "A B C"
print(anUpperCasedString)
let aLowerCaseString = aClosure(anUpperCasedString)()
print(aLowerCaseString)
You can see that the type of this closure is (String) -> () -> String. This is because String.lowercased is completely unapplied, it has no clue what instance it's operating on.
Calling aClosure(anUpperCasedString) will return a closure that's now () -> String. Baked into it is the instance it'll operate on. Only when you call this new closure with no params (()), will it actually execute the body of lowercased(), operating on the instance you gave it in the previous step, and return you the String result.
As a consequence, this is also valid:
let aLowerCaseString = String.lowercased("QWERTY")()
It just does all the steps above in one inlined step.
This technique is called function currying. This post talks more about this technique (called function currying) as it applies to instance methods in Swift.

Lua attempt to index global 'self' error (GMod Lua script)

I have been getting the following error with this section of code:
[ERROR] lua/entities/cook/init.lua:58: attempt to index global 'self' (a nil value)1. cooked - lua/entities/cook/init.lua:58
The function starts at line 57, and when I remove line 58 (local Pos = self.Entity:GetPos() , it just gives the same error message for line 61.
function cooked()
local Pos = self.Entity:GetPos()
local roll = math.random(1, 5);
if roll == 5 then
self.Entity:EmitSound("phx/explode06.wav")
self.Entity:Remove()
else
local createfood = ents.Create("food")
createfood:SetPos(Pos + Vector(0,10,100))
createfood:Spawn()
self:SendLua("GAMEMODE:AddNotify(\"You finish cooking the food and package the product!\", NOTIFY_GENERIC, 4)")
end
end
It's unclear what self should be. The error says it's a global, which is consistent with the code you have shown.
But, self is almost exclusively used as a formal parameter to a function and an implicit one at that.
When self is implicit, the function is called a method because the intent is for it to access fields in a table passed into self. The method value is almost always held by a field in the same table (or at least, available as such via metamethods).
The colon syntax in a function definition creates a method.
If cooked was a method then it would make sense for it to access self. But cooked is a global.
You might have meant:
function sometable:cooked()
-- ...
-- self is an implicit formal parameter
-- ...
end
How to read the Lua statement above:
access sometable as a table
assign its "cooked" field the function value created by the function definition.
(The function definition is compiled from the method syntax, so in the body, self is the first formal parameter, which is implicit.)
The method could be called like:
sometable:cooked() -- passes sometable as self
The colon syntax in a field function call is a method call.
How to read the Lua statement above:
access sometable as a table,
index its "cooked" field,
call its value as a function, passing sometable as the first parameter,
discard the result list.
Oddities:
The syntax for methods is just "syntactic sugar." Methods values are no different than other function values:
A function created from a function definition using the any syntax can be called using any function call syntax.
A method need not be called using the method call syntax.
A non-method can be called using the method call syntax.
self is not reserved so it can be used as any identifier is.
Self is nil, so how do you call cooked()?
It has to be self.cooked(self) or self:cooked(), where self is the table you want to use as self in your function.

Lua: call metatable function from string

I have this function:
function Bootstrap: test()
-- CODE HERE
end
I would call this function from it name.
This example works:
function callFunc()
c = "Bootstrap"
_G[c].test()
end
I need to do something like this:
function callFunc()
c = "Bootstrap"
f = "test"
_G[name].[f]() -- Bootstrap.test()
end
But there is an error:
'<name>' expected near '['
What I should to do? Thank you.
. is unnecessary here. Write _G[name][f]().
.name is just a syntactic sugar and is exactly equivalent to ["name"], and this place is obviously not where you should use it.
BTW, this has nothing do to with metatables or calling from string. You just access element of one table, than happens to be another table, access element inside that second one, that happens to be function and call it.

F# how to AddHandler alike VB.NET

VB.NET code is :
AddHandler TheGrp.DataChanged, AddressOf theGrp_DataChange
So how can I do same with F# ?
theGrp.DataChanged.AddHandler(X.theGrp_DataChange)
Error 1 This function takes too many arguments, or is used in a context where a function is not expected
Try theGrp.DataChanged.AddHandler(fun o e -> X.theGrp_DataChange(o, e)). The signature for AddHandler indicates that it takes a delegate, so you can either explicitly create one (via something like DataChangedEventHandler(fun o e -> X.theGrp_DataChange(o, e))) or you can let the compiler implicitly add the delegate constructor when given a function definition, but you can't just use the method itself.
Alternatively, if you don't want to create a lambda expression explicitly, you can also write (In this case, the function signature matches the signature required by the delegate, so it should work):
theGrp.DataChanged.AddHandler(DataChangedEventHandler(x.theGrp_DataChanged))
Also, if you don't need the sender argument, you can declare the theGrp_DataChanged method to take only the event args argument and then write just:
theGrp.DataChanged.Add(x.theGrp_DataChanged)

Resources