Safely create member functions in Lua

At first there was the simple syntax, and developers could use object.property = "value" to assign or val = object.property to get the value, and with functions there was object.function() to invoke a function that was a member of the object. Pure simple and easy.

Then developers saw, there were some functions that had a : instead of a . and that confused them, what is that, whey are there :'s in some places and .'s in some. This is way too confusing, but nevertheless, the API Documentation suggests that certain functions are to be used with a . and some with a : so they were used without any questions.

As this progressed, developers learned that modules can be used, and with modules came the module(..., package.seeall) after a little while, say about 6 months or so, this was the wrong way to deal with things. So if you make modules you should not use the module(...,package.seeall) declaration.

Anyways, with all of that evolution, one things remained and it never got clarified, where is the . and the : used? Most importantly, how can we ensure that this will work perfectly fine irrespective of the way it is defined or called?

here's an example
 --module.lua
 local module={}
 
 function module.multiply(a,b)
   return a*b
 end

 return module

and in our main.lua file, we can
 local mod = require("module")
 print(mod:multiply(2,4))


this should work, but there are times when a developer might actually have forgotten that the function was defined with a . and is called with a :, so this will not work and cause an error.

First, what's what

What is a . and what is a :

In English, we say "cut the wood with an axe" and if we had a compound sentence, we would say "Take an axe and cut the wood with it" Now most that have studied, known English will know that in the second sentence we imply the Axe as it, even though we are not saying specifically. similarly, in code terms,

 local chop(wood,axe)
  print("Cutting ", wood, " with ", axe)
 end


but we could have the code as

 local axe={}
 
 function axe.chop(wood)
  print("chopping ", wood, " with this axe")
 end


so we have axe as an object that has a member function chop, so we can call it and chop wood (the type we pass to it)

but then some developer comes along and tries axe:chop(wood), what happens now?

The first example, where we called axe.chop is similar to "cut wood with an axe"
and the second example is similar to "take an axe, and cut wood with it"

so when we call the axe:chop, it passes a reference of itself to the function as the first parameter, which is not defined on the function declaration, so what happens is that

axe.chop(wood)

wood becomes the axe when called with axe:chop and there is no wood.

Hopefully, you have gotten this far

Now the point is how to make it safe,

If you or the developers that will use your code be dwindling between using the axe.chop and axe:chop, it is best to define the function (as a general rule for yourself) as

local axe = {}

function axe.chop(self,wood)
end


now what it does is it caters for that extra variable that is implicitly passed, if you were developing with Obj-C, or other languages, you would realise that generally the declaration is defined as

 - (void) chop:(id)sender;

so it is best to keep that and now there is one difference, all calls to axe:chop(wood) will work however you will have to call the axe.chop method as axe.chop(axe,wood) slightly redundant, but worth the effort and you will not face errors due to the . and : again.

Conclusion

If you like this and would like to see more of these, please RT this article and comment. I am also sure that there will be similar articles by some fruity person soon, that is actually flattering just like it is for NimbleBits when Zynga stole their Tiny Towers game, well you cannot change habits can you.




Comments

  1. Woow,believe or not I was thinking about this couple days ago...
    I like it:)

    ReplyDelete

Post a Comment

Popular Posts