Converting Python Code to LUA ... ?

Sounds like a language I could spit something out in real fast like javascript. It also sounds like something that would be insane to try to maintain a large application in. I know mods can get pretty big sometimes, what kind of features does it have for code reuse (since it doesn't have classes and inheritance) and things such as importing/namespaces/object scope

With any dynamically typed language, large systems get difficult to manage. You really have to make sure that your comments are thorough and up to date. Statically typed languages have an aspect of "self-documentation" that you just don't have in a language like Python or Lua. Not to mention the fact that there tend to be more run time errors and fewer compile time errors, which may cause debugging to get difficult.

The thing you get from dynamic typing is that there's no "metaprogramming," or, rather, it's ALL "metaprogramming." And that's nice. :D

Anyway, when it comes to data-hiding:

Someone already mentioned metatables, but I want to put in my 2c on functional programming techniques.

I would argue that Lua does have a class mechanism. It's just called "function."

A simple examle is a counter "class":

Code:
function counter()
  local c = 0
  return function()
    c = c + 1
    return c
  end
end

c1 = counter()
print(c1()) --> prints 1
print(c1()) --> prints 2
c2 = counter()
print(c2()) --> prints 1
print(c1()) --> prints 3

What happening here is that functions in Lua are merely prototypes for "closures." Essentially, every function carries around its scope, and functions that are defined in other functions have access to the local variables of the enclosing function (or functions.)

This is a an incredibly powerful tool. In fact, it pretty much implements all of OOP and more with just this simple rule about "scope carrying" mixed with the idea of a first-class function.

The following Lua code is logically very similar to the following C++ code.

C++:
Code:
//assume some kind of String class

struct Base
{
  virtual String foo()
  {
    return "base foo";
  }

  virtual String bar() = 0;
};

struct Derived : public Base
{
  Derived(String data = "derived bar") : m_data(data) {};

  String m_data;

  virtual String bar()
  {
    return m_data;
  }
};


Lua:
Code:
function Base(virtuals)

  virtuals.foo = virtuals.foo or 
  function()
    return "base foo"
  end

  return virtuals
end

function Derived(data)

  data = data or "derived bar"

  return Base
  {
    bar = function() return data end
  }
end

To translate back and forth, you can think of it like this: You define a constructor function. The private members are locals and the public members are returned (in a table or not, as with the counter example.) Static members exist in the enclosing scope of the constructor itself. So in the simple case, that scope is the file (files are functions in Lua,) but in the more complex case, you can have as many layers of "staticness" as you want!

As seen above, the equivalent of inheritance is really just passing functions to functions.

On top of everything, hiding your data in this way is more efficient because you aren't indexing into a "self" variable all the time. (Although it's still a good idea to make sure that any tables you return can still use the : syntax, just to be consistent and because you might change the implementation later.)

One of the main reasons Lua is able to do this and do it so efficiently is that it's register-based rather than stack-based. Local variables exist in registers, so no special code had to be written to move variables around the stack when you reference one that has "left scope." The problem is that for those of us who learned to code in languages like C, this "stackless" way of looking at variables is incredibly foreign! It takes a bit of un-learning.

Of course in other situations, metatables are more appropriate, but I really think that this functional style of programming is more, I don't know, intuitive is an overused word. It seems "closer to the metal." It does more with less, and that's what Lua is all about.
 
I'm assuming a "table" can only have one meta-table? That would mean multiple inheritance is out. But you could put a meta-table as an element of the original meta-table no? You could have a suedo interface that way.
Multiple inheritance is probably out ... unless you cheat.

See, when you look up things in your meta-table, that meta-table can have a meta-table.

A multiple inheritance meta-table is a different kind of meta-table, and you implement kinds of tables via meta-tables.

So you simply (simply, heh) create a multiple-inheritance meta-meta-table, build a meta-table that uses the multiple-inheritance meta-meta-table as its meta-table, add in the data listing the multiple different kinds of parent meta-tables, then have the meta-meta-table replace the "lookup operation" operations on the meta-table with one that checks the multiple parent meta-tables in whatever order or means you prescribe.

I have no idea if that is practical in Lua (it requires some technical details to be true), but the basic instance-class pattern, when recursively applied, gives you categories of classes, which let you change how the instance-class pattern works for certain classes.
Aren't interfaces better? Sure you have to implement it, but then you can just add a reference to another class that would have the methods already implemented.
Interfaces don't do all of what you want always.

For a real-world example, you expose a "thread safety" interface. This means you are an object that can be locked (possibly in many different ways -- read, write, transaction, exclusive, undo, etc).

Many different classes want to advertise that they are "thread safe". How they implement that "thread safe" interface varies significantly from object to object -- sometimes you know you are using a particular object in a single thread, so you use the non-thread-safe implementation, other times you need one that uses a 3rd party thread safety system, sometimes you need objects that have a single lock, other times you want full reader/writer locks, other times you want objects that can be "live" change who they derive their lock-state from, etc.

Then you go implement a class. Say a simple pixel buffer class. This pixel buffer exposes a thread safety interface.

If you have multiple inheritance, you can simply create a "final" class that mixes in the thread-safety implementation of your choice to the pixel buffer choice.

If you don't, you need to be able to manually forward interfaces over to the "has a" relationship your pixel buffer has to the thread safety. So same difference, right?

Now what happens if the thread safety class needs to know about the reference counting of the object, which similarly has multiple implementations?

In the M-U case, the thread safety is part of the class, as is the reference counting implementation. We just need to tell the thread safety class implementation that it also "is a" reference counter, then the final class must provide the implementation choice.

In the interface-forwarding case, we both need to tell the thread safety class that it "has a" reference counter, and we need to connect that reference counter up to the parent's class "has a" reference counter.

So we end up writing O(n^2) glue code to connect each class to each interface implementation that it needs to know about.

Or we give up. And we make each object do exactly one thing, and make the functions take every argument they need. Which is a viable option, but it cuts out entire chunks of design space.

Or we give up. And we invoke "there is one true reference counter and thread safety unit", and we derive every child class from that one true reference counter/thread safety unit. Which results in every implementation depending on implementation details of some low-level code, which sucks. And it makes replacing our thread-safety and reference-counting engines a serious pain, or even prototyping new ones. And if we need any new trick for some thread-safe or reference-counting object, we need to add it to every single one (practically), because we are not allowed in the design to defer the decision of which one we want until the last possible moment.
Multiple inheritance sounds messy. Should be some wild fun when I get into C++.
Now, much of what I described above was for a seriously huge project where we where doing some relatively experimental design to get it to work.

There are "best coding practices" that often boil down to "KISS" (keep it simple, stupid), and "don't do anything experimental -- only do what you have done a thousand times before", which are wise when you want to hire cheap programmers and keep your failure rate extremely low.

Multiple inheritance and the like can make projects more complex, and/or permit more complex projects to be written. This makes them bad from some perspectives. :)
 
Another way of doing multiple inheritance in Lua is to simply not use a table as your __index metamethod.

Instead, write a function that describes how the multiple inheritance works.

something like:

Code:
function setmultiplemetatables(t, metas)
  return setmetatable(t, {__index =  function(self, key) --setting __index to a function calls the function when the table doesn't have the key
    for _,meta in ipairs(metas) do
      if meta[key] then return meta[key] end
    end
  end})
end

That's just a simple example, but it's easy to see how you might make very custom behavior. For instance:

Code:
function setmultiplemetatables(t, metas)

  local checkmefirst = metas.checkmefirst

  return setmetatable(t, {__index =  function(self, key)

    if checkmefirst and checkmefirst[key] then 
      return checkmefirst[key]
    end

    for _,meta in ipairs(metas) do
      if meta[key] then return meta[key] end
    end
  end})
end

or to make the first one more efficient:

Code:
function setmultiplemetatables(t, metas)
 
  local mastermeta = {}

  for _,meta in ipairs(metas) do
    for k,v in pairs(meta) do
      mastermeta[k] = v
    end
  end

  return setmetatable(t, {__index = mastermeta}) --setting __index to a table just looks up in the table
end

I think this demonstrates pretty well the Lua idea of "mechanisms over policies." Lua does not include a language concept of multiple inheritance because that would be "implementing a policy." There are tons of ways to do multiple inheritance, and Lua does not choose one for you. Instead, it exposes the mechanisms that you would use to tailor your own language features to meet your needs.
 
  • Functions are objects, objects are theoretically callable but will throw an error if the call is undefined.
  • Tables can have so-called metatables. This can, among other things, make the table callable like a function or override the default behaviour for operators like "+" or "=". Metatables are also tables.

This one point here to explain one of the great things about LUA, from a game developer point of view. Functions been objects, or more important, variables. Means that everything can be rewrite and, the reason it was done so, sandboxed. So, they can for example easily block the load function by doing a load = nil;

More important they can sandbox it pretty well, by whitelist which functions you can use from the main libs. (check this article http://lua-users.org/wiki/SandBoxes). This is essential for multiplayer gaming.

  • Lua has a custom RegExp implementation that doesn't conform to POSIX
This is my main problem with Lua =( . The POSIX RegExp is fantastic, and I do some pretty good things with it on PHP (which has some changes, but it is mostly POSIX).
 
Back
Top Bottom