tags:

views:

1553

answers:

7

I'm currently embedding Lua and using it as a glorified intelligent config file. However, I think I'm missing something since people rave about the uses of Lua.

For example, I can easily explain why you might use shell scripting instead of C by showing this example (admittedly , boost regexp is overkill):

#include <dirent.h> 
#include <stdio.h> 
#include <boost/regex.hpp>

int main(int argc, char * argv[]) {
    DIR           *d;
    struct dirent *dir;
    boost::regex re(".*\\.cpp$");
    if (argc==2) d = opendir(argv[1]); else d = opendir(".");
if (d) {
    while ((dir = readdir(d)) != NULL) {
            if (boost::regex_match(dir->d_name, re)) printf("%s\n", dir->d_name);
    }

    closedir(d);
}

return(0);

and compare it to:

for foo in *.cpp; do echo $foo; done;

Are there any examples that you can give in Lua which can make it 'click' for me?

EDIT: Maybe my problem is that I don't know Lua well enough yet to use it fluently as I'm finding it easier to write C code.

EDIT2:

One example is a toy factorization program in C++ and Lua:

#include <iostream>

int fact (int n){
    if (n==0) return 1; else
    return (n*fact(n-1));
}

int main (){
    int input;
    using namespace std;
    cout << "Enter a number: " ;
    cin >> input;
    cout << "factorial: " << fact(input) << endl;
    return 0;
}

Lua:

function fact (n)
    if n==0 then
     return 1
    else 
     return n * (fact(n-1))
    end
end

print ("enter a number")
a = io.read("*number")
print ("Factorial: ",fact(a))

Here, the programs look alike, but there's clearly some cruft in the include, namespace and main() declarations you can get rid of. Also remove variable declarations and strong typing.

Now are people saying this is the advantage which adds up over a larger program, or is there more to it? This doesn't stand out in the same way as the bash example.

+3  A: 

Using a scripting language such as Lua has many other benefits.

A couple of advantages to Lua vs. C++:

  • It's often shorter in terms of development time due to the high-level nature, as in your example.
  • It doesn't require recompilation to change behavior.
  • Behavior can be changed on non-development machines.
  • Prototyping is very fast and easy, since you can just tweak logic at runtime.
Reed Copsey
... functionality can be modified and augmented/improved by non-developers
none
@none: Good point, but I still consider Lua a programming language in its own right, so IMO, you still need a "developer" (although perhaps a less experienced one).
Reed Copsey
+2  A: 

Try to implement a Lua table in C/C++, you'll see the strength of Lua right there.

In Lua:

a["index"] = "value"

In C, start by reading about linked list...

C++ STL may help, but it is going to be a lot more verbose than Lua.

Also, Lua makes great glue. It is so easy (IMHO) to interface to C.

0x6adb015
Thanks. Have you used Qt's QList? Just wondering if that offers something comparable.
bugmenot77
No. I'm sure there is some lib that offers similar stuff, but as simple as Lua?
0x6adb015
What about std::map<std::string, valuetype> in C++?
bdonlan
A std::map will be orders of magnitude slower for large maps - you'd need a hash map. Google offers several (http://code.google.com/p/google-sparsehash/), or you can use tr1::unordered_map. Or @bugmenot77, with Qt you'd use QHash.
gnud
However, most Lua maps I've seen are small (less than 100 entries). Then again, Lua is dynamically-typed so you'd need something like a std::map<std::string, boost:variant>.
Max Lybbert
Its not only dynamically typed, but values of any type (except nil) can be used to index the table. There are times when its handy to be able to use a function as a key, for instance.
RBerteig
+2  A: 

I don't know if I make it 'click' for you but I'll try.

One of the advantages of embedding Lua is, that you can not only use it as a configfile but actually offer your C/C++-interfaces to lua and 'script' their usage via the Lua-scripting language.

If you want to change the behaviour/logic of your application, you just have to change the code in the Lua-script without the need to recompile the whole application.

Prominent uses are game logics like AI oder state machines, where a fast roundtrip-time from change to play is essential for developing the game.

Of course, the main logic has then to be present within the Lua-script, not within the C/C++-code, to be effectively used.

Kosi2801
Thanks. I probably exaggerated a bit and do use Lua to implemnet AI in game logic. Doing this, I did come across issues as to whether stuff should be implemented in C, Lua or some mix.
bugmenot77
+1  A: 

For an example of where Lua fits better then c++ look at distributing scripts. Mush Client offers Lua as a scripting language. As shown by the link above you can do a lot with Lua to extend the program. Unlike C++ though Lua doesn't have to be compiled and can be restricted. For example you can sandbox Lua so it can't access the file system. This means that if you get a script from someone else it is incapable of destroying your data since it can't write to the disk.

Jared
Thanks. I can totally see the case where Lua is embedded or used to extend, plugin, script etc. But I also hear of people switching from C to Lua and only writing C 'modules' when speed is a factor. I suspect maybe I'm not fluent enough in Lua and if I was I could write faster/easier in Lua than C.
bugmenot77
+1  A: 

Programming just in C can be a very tedious and redundant task, this certainly applies when compared to more abstract, high level languages.

In this sense, you can get started and finish things much more quickly than doing everything directly in C, this is because many things that need to be set up, done and cleaned up explicitly and manually in C, are often implicitly and automatically handled by a scripting language such as Lua (e.g. imagine memory management).

Similarly, many more abstract data structures and algorithms are often directly provided by such high level languages, so you don't have to re-invent the wheel and re-implement it, if all you need is a standard container (think linked list, tree, map etc).

So, you can get a fairly good ROI when using a fairly abstract scripting language such as Lua or even Python, especially if the corresponding language comes with a good library of core functionality.

So, scripting is actually ideal in order to prototype ideas and projects, because that's when you need to be able to concentrate on your effort, rather than all the mechanical redundancies that are likely to be identical for most projects.

Once you got a basic prototype done, you can always see how to improve and optimize it further, possibly be re-implementing essential key functionality in C space, in order to improve runtime performance.

none
Thanks. Do you mean the things as shown in my second edit?
bugmenot77
A: 

The main advantages of Lua as a programming language (apart from the embeddability) are

  • Powerful, efficient hash table as the main data structure
  • String-processing library with an excellent balance of complexity and expressive power
  • First-class functions and generic for loop
  • Automatic memory management!!

It's hard to find a short example that illustrates all these. I have 191 Lua scripts in my ~/bin directory; here's one that takes the output of pstotext and joins up lines that end in a hyphen:

local function  printf(...) return io.stdout:write(string.format(...)) end
local function eprintf(...) return io.stderr:write(string.format(...)) end

local strfind, strlen = string.find, string.len

function joined_lines(f)
  return coroutine.wrap(function()
                          local s = ''
                          for l in f:lines() do
                            s = s .. l
                            local n = strlen(s)
                            if strfind(s, '[%-\173]$', n-1) then
                              s = string.sub(s, 1, n-1)
                            else
                              coroutine.yield(s)
                              s = ''
                            end
                          end
                        end)
end

-- printf('hyphen is %q; index is %d\n', '­', string.byte('­'))

for _, f in ipairs(arg) do
  for l in joined_lines(io.popen('pstotext ' .. f, 'r')) do
    printf('%s\n', l)
  end
end

This example shows several features to advantage but does nothing interesting with tables.

Here's a short snippet from a Key Word In Context indexing program, which fetches context from a table and formats the key word in context. This example makes more extensive use of nested functions and shows some more table and string stuff:

local function showpos(word, pos, lw, start)
  -- word is the key word in which the search string occurs
  -- pos is its position in the document
  -- lw is the width of the context around the word
  -- start is the position of the search string within the word
  local shift = (start or 1) - 1  -- number of cols to shift word to align keys
  lw = lw - shift -- 'left width'
  local rw = cols - 20 - 3 - lw - string.len(words[pos])  -- right width
  local data = assert(map:lookup(pos)[1], "no map info for position")
     -- data == source of this word
  local function range(lo, hi)
    -- return words in the range lo..hi, but only in the current section
    if lo < data.lo then lo = data.lo end
    if hi > data.hi then hi = data.hi end
    local t = { }
    for i = lo, hi-1 do table.insert(t, words[i]) end
    return table.concat(t, ' ')
  end
  -- grab words on left and right, 
  -- then format and print as many as we have room for
  local left  = range(pos-width, pos)
  local right = range(pos+1, pos+1+width)
  local fmt = string.format('[%%-18.18s] %%%d.%ds %%s %%-%d.%ds\n', 
                            lw, lw, rw, rw)
  printf(fmt, data.title, string.sub(left, -lw), word, right)
end
Norman Ramsey
+1  A: 

Scripting languages reduce the effort required to build complex GUIs that otherwise require a lot of framework glue and repetition of code. Several GUI toolkits are available with Lua bindings, including wxWidgets and the IUP toolkit.

In both of those bindings, first class function values and full closures make event callbacks easy to code and easy to use.

A large application using Lua at its core (such as Adobe Photoshop Lightroom) has an outer C/C++ program that hosts the Lua interpreter and provides access to its core features by registering C functions with that interpreter. It typically implements compute-intensive core functions in C functions, but leaves the overall flow, operation, and even the GUI layout to Lua scripts.

I have found in my own projects that it is often the case that the stock standalone Lua interpreter (lua.exe or wlua.exe) is sufficient for the outer application when combined with IUP loaded at run time along with one or two custom DLL-based Lua modules coded in C that implement features that require that level of performance, or features that are implemented via other C-callable libraries.

The important points for my projects have included:

  • True tail calls allow for a easy expression of finite state machines.
  • Garbage collected memory management.
  • Anonymous functions, closures, first class function values.
  • Hash tables.
  • Rich enough string library.
  • Userdata extends the garbage collector to C side allocations.
  • Metatables allow a rich variety of object oriented and functional techniques.
  • Small but sufficiently powerful C API.
  • Good documentation, with open source as a backup.
  • Good user to user support through the mailing list and wiki.
  • Powerful modules such as a PEG parser available from the authors and from the community.

One of my favorite examples to cite is a test jig I built for an embedded system that required about 1000 lines of Lua and 1000 lines of C, ran under lua.exe, and used IUP to present a full Windows GUI. The first version was running in about a day. In C++ with MFC, it would have been at least a week's work, and many thousands of lines of code.

RBerteig