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.

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.