66

This is a question I've been mildly irritated about for some time and just never got around to search the answer to.

However I thought I might at least ask the question and perhaps someone can explain.

Basically many languages I've worked in utilize syntactic sugar to write (using syntax from C++):

int main() {
    int a = 2;
    a += 3; // a=a+3
}

while in lua the += is not defined, so I would have to write a=a+3, which again is all about syntactical sugar. when using a more "meaningful" variable name such as: bleed_damage_over_time or something it starts getting tedious to write:

bleed_damage_over_time = bleed_damage_over_time + added_bleed_damage_over_time 

instead of:

bleed_damage_over_time += added_bleed_damage_over_time

So I would like to know not how to solve this if you don't have a nice solution, in that case I would of course be interested in hearing it; but rather why lua doesn't implement this syntactical sugar.

Jon 'links in bio' Ericson
  • 20,880
  • 12
  • 98
  • 148
qrikko
  • 2,483
  • 2
  • 22
  • 35
  • 8
    At least one 3rd-party patch implements this: http://lua-users.org/wiki/LuaPowerPatches (Scroll down to "Compound Assignment Operators (5.2)") – finnw Nov 20 '13 at 09:58
  • 9
    Why doesn't C support classes? Why can't I use `int a = b = c = 0;` in C? Why is there no allocation like `int a, float b, char *c = 1, 2.22, "3rd string";` in C++? No offence meant, but every language has its own limitations and advantages. – hjpotter92 Nov 20 '13 at 10:24
  • 1
    @hjpotter92 No offence taken at all, you answered the question I asked proving a point which is exactly what I wanted. -> +1 – qrikko Nov 20 '13 at 10:50
  • As an "by the way" to your question, if you are looking for some nice lua syntax extensions take a look at moonscript (https://github.com/leafo/moonscript), which is a metaprogramming library that extends Lua syntax with such things, behind the scene it generates Lua. – Oliver Nov 20 '13 at 16:55
  • 1
    As an aside, long variable names like that are a sign that you are not using the appropriate data structures and/or not scoping functions to a reasonable size. Variable names should be descriptive _within their context_. – Jon 'links in bio' Ericson Nov 20 '13 at 20:30

3 Answers3

90

This is just guesswork on my part, but:

1. It's hard to implement this in a single-pass compiler

Lua's bytecode compiler is implemented as a single-pass recursive descent parser that immediately generates code. It does not parse to a separate AST structure and then in a second pass convert that to bytecode.

This forces some limitations on the grammar and semantics. In particular, anything that requires arbitrary lookahead or forward references is really hard to support in this model. This means assignments are already hard to parse. Given something like:

foo.bar.baz = "value"

When you're parsing foo.bar.baz, you don't realize you're actually parsing an assignment until you hit the = after you've already parsed and generated code for that. Lua's compiler has a good bit of complexity just for handling assignments because of this.

Supporting self-assignment would make that even harder. Something like:

foo.bar.baz += "value"

Needs to get translated to:

foo.bar.baz = foo.bar.baz + "value"

But at the point that the compiler hits the =, it's already forgotten about foo.bar.baz. It's possible, but not easy.

2. It may not play nice with the grammar

Lua doesn't actually have any statement or line separators in the grammar. Whitespace is ignored and there are no mandatory semicolons. You can do:

io.write("one")
io.write("two")

Or:

io.write("one") io.write("two")

And Lua is equally happy with both. Keeping a grammar like that unambiguous is tricky. I'm not sure, but self-assignment operators may make that harder.

3. It doesn't play nice with multiple assignment

Lua supports multiple assignment, like:

a, b, c = someFnThatReturnsThreeValues()

It's not even clear to me what it would mean if you tried to do:

a, b, c += someFnThatReturnsThreeValues()

You could limit self-assignment operators to single assignment, but then you've just added a weird corner case people have to know about.

With all of this, it's not at all clear that self-assignment operators are useful enough to be worth dealing with the above issues.

munificent
  • 11,946
  • 2
  • 38
  • 55
  • 7
    Thanks a bunch for taking the time to answer. You really point out some really plausible and likely arguments to my question. I had kind of just accepted it to be nothing but a bad question. But after reading your answer I feel more like I understand and given all the arguments, even agree with Lua on not trying to provide those operators. – qrikko Dec 05 '13 at 05:32
  • You're welcome! This stuff is fresh on my mind because I'm currently implementing a language that also has a single pass compiler and it forces me to realize how that affects the design of it. – munificent Dec 05 '13 at 06:12
  • 1
    Somebody mention recursive descent compiler and problems parsing assignment statements? I know it well, but the problems are mostly in parsing the LHS. If you can reliably find the assignment operator and make sense of the LHS, manipulating the tree to generate '+=' or equivalents is not that hard. Doing it without a tree, now that's harder. – david.pfx Apr 07 '14 at 12:01
  • 9
    *1.* But there is already an operator of this type, `:`. It's used for calling functions while automatically passing the table you're using it on as the first parameter, just like `+=` and friends. *2.* That doesn't make any sense. Why does line separation have to do with it? It'd have the same syntax as the normal assignment operator, `=`. *3.* It sounds very clear to me. You want to increment all three. – jv110 Jun 14 '17 at 21:23
  • is there any documentation on lua's *source*? like when looking into the source i found prototypes. what?! – somerandomdev49 Apr 02 '20 at 09:23
  • 1
    The source is not well documented unfortunately. "Prototype" is what Lua uses to refer to the compiled internal representation of a function before it has been wrapped in a closure. It's a function without its upvalues. – munificent Jun 07 '20 at 17:21
  • FWIW about point 3 - for example `awk` supports both multiple assignments and the `+=` operator (and other variants), so it may not be an issue in itself... – jena Aug 23 '23 at 14:17
17

I think you could just rewrite this question as

Why doesn't <languageX> have <featureY> from <languageZ>?

Typically it's a trade-off that the language designers make based on their vision of what the language is intended for, and their goals.

In Lua's case, the language is intended to be an embedded scripting language, so any changes that make the language more complex or potentially make the compiler/runtime even slightly larger or slower may go against this objective.

If you implement each and every tiny feature, you can end up with a 'kitchen sink' language: ADA, anyone?

And as you say, it's just syntactic sugar.

Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 1
    Thank you for that answer which really provide the information I wanted. It does make sense and I like how you show the general form of the question which put it in perspective. – qrikko Nov 20 '13 at 09:36
14

Another reason why Lua doesn't have self-assignment operators is that table access can be overloaded with metatables to have arbitrary side effects. For self assignment you would need to choose to desugar

foo.bar.baz += 2

into

foo.bar.baz = foo.bar.baz + 2

or into

local tmp = foo.bar
tmp.baz = tmp.baz + 2

The first version runs the __index metamethod for foo twice, while the second one does so only once. Not including self-assignment in the language and forcing you to be explicit helps avoid this ambiguity.

hugomg
  • 68,213
  • 24
  • 160
  • 246
  • 2
    The second option would be more sensible like `do local t=foo.bar t.baz=t.baz+2 end`. – Thomas W Mar 16 '14 at 09:35
  • 10
    `:` is a very similar operator in Lua, and does not work like that. It just calls `__index` once, and the value is used twice. – jv110 Jun 14 '17 at 21:25