lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


Oops, you're right.
I rarely use long brackets, and absolutely never after an identifier for an implicit function call without parentheses, or after any other _expression_. Long brackets litterals (with [[...]] or [=[...]=] or with longer matching sequences of "=") are very rarely used (unlike long comments where "[[...]]" or "[=[...]=]" or al. immediately follows "--")

In fact long brackets cause various issues for code maintenance,

Notably you can't comment out some parts of long-brackets string literals.

You can more easily maintain your code by using only concatenations of string literals with the ".."  operator (that the compiler should impliclty optimize into merged literals without forcing the runtime to call successive binary operator function calls; such assumption should not be made)

And in my opinion it should be clear in the Lua specification that implicit concatenation of string literals into a single precomputable string value is the expected default, which can be avoided explicitly (where it is absolutely needed) either by using either parenthesed subexpressions, or separate assignment statements into a string variable

Even table.concat() can optimize the allocation of the final result string, as it implicitly can and even should use "tostring()" calls on all enumerated non-nil members before building the final result
Tthe order or grouping (right to left or left-to-right, or any suitable order that could reduce memory overhead for concatenating pairs of strings, is also dependant on the implementation of table.concat() even if it internally uses the ".." operator mapped to an equivalent function call

The only case where this could bring a different result is
* when the first member of the concatenation (of 3 or more values) is not a string, and the binary ".." operator has been overriden to not always return a string but some other object type with other properties,
* or when this operator accepts a non-string value in the first member, and treats the sequence of "o..b..c" like the "<<" stream operator in C++.
(in that case, this does not mean that the final concatenation of the string value of the object is performed, just that a tostring() operation on this object will really make the concatenation, the object can still use any convenient store, such as keeping the members of the concatenation in an sequence kept in a property of the object; how the tostring() operation will be implemented is left to the implementation which can use any order or grouping to create the final string result in an efficient way, and the members of the internal sequence property are not required to be converted individually to strings immediately, as some members may not be immediately evaulatable as such if their string value depends on other members, or on the final state of the object which will indicate how to serialize members into a suitable output string, or would depend on other parameters given to tostring() such as a desired encoding like 'UTF-8' or 'HTML' or 'EBCDIC' or 'MIME'; the same object containing the enumerated items could be reused to return multiple tostring() values).

For example you could have an string-like object containing not just the string value, but also a language code property, or some other (mutable) properties needed for encoders or for stateful data compressors, for which the left-to-right grouping and order of concatenation calls really matters or would make no sense if they are grouped differently. But the concatenation of two "non-decorated" string literals must have a predictable result.

But even in this case if you use (object .. 'literal1' .. 'literal2') it should behave exactly like (object .. 'literal1literal2'), ie. a single concatenation, but  ((object .. 'literal1') .. 'literal2') would still be different and should perform two separate concatenations in the specified left-to-right order, just like also (object .. 'literal1' .. variable) or (object .. variable .. 'literal1')... except if "variable" is declared as a *constant* with a literal string value (which would them allow its replacement by the compiler as if we inserted the literal directly instead of the variable name defining with this literal.

With this rationale, long literals are never necessary, code is simpler to manage (and comment out) using only 'single-quoted' or "double-quoted" one-line literals, separated by ".." operators with this specified semantic (which will avoid runtime overhead caused by multiple memory allocations for string buffers and by runtime reevaluation of string hashes if concatenated strings are used for key-indexing into tables)




Le dim. 24 mai 2020 à 14:06, Andrew Gierth <andrew@tao11.riddles.org.uk> a écrit :
>>>>> "Philippe" == Philippe Verdy <verdyp@gmail.com> writes:

 >> Well, you'd need to invent something else, because [[...]] already
 >> has a meaning in Lua. (t[[x]] is actually a function call, though
 >> not a very obvious one.)

 Philippe> I'm very curious about which function call is made, because
 Philippe> "[x]" inside "[]" cannot be a valid _expression_ that would
 Philippe> perform some "magic" function call (which function?? with
 Philippe> which parameters?? Couldn't this magic function call be some
 Philippe> "getmetatable(object)", but with which "object "and how is
 Philippe> then used "x"?)

[[x]] is a long-bracket string literal, equivalent to "x".

So t[[x]] is equivalent to  t "x"  which is equivalent to t("x").

This isn't at all obvious - I only realized it myself when the issue
came up on the IRC channel, when someone had taken a chunk of lua code
from an autoconf file (not realizing that all the [ ] had been changed
to [[ ]] thanks to m4 syntax) and couldn't see why it gave errors about
calling something that wasn't a function.

--
Andrew.