Tutorial: Extending Libraries Without Native Code

book-feat
Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0

Today’s guest tutorial comes to you courtesy of Matt Webster, an aspiring mobile app developer and veteran of Corona SDK. He’s been involved with .NET-based websites for many years and currently manages mobile app-related web services in London. With a passion for physics, Matt has contributed numerous posts and code samples to the Corona Code Share, listed on his sporadic technical blog. You can follow Matt on Twitter here.


book-featWhile Corona SDK is simple, powerful, and has many useful APIs, sometimes there’s that “one extra little thing” you wish was there. Often, that one thing is apparently simple enough to be incorporated into an existing Lua API, but it may appear “forgotten about.” In this tutorial, we’ll learn how to:

  1. Add new functionality to the existing libraries.
  2. Extend the existing functionality.

Corona API Libraries

The core functionality of Corona SDK is provided by API libraries, the documentation for which is found here:

http://docs.coronalabs.com/api/index.html

If we take a look at the string library, we see a collection of functions:

  • string.byte()
  • string.char()
  • string.find()
  • string.format()
  • etc…

It so happens that these functions are not written in Lua; instead, they are “hooks” into lower-level functionality written in either Objective-C (iOS) or Java (Android). The same is true for the math, graphics , and other libraries.

Some libraries, however, are written completely in Lua, for example Corona’s widget library. Corona Labs has even made the original source code available. Whichever implementation the engineers chose for their code, the fact remains that in the “Lua world” each function is tied to the rules of Lua. In fact, every library — including the string library — is actually a Lua table. That’s right: string is a table and all of its functions are members of that table.

As a result of this, we can do some clever things quite easily!


A Useful Custom Function

The first thing we’ll learn is how to add our own functions to Corona’s own API libraries. Why would we want to do that? Well, let’s say you’ve written a really useful function which removes the leading and trailing spaces from a string. In most languages, this is called trim().

Don’t worry about what’s actually happening inside the function. Just know that you’ve written it, it’s awesome, and it works really well on strings that have annoying and unnecessary spaces at the start and/or end.

A common practice for Corona developers is to put this trim() function into a custom Lua module such as utils.lua. This is fine, but we can easily make it more memorable and categorically accurate — after all, this function is a “string” function, so why not access it like the built-in string functions?


Adding to Corona’s APIs

To be clear, if our custom trim() function is in a file called utils.lua, we want all the work done in that file. To facilitate this, utils.lua must be loaded into memory using a standard require() call:

And the function in the utils.lua may look like this:

Now let’s add this function to the Corona string library. In utils.lua, after we define our function, we follow it with a standard table value assignment (this is the magic bit):

That’s it! You can now call the function from anywhere in your code.


The Beauty of Libraries

Let’s say we have a string defined:

What’s great about having the trim() function in the string library is that we can now call the function as a member of any string variable:

This is because the string library represents string variables in general.


Lua 101 (Sort of)

Note: Skip to the end of this tutorial for links to some more advanced topics in the Lua language.

Section 6 of the Programming in Lua website describes functions as “first-class values with proper lexical scoping.” You may be wondering, “what on earth does that mean?”

Well, in short it means that when you define a function in Lua, you can pass its name around just like any variable. You can even pass it as an argument to a function or store it in a variable to be used later. You may already have done this many times without even thinking about it.

One common instance of passing a function as a value is with the timer.performWithDelay() function:

This code will print “Hello!” once per second for ten seconds. In general terms, what’s happening is this:

  1. The low-level timer function waits for 1000 milliseconds (1 second).
  2. The timer function calls the HelloWorld() function.
  3. The timer function then decrements the counter (started at 10) by 1 and begins again.

Storing Functions in Variables

Just as we can pass a function as a parameter to another function, we can also store the function in a variable. This allows us to treat the variable as that function:

The code above:

  1. Declares a variable called helloFunc.
  2. Assigns the HelloWorld() function to the value of the helloFunc variable.
  3. Calls the variable as a function.

Which will print:


Using Functions as First Class Values

So, now we know that we can:

  • Add functions to Corona’s APIs.
  • Store functions in variables.
  • Pass functions as parameters.

To enhance Corona’s own functionality, we will make use of all three of these Lua features.


Building on What’s There

Now your clever little function is there in the API and working happily along with the others. You’re calling it from your code, content in the knowledge that it’s a fun new feature of the API.

However, now we notice a problem with one of the existing string library functions. The gsub() function lets us do some pretty powerful things. Take a look at the documentation page and you’ll see that it is basically a search-and-replace:

Unfortunately, what it does not do is allow us to specify a list of key/value string pairs to do a bulk search and replace. For example, we cannot provide a table to be used, like this:

To do this, we need a for loop to iterate over the entries in the table and call the gsub() function for each entry:

The pairs() function is a clever little Lua function which identifies each index in the searchreplace table and returns its name and value. This allows Lua tables to be used as dictionaries quite effectively. Don’t worry about the clever bit inside the loop — just know that you’ve written another awesome function which you’ll be using everywhere you’ve got lots of boring string replacement to do.

Now let’s put that loop in a function:

This function lets us reuse the neat little string-replacing loop anywhere we like:

Easy, yes?


Improving What’s There

Let’s put this all together and actually override the gsub() function. First, we need to get the gsub() function into a variable. As we saw earlier, this is possible because, in Lua, functions are first class values:

With this, we can call the gsub() function just by using the gsub variable. Now that we’ve stored the function, we need to overwrite the Lua gsub function by replacing it with our own. We saw this earlier, too. We’ll use the same function parameters which the real gsub() function has:

What we’ve done in just two lines is to take a copy of the gsub() function (to avoid losing it) and replace it with our own function. We can now put any logic in there that we like. In this example we’ll check if the pattern parameter is a string or a table:

If you take a quick look at the string.gsub() documentation, you’ll see that the pattern parameter is always a string. It’s the search pattern used to identify what should be replaced in the s string parameter.

If the pattern parameter is a string, we can just call the original function. How do we do that? Well, remember that we kept a copy of the original gsub() function around, so use that:

If the pattern parameter is not a string, however, we know that it will be a table of key/value pairs to use in our clever little loop. The loop can go in the second half of the if statement:

Note that we’ve modified the loop a little to make use of our new parameter names s and pattern.


Putting it Together

Putting this all together, we can see that the our override and new gsub() function look like this:

The result of all this work is that the string.gsub() function has been replaced with our own logic which will call the original function if the parameters are normal, but do its own work (while reusing the original function) if the parameters have changed. Presto! We’ve just extended the functionality of Corona’s own library:

What’s great about this is that you can do it with any API library provided by Corona.

Warning!

I’m sure you can think of many possibilities using your new-found “god mode,” but you must be careful.

  • Don’t lose your original function by forgetting to store it in a variable.
  • Don’t call your own function from within itself or you’ll end up with an infinite loop.
  • Always make sure that your overriding function calls the original at some point, otherwise you’re not overriding, you’re replacing.

This is an advanced topic so experiment with it and become very familiar with its usage. Do not write production-ready code unless you fully understand what’s happening. There’s a lot of smoke and mirrors here — it’s easy to get lost.


Examples

Here are a few additions to your libraries that you might find interesting and useful:

1. “math” library — adding a function to calculate length:

2. “math” library — adding a function to clamp values:

3. print() function — overriding print() to not print when running on a device:

4. “math” library — adding a function to calculate nearest multiples:


References

Share on Facebook0Share on Google+0Tweet about this on TwitterShare on LinkedIn0
Brent

Brent Sorrentino serves as a full-time Developer Evangelist for Corona Labs, assisting developers in the forums, maintaining documentation/guides, and creating samples which highlight core features of Corona SDK.

This entry has 6 replies

  1. Carlos says:

    Wao!, so much wisdom in just one post.

  2. J. A. Whye says:

    Great tutorial! Easy to understand and really useful stuff!

  3. Matt says:

    Thank you guys 🙂

    Just want to let you know that I’ve started a thread for any questions, advice or requests which anyone may have on this subject:

    http://forums.coronalabs.com/topic/36824-tutorial-extending-libraries-without-native-code/

  4. Nick says:

    Awesome tutorial! This really shows you how powerful Lua and Corona are together!

  5. Marcos Tito says:

    Hi people !

    By the way, could you list the top Lua libraries for Corona SDK ?

    Does anybody suggest a must have “tool set ” of Libraries ?

    How about the best libraries for business Apps ?

    I know there are plenty of libraries, thus I would like to hear from the community the most widely used ones!

    Thank you !

  6. Matt says:

    I use Particle Candy the most, but some popular libraries are Director and Widget Candy. Popular tools would include Texture Packer, Corona Remote and Physics Editor – a personal favourite.

    Take a look on the Corona Resources page for third party tools:

    http://www.coronalabs.com/resources/3rd-party-tools-and-services/

Leave a reply

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">