Posted on by


Simple function

local function main()
   print("Hello from CoronaSDK")
  end

  main()

This shall work perfectly fine and print Hello from CoronaSDK when we run it.

Forward Declarations

There are cases when we need to pre-declare a function, so here’s how we do it

local main

  local function init()
    main()
  end

  function main()
   print("Hello from CoronaSDK")
  end

  init()

In this example, we call init, which in turn calls main and for forward declaration, we declare that main is a local variable by declaring it then we just define main as a function, note that we did not add the local in front of it, if we did, it would become a new declaration and would not work for us.

Encapsulated Function

What if we wanted to have a function that is only available from within a function?

local function main()
    print ("Hello from CoronaSDK")

    function insideMain()
      print("This is a function inside of main, not available to be called from any other")
    end

   insideMain()
  end

This example is not very illustrative of where this can be used, so let us look at a practical example

local function spawnObject()
   local resultingObject = display.newRect(10,10,100,100)
   
   local function onTouch(event)
     if "ended" == event.phase then
      print("touched rectangle")
     end
   end

   resultingObject:addEventListener("touch",onTouch)

   return resultingObject
  end

  local xTemp = spawnObject()

You can see that the function that handled touch is well within the function spawnObject, this is one cool way of having all related function to the object inside, more like a class without creating a class. These function shall be available to the object to be invoked internally.

Member functions

Member functions are a bit different than normal functions as they become part of the object than being just local to the object. so, in the previous example, let us say we want to change the color of the resultingObject, we do not have a function as yet, let us add a function that will help change the color of the object.

local function spawnObject()
   local resultingObject = display.newRect(10,10,100,100)

   function changeColor(theColor)
     resultingObject:setFillColor(theColor[1],theColor[2],theColor[3])
   end
   
   local function onTouch(event)
     if "ended" == event.phase then
      print("touched rectangle")
     end
   end

   resultingObject:addEventListener("touch",onTouch)

   return resultingObject
  end

  local xTemp = spawnObject()

We cannot access this function from outside of the spawnObject function even though it is not local as there is no way to have a handle to it. So we just make a small modification to the same and we get

local function spawnObject()
   local resultingObject = display.newRect(10,10,100,100)

   function resultingObject.changeColor(theColor)
     resultingObject:setFillColor(theColor[1],theColor[2],theColor[3])
   end
   
   local function onTouch(event)
     if "ended" == event.phase then
      print("touched rectangle")
     end
   end

   resultingObject:addEventListener("touch",onTouch)

   return resultingObject
  end

  local xTemp = spawnObject()
  xTemp.changeColor({255,0,255})

As you can see after running this code, a pink/magenta rectangle is seen on the screen.
If we were to call the changeColor from within the function spawnObject, we would have a bit of a dilemma, how would we access it? we would not have a handle on the function. So, in cases like these, since it is inside of the function and we are referring to another function that is part of the function, we use the keyword self and we call it as

self.changeColor({255,0,255})

Cross calling

This is based off a question on the forum, where the user wanted to know how to call a particular function that was inside of another function. Now by the sound of that sentence it is such a complicated and complex thing to achieve, but in reality, let us see.

We want to be able to call a function that checks for the bounds of the object and make it wrap on the screen like the asteroids game. Now in any thing that we want to do, it is better to actually put what we want to achieve on paper before we attempt to actually achieve that. So, we want that the player object wraps around the screen. We shall call this via a runtime event listener. Since it is not inside of the function, we cannot use the self, though both could be part of the main.lua, self would not work, and the only way is to use the function names. Also since we have determined initially that one function is inside of a function and the other is outside, we need to be able to cross call. We would in the way that we have just seen in the previous example.

local function spawnObject()
   local resultingObject = display.newRect(10,10,100,100)

   function resultingObject.changeColor(theColor)
     resultingObject:setFillColor(theColor[1],theColor[2],theColor[3])
   end
   
   local function onTouch(event)
     if "ended" == event.phase then
      print("touched rectangle")
     end
   end

  function wrap(event)
   if self.x < 25 then self.x = 25 end
   if self.x > 743 then self.x = 743 end
  end

   resultingObject:addEventListener("touch",onTouch)

   return resultingObject
  end

  local xTemp = spawnObject()
  Runtime:addEventListener("enterFrame", xTemp.wrap)

The same code can be made even more structured and cleaner as

local function spawnObject()
   local resultingObject = display.newRect(10,10,100,100)

   function resultingObject.changeColor(theColor)
     resultingObject:setFillColor(theColor[1],theColor[2],theColor[3])
   end
   
   local function onTouch(event)
     if "ended" == event.phase then
      print("touched rectangle")
     end
   end

  local function wrap(event)
   if resultingObject.x < 25 then resultingObject.x = 25 end
   if resultingObject.x > 743 then resultingObject.x = 743 end
  end

   resultingObject:addEventListener("touch",onTouch)
   Runtime:addEventListener("enterFrame", wrap)

   return resultingObject
  end

  local xTemp = spawnObject()

Now every time a new object is spawned, it is fully encapsulated, having its own functions for enterFrame and for touch.

Advanced Function

Functions in Lua are an amazing thing, they are nothing bu pointers to a memory address that holds the code and therefore can be modified on the fly, this is lots of flexibility and also dangerous, useful for obfuscation too.

local hide = print
 local print = math.random
 local function main()
   hide("What do you have to hide?")
   hide( print(5) )
 end

  main()

Now at first glance that is a bit strange looking code, but you know why, coz we have assigned hide to the function print and the local variable print to the function math.random.

More Advanced Function

Functions can also be stored as part of tables, but for this tutorial we shall stop here, the functions as part of tables shall be *perhaps* part #3 of the tables in lua series. So you can read up on those at Part #1 or at Part #2


Posted by . Thanks for reading...

3 Responses to “Tutorial: Scopes for Functions”

  1. Eiswuxe

    Great tutorial, hental! I bet Corona devs will all be LUA pros soon :)

    Just to things to mention:
    In the first code-sample of the “Cross Calling” example is a function called
    “function wrap(event)”.
    This function is then used OUTSIDE of the object (xTemp.wrap). My understanding (and also your info in the turorial) is that the function then must be named “function resultingObject.wrap()”, like with the “changeColor” function. Or am I wrong?

    Second, could you please point out the difference between “function resultingObject.changeColor” and “function resultingObject:changeColor”? So basically “.” vs “:”? I know it makes no difference to the result when you execute the code, but its a difference from a syntax kind of view :)

    Reply
  2. Ingemar

    Regarding ‘:’ vs ‘.’
    The only difference I know of is that the ‘:’ call has an implicit object reference as the first parameter.

    Example 1:
    function resObject:someFunction(value);

    Example 2:
    function resObject.someFunction(self, value);

    Example 3:
    function resObject.someFunction(value);

    Examples 1 and 2 above are the same.
    It’s important to know how a function has been declared (with ‘:’ or ‘.’), otherwise you can get parameter mis-matches if you call a ‘:’-declared function with a ‘.’ or vice versa.
    A ‘:’-declared function will expect the first parameter to be a reference to the calling object.

    The function for Examples 1 and 2 can be called as:
    myObject:someFunction(myValue);
    myObject.someFunction(myObject, myValue);

    However Example 3 can only be called with
    myObject.someFunction(myValue);

    If you try to call Example 3 with
    myObject:someFunction(myValue);

    you’ll get unexpected results as the parameter ‘value’ will get an object reference and not the value of ‘myValue’.

    Reply
  3. OZApps

    @Eiswuxe,
    firstly, that is Hetal, not Hental or Hentai and he is the great guy at Ansca Mobile that is the author of the blog posts on this site, not the Author of the content.

    secondly, you had a valid question and a bit of a misunderstanding, so here’s a follow up article to clarify what you asked here

    cheers,

    ?:)
    The Author of the article

    Reply

Leave a Reply

  • (Will Not Be Published)