Pluto, a Modern Lua Dialect
pluto-lang.org
pluto-lang.org
Instead of their new fancy syntax:
print(message ?? "The message was nil.")
The idiomatic way would be: print(message or "The message was nil.")
The or operator works just fine. (Edit: Note that this works because empty strings, lists and the number 0 are all truthy in Lua)Generally not a big fan of adding additional syntax and operators for minimal gain.
I feel like most changes are nice to have but not really worth the disadvantage of not being able to use LuaJIT.
Honestly, the most interesting goal for me is is having a beefier Python-style standard library. Now, if we had that together with LuaJIT levels of performance that would be an absolute Python killer.
The only actual problem with Lua (that can't be fixed without forking) is that new variables are global by default but you can cope with that. Just have your linter check that you are always using the "local" keyword. Couldn't find if Pluto is fixing that.
Edit: Oh they provide a "let" alias for "local", case in point, little changes with not much value.
This idiom seems to have been made widely popular by Perl folks, and while it has always been a good trick up your sleeve when you're 16 and want to impress the other kids, it's never been a good, correct way of doing things seriously, especially not across different scripting languages when every single one has its own Byzantine rules of what counts as truthy and what as falsey (like empty strings or empty lists). It is an especially pernicious idiom because of the widespread clout with which it tends to be transmitted; turns out it's one of the Falsehoods Clever Programmers Think They Know Better About. They don't.
it would certainly be frustrating to have to juggle these semantics as you switched back and forth.
however, languages are just that - they have their own meanings, and unfortunately they can't all be the same across languages (or they'd all be the same language).
Be that as it may but shrugging and sighing, like, "ah well, different languages will be different" and using that as an argument against a discussion of the merits and demerits of certain aspects of certain languages is not constructive, is it?
I've indeed gotten tired by the entire idea of Boolean projections, yes, but that's not the point here, at least not almost always in practice.
Different languages have different semantics. Yes, using the or operator like that is not a good idea in many languages but in Lua it is idiomatic.
return 0 or 42
> 0
Obviously the pattern doesn't work for checking for the existence of booleans as both nil and false are falsy but you are less likely to confuse that. So yes, the ?? would help a little bit but then again, you could just explicitly check for nil.that's the only point of the operator.
given: a = 0; b = 42;
then `a or b` and `a ?? b` give two different answers, but take the same number of characters to write.
> just explicitly check for nil
1. I am lazy and 2. I am explicitly checking, that's why I picked `??` not `or`
local x = false
print(x ?? "message was nil")
print(x or "message was nil")
which results in>false
>message was nil
I've done a fair bit of professional lua development and I don't think I've ever written standalone up-to-date puc lua except maybe for some tooling & scripts. It's such a small language and used in such a way that the runtime, distribution method, and available APIs have much more impact on your use (and compatibility) than the version.
Virtually everyone shipping a lua environment is also shipping changes to it that make it a unique target, if only extensions to the standard library. This is why I think syntax layer-only approach like fennel's is the correct choice for improving on lua. It mirrors lua's runtime semantics exactly, and allows you to access the implementation peculiars on their own terms and so can just be run on top of any lua system.
the good:
- string interpolation
- a continue statement
- conditional expressions
- augmented assignment
- frozen tables
- some kind of static typing?
the bad:
- much worse documentation
- no luajit
- you can't compile without c++‽ that's the opposite extreme from 'retains the easy embeddability of Lua'
- and wtf, a build system in php? the nope level is rising rapidly
- you still index from 1
- variables are still global by default
- misspelling a variable or property still gives you nil instead of throwing an exception
- aping c++/java syntax and semantics for classes and class instantiation
- redundant aliases for operators
- a redundant mechanism for private fields
- dwim for for-in on a table
it seems like a c++ or perl programmer didn't understand what was good about lua and decided to make it look like perl
Conditional expression which I imagine is ternaries can be done with a constructor and the condition in the field a la {nil,"b"}[cond and 1 or 2]
Isn't that the whole point of "frozen tables", which you listed as "good"? For globals, freeze `_G` and/or `_ENV`.
I cannot even imagine how pattern matching will work when it always returns nil, not to mention tables are full of nil sometimes, it would be an incredible waste to have a table full of false instead of nil.
what do you mean about pattern matching
i may be falling into the trap of trying to make language x more like language y that i'm more familiar with, but i think that if a language has one or more nil values, it's usually worthwhile to draw a distinction between a variable that has one of those values and a variable that doesn't exist at all. lua gets some simplicity out of conflating these situations, because it means it doesn't need a separate mechanism for causing variables to cease to exist (you can simply assign nil), and sometimes it can simplify your code by leaving initialization implicit. but i think that the result is that lua is a lot more bug-prone
languages that do draw a distinction between not existing, and existing with a null value, include smalltalk, ruby, c, c++, python, javascript, perl, python, tcl, java, the bourne shell (except perhaps very early versions), pascal, common lisp, scheme, golang, rust, octave, and most assembly languages. conflating the two is not completely unique to lua; awk, basic, and arguably fortran 77 do that, though the nil value they give previously nonexistent variables is a numeric 0 rather than Γ
the bourne shell and by default perl also allow reads from nonexistent variables with well-defined semantics, and perl and js also allow reads from nonexistent table slots (hash and array slots) with well-defined but sometimes startling semantics. but none of these have the behavior shared by lua, awk, basic, and arguably fortran 77, where there's no way to tell the difference between a nonexistent variable and a variable that has had the null value assigned to it
so i think that lua's design choice here should be regarded as an experimental innovation, like java's checked exceptions; and, specifically, a failed one
so there would be no problem with pattern matching returning nil and storing it in a variable
I think having a special datatype differing between nil and null would still render the code the same, instead of using if var==nil, you're just now doing if var==null, if you're using a variable after you know a function was used and its nil you know it returned null. you can always just use { or false } if you really need to differ between nil (and waste space), that or use assert()
Also my problem with pattern matching returning nil is it breaks usage of concatenative :, as in match:""match"":match""
So if you use concatenative objects with :, make sure you never return any other type but the object itself. its what allows lpeg operator overloading to not error out in the middle of it.
https://ecss.nl/standard/ecss-e-st-70-32c-test-and-operation...
[1] https://github.com/PlutoLang/Pluto/blob/main/src/ljumptabgcc...
[2] https://github.com/PlutoLang/Pluto/blob/main/src/ljumptab.h
There seems to be zero braking force on adding new features to the syntax and libraries. While I agree with 90% of them, I can find no discussion of why they were added, what arguments against adding were considered, how the decision was made, and by whom.
I have created my own (as yet unreleased) fork of Lua, adding some of these same features. I could abandon it and instead use (and contribute to) Pluto, but I am frightened by the mystery surrounding its origins, governance, and seeming lack of community input into the future direction.
The "continue" statement[3] is the one I really wish was available everywhere.
[1] https://pluto-lang.org/docs/New%20Operators#compound-operato...
[2] https://sdk.play.date/2.1.1/Inside%20Playdate.html#_lua_enha...
[3] https://pluto-lang.org/docs/New%20Features/Continue%20Statem...
Where does `$file` come from in `for_each_obj` <https://github.com/PlutoLang/Pluto/blob/0.8.0/scripts/compil...> ... from `scandir` of "src" of course: https://github.com/PlutoLang/Pluto/blob/0.8.0/scripts/common...
Here's hoping you didn't want to alter the intermediate output directory away from "int" or change the CPPFLAGS for your own setup
I'm certainly no php ninja, but I'd put good money that a similarly homegrown bash build system would be about an equal number of lines of code but 1/10000th the WTF and not require an apt-get install before trying to contribute to the project
Then again, writing maintainable Bash is a pain so I don't totally hate it. Definitely have wrestled with a fair share of write-only Bash scripts where I was tempted to rewrite them in PHP.
I think berrylang shows a lot of promise now https://berry-lang.github.io/. The documentation has improved a lot and while it doesn't have a 'luajit' yet it has a lot of really interesting optimisation/reduction techniques.
script.pluto:1: warning: function was hinted to return string
but actually returns nil [type-mismatch]
1 | function foo(x: number): string
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ here
Unfortunately the underlying table was corrupted when the code ran and only 1 foo
was generated in the output. I would have preferred it to have refused to run at all (will need to look in the docs to see if there's a way to get that behavior with configuration). The purist in me wants more but the practical side of me appreciates that this is definitely an improvement over current Lua.¹: https://pluto-lang.org/web/#code=function%20foo(x%3A%20numbe...
https://pluto-lang.org/docs/New%20Features/Compiler%20Warnin...
The language just doesn't distinguish "key present with no value" in a table, which is frankly a bizarre thing to want with typechecking in the same breath.
I think working with newer languages like Typescript have made me unsatisfied with languages like Lua which provide no clear way to prevent this sort of mistake, so I like that dialects like Pluto are showing ways Lua could be improved.
Requiring C++17 to build is also a downgrade.
The lambda shorthand looks fine. Typing might be useful. But it says that's WIP so I'll have to try it out more than the examples. Default arguments, named arguments, the added general operators and safe navigation operators are generally useful and positive changes.
Compiler message improvements would be great to port, too.
I see Pluto as a research project of sorts, trying new things. Trying incompatible and controversial things in such a project is the point.