This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
lucy-san's profile picture

Lua rants, because we all love it!

Started by lucy-san, 11 January 2015 - 02:18 PM
lucy-san #1
Posted 11 January 2015 - 03:18 PM
So yeah, I've been doing some metatables lately and felt like ranting a bit.

__index: What the actual f, lua devs? A bloody function which name indicates that it is run every time a field in table is indexed, but no no no! That would be too easy to use, wouldn't it? So instead of doing a normal index handler let's do one that is called whenever indexed field is nonexistent! Great idea! So instead of doing


local t = {
  print = function(self) print(self.text) end,
  text = "quix"
}
local mt = {
  __index = function(t , k)
	if type(rawget(t, k)) == "function" then
	  return function(...) rawget(t, k)(t, ...) end
	end
	return rawget(t, k)
  end
}
setmetatable(t, mt)

t.print()

You have to do


local t = {
  print = function(self) print(self.text) end,
  text = "quix"
}

local _t = t
t = {}

local mt = {
  __index = function(t, k)
	if type(_t[k]) == "function" then
	  return function(...)
		_t[k](_foo, ...)
	  end
	end
	return _t[k]
  end
})

setmetatable(t, mt)

t.print()

Because it looks so much better, RIGHT!?

local: Oh yes, local variables. This keyword shouldn't exist. Because there should be no need for it's existence! Every goddamn variable should be local by default! And if You need global variable (what happens never very rarely with proper design) you cloud use for example a "global" keyword, uh?


So that was it for now, please use this general stress relief thread to your pleasure!
Edited on 11 January 2015 - 02:27 PM
Lignum #2
Posted 11 January 2015 - 03:47 PM
String concatenation. When I first used Lua, I tried to do this:

"Hello " + "World"

But no, that's too complex for such a lightweight language. We have to do this:

"Hello " .. "World"
Agoldfish #3
Posted 11 January 2015 - 04:14 PM
SquidDev #4
Posted 11 January 2015 - 05:39 PM
Ok, ok… When I started with Lua I hated it. I've come from a C# & Python background so (In my opinion) have used the two best 'learning' languages. Python for its simplicity and flexibility, C# just being awesome (I'm writing Java at the moment and it makes me realise how much the .Net team got right).

However, I've come to almost love Lua, I'll go though these points one by one:

So yeah, I've been doing some metatables lately and felt like ranting a bit.

__index: What the actual f, lua devs? A bloody function which name indicates that it is run every time a field in table is indexed, but no no no! That would be too easy to use, wouldn't it? So instead of doing a normal index handler let's do one that is called whenever indexed field is nonexistent! Great idea! So instead of doing

Well, the trouble with Lua tables is that they aren't designed for how this type of (ab)use. __index is wonderful. Most of the time I use it to inherit environments (setmetatable({}, {__index = getfenv()})) or classes. I almost never use it to track access to a key.

Almost every other language uses a similar principal. Python has __getattr__, PHP has __get, I'm sure many other languages have a similar thing.

local: Oh yes, local variables. This keyword shouldn't exist. Because there should be no need for it's existence! Every goddamn variable should be local by default! And if You need global variable (what happens never very rarely with proper design) you cloud use for example a "global" keyword, uh?

Yep, agree with that. Sometimes it is useful because you can see when you define variables, however the first thing I check with any program is if it uses locals or not.

String concatenation. When I first used Lua, I tried to do this:

"Hello " + "World"

But no, that's too complex for such a lightweight language. We have to do this:

"Hello " .. "World"

In any normal language I would agree, but some languages (Lua, VB, I'm sure there are others - maybe ActionScript and PHP) have type conversion things. This is the trouble:


"1" + "1" -- 2

But I wanted 11! These are strings, but we get a number out of it? Explicitly defining addition or concatenation is really the only solution.

Anyway, it isn't as bad as some languages:
Spoiler

I'm going to suggest reading these two articles by the co-creator of StackOverflow. The general point is 'Language design is hard'. Despite Lua's many odd things, I do quite like it now.

Anyway! It is more fun writing massively complicated programs in a slightly obscure language then it is in one that actually works!

Sorry for the long post.
Edited on 11 January 2015 - 04:40 PM
lucy-san #5
Posted 11 January 2015 - 05:47 PM
In any normal language I would agree, but some languages (Lua, VB, I'm sure there are others - maybe ActionScript and PHP) have type conversion things. This is the trouble:


"1" + "1" -- 2

But I wanted 11! These are strings, but we get a number out of it? Explicitly defining addition or concatenation is really the only solution.
Well, unless javascript it shouldn't be a problem ;)/>
>only solution
Uhmm, for example: don't store ints as strings? :D/>

Anyway, it isn't as bad as some languages:
Spoiler
It would be a rather hard thing to be worse than a fractal of bad design :D/>
We are actually going to cast some of these fine sidehammers from aluminum in local Hackerspace :D/>

Sorry for the long post.
Why would You apologize for long post? Please post!
Edited on 11 January 2015 - 04:48 PM
SquidDev #6
Posted 11 January 2015 - 06:03 PM
Well, unless javascript it shouldn't be a problem ;)/>
>only solution
Uhmm, for example: don't store ints as strings? :D/>

This would be fine, but what if you are reading user input? Or sub-strings? Javascript just forces it to be a string, which I guess is the better solution, but then you need to call tonumber. *SIGH*.
It would be a rather hard thing to be worse than a fractal of bad design :D/>
We are actually going to cast some of these fine sidehammers from aluminum in local Hackerspace :D/>
What about VBA/VB6, Fortran, Applescript, HTML and Milton Keynes? Laravel makes PHP nice to write.

The thing is Lua works. People have written Web browsers, encryption software, and Java in it. It is pretty easy to learn. From Dan200's point of view, there really isn't another embeddable language for ComputerCraft. I know the language I would end up designing would look like a C#/D mutant mess. I can't complain really!

I would suggest looking at ElvishJerricco's LuaLua. He has managed to get Yueliang working in CC. See if you can use it to make fix concatenation and locals!
Edited on 11 January 2015 - 05:33 PM
lucy-san #7
Posted 11 January 2015 - 06:58 PM
>This would be fine, but what if you are reading user input? Or sub-strings?
It should stay as string, since it is string. If you will need an int, you will convert type. Calling int, tonumber or whatever else is the way to go. Excatly because "1"+"1"==2.

>The thing is Lua works.
PHP works as well.
AFAIK lua was never meant to be a professional language, but a simple language for modding, etc. It gets job done, but it could get job done in nicer way. No language is perfect and lua is not bad, neither is excellent rough.

>Dan200's point of view, there really isn't another embeddable language for ComputerCraft
He could use Jython, but ain't complaining - we could be running BASIC or JavaScript.

> See if you can use it to make fix concatenation and locals!
Maybe, but it would be pointless - it's like lua compiled to JavaScript, but worse. Running lua in lua in Java VM will not be an efficient solution ;)/>
Agent Silence #8
Posted 11 January 2015 - 07:26 PM
>The thing is Lua works.
PHP works as well.
AFAIK lua was never meant to be a professional language, but a simple language for modding, etc. It gets job done, but it could get job done in nicer way. No language is perfect and lua is not bad, neither is excellent rough.

There are occasions when you have a game/engine that uses Lua. For example, World of Warcraft and Crysis1/2/3(Uses Lua along with C++) both use Lua.
Bomb Bloke #9
Posted 11 January 2015 - 10:40 PM
Removing "local" altogether would completely break the language, as explained here. How would you prevent new variables in functions and loops and so on from accessing upvalues of the same name? You couldn't do it - you'd be forced to make sure every new variable in your script had a unique title. It'd be a royal mess.
ElvishJerricco #10
Posted 11 January 2015 - 11:43 PM
I hate that Lua 5.2 removed setfenv and uses that stupid _tEnv thing. There's so much brilliant hackery that you can do with setfenv it's wonderful.

I despise the wordiness of the language. Do / then end is awful. I just want brackets…

This is more a problem with scripting languages than Lua itself: I wish I could just compile my code so that I'm not using unsafe globals and stuff all the time. Access is important, and it lets the compiler / VM do extra optimization. Indexing globals by string names, for example, is slow.

Related to that point: Using multiple files in CC Lua is a nightmare. You have to use os.loadAPI, which means you can't have a .lua extension unless you override loadAPI manually. It also means your code is now in the global scope because why not? The other option is manually loading files but that's tedious. If we could just have a function similar to require…

Problem with CC rather than Lua: I want the debug library dammit! I know it's not exactly safe to enable by default, but it needs to be a config option.
ElvishJerricco #11
Posted 11 January 2015 - 11:56 PM
I would suggest looking at ElvishJerricco's LuaLua. He has managed to get Yueliang working in CC. See if you can use it to make fix concatenation and locals!

Unfortunately there's no fixing concatenation with LuaLua. The + operator must emit an add instruction. And it's the VM that determines how an add instruction works with string types. The reason I say it can't emit a concat instruction is this:


function concat(s1, s2)
    return s1 + s2
end

Lua has no way of knowing if s1 and s2 are strings or numbers or whatever. So the only option is to emit an add instruction, which the VM doesn't handle with strings like it should.

Maybe, but it would be pointless - it's like lua compiled to JavaScript, but worse. Running lua in lua in Java VM will not be an efficient solution ;)/>

I should point out that LuaLua is not a Lua VM. It's a Lua compiler. It just adds syntax to Lua and runs the resulting bytecode through ordinary means. There's no in-between except the compilation step, which is tiny.
Lyqyd #12
Posted 12 January 2015 - 07:48 AM
Nobody forces you to use os.loadAPI. I have lately been writing configuration files as valid lua, then doing something like what os.loadAPI does (set up its env table, run the file, then use the resulting filled env table) to load them up and make use of them. It's quite handy and doesn't pollute the global table.
lucy-san #13
Posted 12 January 2015 - 07:53 AM
Removing "local" altogether would completely break the language, as explained here. How would you prevent new variables in functions and loops and so on from accessing upvalues of the same name? You couldn't do it - you'd be forced to make sure every new variable in your script had a unique title. It'd be a royal mess.

Every goddamn variable should be local by default



I just want brackets…
+2


Related to that point: Using multiple files in CC Lua is a nightmare. You have to use os.loadAPI, which means you can't have a .lua extension unless you override loadAPI manually. It also means your code is now in the global scope because why not? The other option is manually loading files but that's tedious. If we could just have a function similar to require…
Just the execute file, or construct it that way, that it will return a "class" containing all functions.


Unfortunately there's no fixing concatenation with LuaLua. The + operator must emit an add instruction. And it's the VM that determines how an add instruction works with string types. The reason I say it can't emit a concat instruction is this:


function concat(s1, s2)
  if type(s1) == "string" or type(s2) == "string" then --# Or whatever type returns
	return tostring(s1) .. tostring(s2)
  else
	return s1 + s2
  end
end


I should point out that LuaLua is not a Lua VM. It's a Lua compiler. It just adds syntax to Lua and runs the resulting bytecode through ordinary means. There's no in-between except the compilation step, which is tiny.
Oh, this changes a lot then ;)/>
Edited on 12 January 2015 - 06:54 AM
Bomb Bloke #14
Posted 12 January 2015 - 08:00 AM
Removing "local" altogether would completely break the language, as explained here. How would you prevent new variables in functions and loops and so on from accessing upvalues of the same name? You couldn't do it - you'd be forced to make sure every new variable in your script had a unique title. It'd be a royal mess.

Every goddamn variable should be local by default

Yes, I saw that, and I'm saying that wouldn't work. How would you declare a new local with the same name as an old one? If it's done automatically the first time you refer to a variable in a function, then how would you refer to upvalues?

function concat(s1, s2)
  if type(s1) == "string" or type(s2) == "string" then --# Or whatever type returns
	return tostring(s1) .. tostring(s2)
  else
	return s1 + s2
  end
end

Something along these lines could be applied, but the overhead… You'd need to add it to the bytecode around every single + in each script. Ouch.
Edited on 12 January 2015 - 07:05 AM
lucy-san #15
Posted 12 January 2015 - 08:30 AM
Removing "local" altogether would completely break the language, as explained here. How would you prevent new variables in functions and loops and so on from accessing upvalues of the same name? You couldn't do it - you'd be forced to make sure every new variable in your script had a unique title. It'd be a royal mess.

Every goddamn variable should be local by default

Yes, I saw that, and I'm saying that wouldn't work. How would you declare a new local with the same name as an old one? If it's done automatically the first time you refer to a variable in a function, then how would you refer to upvalues?

Same way You do now?
ElvishJerricco #16
Posted 12 January 2015 - 08:55 AM
Unfortunately there's no fixing concatenation with LuaLua. The + operator must emit an add instruction. And it's the VM that determines how an add instruction works with string types. The reason I say it can't emit a concat instruction is this:


function concat(s1, s2)
  if type(s1) == "string" or type(s2) == "string" then --# Or whatever type returns
	return tostring(s1) .. tostring(s2)
  else
	return s1 + s2
  end
end

My point was more that the + operator can't be changed in the compiler to concatenate strings. I'm aware that Lua code can be written to handle doing either concatenation or addition. It's just that the + operator must equate to an add instruction.

Nobody forces you to use os.loadAPI. I have lately been writing configuration files as valid lua, then doing something like what os.loadAPI does (set up its env table, run the file, then use the resulting filled env table) to load them up and make use of them. It's quite handy and doesn't pollute the global table.

Well what I mean to say is that there is no decent way to work in multiple files without writing your own code loading system. You can, and it's not too bad but, but I think a better way should just be included in CraftOS
Edited on 12 January 2015 - 07:55 AM
lucy-san #17
Posted 12 January 2015 - 02:33 PM
My point was more that the + operator can't be changed in the compiler to concatenate strings. I'm aware that Lua code can be written to handle doing either concatenation or addition. It's just that the + operator must equate to an add instruction.
By compiler You mean LuaLua? I haven't read the code, but I'm pretty sure that this can be accomplished in one way or another :)/>

Nobody forces you to use os.loadAPI. I have lately been writing configuration files as valid lua, then doing something like what os.loadAPI does (set up its env table, run the file, then use the resulting filled env table) to load them up and make use of them. It's quite handy and doesn't pollute the global table.

Well what I mean to say is that there is no decent way to work in multiple files without writing your own code loading system. You can, and it's not too bad but, but I think a better way should just be included in CraftOS

Yes, it sucks big.
MKlegoman357 #18
Posted 12 January 2015 - 03:23 PM
Well, from my point of view Lua's 'require' is basically 'dofile' but with a little more functionality for managing libraries. 'dofile' works quite well instead of 'require'.

What I don't like about CC Lua is the lack of not just the debug library but all Lua's libraries. Literally, why CC doesn't have all the default Lua's libraries. In fact almost every library can be recreated in CC Lua so I do not see why, for example, the io library couldn't be completely added and functional in CC. And the package library with 'require'. And the debug library (allowed by config option). Why Dan? Why??
thedobbles #19
Posted 12 January 2015 - 06:29 PM
>The thing is Lua works.
PHP works as well.
AFAIK lua was never meant to be a professional language, but a simple language for modding, etc. It gets job done, but it could get job done in nicer way. No language is perfect and lua is not bad, neither is excellent rough.

There are occasions when you have a game/engine that uses Lua. For example, World of Warcraft and Crysis1/2/3(Uses Lua along with C++) both use Lua.

As well as G-Mod and Roblox!
lucy-san #20
Posted 12 January 2015 - 07:34 PM
Well, from my point of view Lua's 'require' is basically 'dofile' but with a little more functionality for managing libraries. 'dofile' works quite well instead of 'require'.

What I don't like about CC Lua is the lack of not just the debug library but all Lua's libraries. Literally, why CC doesn't have all the default Lua's libraries. In fact almost every library can be recreated in CC Lua so I do not see why, for example, the io library couldn't be completely added and functional in CC. And the package library with 'require'. And the debug library (allowed by config option). Why Dan? Why??

Probably somewhere "because f you" and fact, that lua libraries are usually written in C/Cop. Is there debug library in luaj?
MKlegoman357 #21
Posted 12 January 2015 - 07:44 PM
I suspect LuaJ has all the native Lua libraries built-in. But like I said, a lot of Lua libraries can be made in plain CC Lua.
Edited on 12 January 2015 - 06:53 PM
Engineer #22
Posted 12 January 2015 - 09:37 PM
I suspect LuaJ has all the native Lua libraries built-in. But like I said, a lot of Lua libraries can be made in plain CC Lua.
What's the point about reinventing the wheel?
anyway, I think Dan has reasons for the removal of those libraries. You'll live without those libraries, they are not life dependant
Agent Silence #23
Posted 12 January 2015 - 09:46 PM
Well, from my point of view Lua's 'require' is basically 'dofile' but with a little more functionality for managing libraries. 'dofile' works quite well instead of 'require'.

What I don't like about CC Lua is the lack of not just the debug library but all Lua's libraries. Literally, why CC doesn't have all the default Lua's libraries. In fact almost every library can be recreated in CC Lua so I do not see why, for example, the io library couldn't be completely added and functional in CC. And the package library with 'require'. And the debug library (allowed by config option). Why Dan? Why??
Why does everyone want the debug library? Im confused as to what it does.
Lyqyd #24
Posted 12 January 2015 - 10:15 PM
So they can break the sandbox more easily. That might not be what it would be used for initially (it does have debugging uses as well), but that's the biggest thing it would be used for after maybe a day at most. We will likely never see it in ComputerCraft.
ElvishJerricco #25
Posted 13 January 2015 - 01:10 AM
So they can break the sandbox more easily. That might not be what it would be used for initially (it does have debugging uses as well), but that's the biggest thing it would be used for after maybe a day at most. We will likely never see it in ComputerCraft.

I would love the debug library so that I could, you know, debug. I say it should be a config option so that I can use it for debugging, then distribute a program that doesn't rely on the debug library.

My point was more that the + operator can't be changed in the compiler to concatenate strings. I'm aware that Lua code can be written to handle doing either concatenation or addition. It's just that the + operator must equate to an add instruction.
By compiler You mean LuaLua? I haven't read the code, but I'm pretty sure that this can be accomplished in one way or another :)/>

I mean you could. But doing so would require replacing every add instruction with a series of operations that would ultimately just be very slow.
Bomb Bloke #26
Posted 13 January 2015 - 06:22 AM
Certainly it wouldn't hurt to have the debug libraries accessible via config. There'd need to be some warnings attached, though - the typical server owner, if asked by one of their users to enable them, wouldn't have any idea as to the ramifications. Some commented lines in the config should suffice.

Same way You do now?

Those were two mutually exclusive methods. I'm not sure what you're on about. :|

Let's say "local" is abolished, and you have this:

x = 0

for i=1,10 do
  x = x + 1
end

print x

Is the "x" that we're assigning to within the loop local to that loop, or does it refer to the pre-defined upvalue above the loop? That is to say, does the print statement at the end print 0, or does it print 10?

Let's say it's a new local. In that case, how would you make it refer to the upvalue? By constantly sticking an "upvalue" keyword in front of it? You'd end up typing that more often than you have to type "local" now. Re-assignments to upvalues typically occur far more frequently than new declarations.

Let's say it's the upvalue. What options would you have if you wanted to declare a new variable, short of using a unique title every single time? There goes that flexibility - you'd need to make absolutely sure you don't let your names collide.

These aren't insurmountable problems; but I'm not seeing a solution that isn't worse than the original issue.
ElvishJerricco #27
Posted 13 January 2015 - 06:30 AM
Certainly it wouldn't hurt to have the debug libraries accessible via config. There'd need to be some warnings attached, though - the typical server owner, if asked by one of their users to enable them, wouldn't have any idea as to the ramifications. Some commented lines in the config should suffice.

Yea as it stands, debugging in CC can be a nightmare. I really don't see a reason not have this config option.
SquidDev #28
Posted 13 January 2015 - 07:51 AM
-spoiler-

Yea as it stands, debugging in CC can be a nightmare. I really don't see a reason not have this config option.

I thought about re-implementing some elements with bytecode injection. I started some work here, though most of it doesn't work.

Basic description behind it:
SpoilerThe idea was that you replace:

local function a()
  local a = "HELLO"
  local b = "ANOTHER"
  return a .. b
end

with the bytecode equivalent of.

local function a()
  local a, b
  __pushStack(1, function() return a, b end)
  local temp = a .. b
  __popStack()
  return temp

This means when you get an error, you can get the top most function on the stack, and get all locals via a function. The overhead for small functions would be massive though. The 1 would be a function ID, so you could trace which function was called better.

I guess you could also use a similar idea for breakpoints.

I stopped work on it because I got distracted and multiple exit points is tricky.

What I don't get though is why emulator developers don't add the option for it, even if we don't have it normal ComputerCraft?
Edited on 13 January 2015 - 06:52 AM
MKlegoman357 #29
Posted 13 January 2015 - 02:05 PM
What's the point about reinventing the wheel?
anyway, I think Dan has reasons for the removal of those libraries. You'll live without those libraries, they are not life dependant

But you have to modify most of the external Lua scripts or libraries if you want to include in your scripts. By saying that 'you can write most of the libraries in plain CC Lua' I meant that if it is possible to do it, why didn't Dan include them? I understand why debug library is dangerous but the package library? It would of course be restricted to local .lua files so C libraries couldn't be loaded but why not to include it at all? At the worst all those libraries could have been rewritten as an API just like io library is now. But why to exclude them completely?
Edited on 13 January 2015 - 01:06 PM
lucy-san #30
Posted 14 January 2015 - 09:11 AM
Those were two mutually exclusive methods. I'm not sure what you're on about. :|

Let's say "local" is abolished, and you have this:

x = 0

for i=1,10 do
  x = x + 1
end

print x

Is the "x" that we're assigning to within the loop local to that loop, or does it refer to the pre-defined upvalue above the loop? That is to say, does the print statement at the end print 0, or does it print 10?

Let's say it's a new local. In that case, how would you make it refer to the upvalue? By constantly sticking an "upvalue" keyword in front of it? You'd end up typing that more often than you have to type "local" now. Re-assignments to upvalues typically occur far more frequently than new declarations.

Let's say it's the upvalue. What options would you have if you wanted to declare a new variable, short of using a unique title every single time? There goes that flexibility - you'd need to make absolutely sure you don't let your names collide.

These aren't insurmountable problems; but I'm not seeing a solution that isn't worse than the original issue.

It should refer to upvalue, just as Python and any other normal language does. Reusing names is not a good coding habit.
In normal case you rarely will have to handle more than handful of variables at once - you will have functions, classes and loops, not spaghetti with gotos.
Engineer #31
Posted 14 January 2015 - 07:36 PM
Reusing names is not a good coding habit.
Yet there has to be accounted for it, because not all people follow conventions