Working lua need advice deciding which method is best
Moderator: Forum Moderators
- Spannerbag
- Posts: 557
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Working lua need advice deciding which method is best
Hi,
I've finally bitten the bullet and decided to make a coherent attempt at learning lua.
It's slow, but I'm making progress.
I have some very basic lua that works, I'd just like to sanity check my approach.
All I wanted the code to do initially was confirm the value of some lua variables in a
Here's the lua:
This all works fine, as does an alternative message format (with added line breaks to aid legibility):
I prefer the first (concatenation) method however I've read on stackoverflow that this is inefficient.
I'd like to use a stringx.join as I presume this is more efficient but that wants a list and I couldn't find a (sane) way to get that to work with simple strings.
So, my question is this: what's the best (i.e. most efficient and preferably most terse) form of this logic?
Thanks in advance for your time and trouble.
Cheers!
-- Spannerbag
I've finally bitten the bullet and decided to make a coherent attempt at learning lua.
It's slow, but I'm making progress.
I have some very basic lua that works, I'd just like to sanity check my approach.
All I wanted the code to do initially was confirm the value of some lua variables in a
[message]
- and it's this bit I want to check.Here's the lua:
Code: Select all
local _ = wesnoth.textdomain "wesnoth-stub"
-- Pass values from WML to lua
function wesnoth.wml_actions.dbck_setup(cfg)
local event_name = cfg.event_name or wml.error "[dbck_setup] missing required event_name= attribute."
local side_candc = tonumber(cfg.side) or wml.error "[dbck_setup] missing required side= attribute."
local unit_filter = cfg.unit_filter or wml.error "[dbck_setup] missing required unit_filter= attribute."
wml.fire("message",
{ speaker = "narrator", message = stringx.vformat(_ "dbck_setup values in lua:\nevent_name=" .. event_name .. "\nside_candc=" .. side_candc .. "\nunit_filter=" .. unit_filter)})
end
Code: Select all
wml.fire("message",
{ speaker = "narrator", message = stringx.vformat(_ "dbck_setup values in lua:
\nevent_name=$eventname\nside_candc=$sidecandc\nunit_filter=$unitfilter",
{eventname=event_name,sidecandc=side_candc,unitfilter=unit_filter})})
I'd like to use a stringx.join as I presume this is more efficient but that wants a list and I couldn't find a (sane) way to get that to work with simple strings.
So, my question is this: what's the best (i.e. most efficient and preferably most terse) form of this logic?
Thanks in advance for your time and trouble.
Cheers!
-- Spannerbag
Re: Working lua need advice deciding which method is best
I would not worry about this unless you are (a) inside a loop, and (b) performing concatenation on the same string over and over again inside that loop.Spannerbag wrote: ↑April 10th, 2024, 11:12 am I prefer the first (concatenation) method however I've read on stackoverflow that this is inefficient.
Performing a single string concatenation, or even five string concatenations (as in your first example), is unlikely to cause performance problems.
There are other problems with your first example, though:
- It is using both
stringx.vformat
and concatenation. This doesn't really make sense - normally you would use one or the other, but not both. - It isn't translatable. (What you're doing with
_
won't really work right.) Since it appears to be just for debugging purposes maybe this isn't an issue, but if you want your output to be translated it is probably better to avoid concatenation and just usestringx.vformat
(like in your second example).
- Celtic_Minstrel
- Developer
- Posts: 2281
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Working lua need advice deciding which method is best
You don't need to make it translatable at all. Just concatenate if that feels easier for you, but keep in mind that when you do need something to be translatable that you must use
stringx.vformat
(or string.format
is fine too).- Spannerbag
- Posts: 557
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Working lua need advice deciding which method is best
Thanks for taking the trouble to reply, much appreciated.gnombat wrote: ↑April 10th, 2024, 12:55 pm ...There are other problems with your first example, though:
- It is using both
stringx.vformat
and concatenation. This doesn't really make sense - normally you would use one or the other, but not both.- It isn't translatable. (What you're doing with
_
won't really work right.) Since it appears to be just for debugging purposes maybe this isn't an issue, but if you want your output to be translated it is probably better to avoid concatenation and just usestringx.vformat
(like in your second example).
I'm very much a beginner here so please bear with me.
First, why does using both
stringx.vformat
and concatenation not make sense?Can
stringx.vformat
also concatenate and I missed it?Or is there some other reason?
Also, what am I doing wrong with
_
?Is it in the wrong place or needs a comma or brackets somewhere or what?
I have no idea I'd got that wrong so have no idea how to remedy it!
Sorry to be dim but this is all very new to me.
Thanks again for your help.
Cheers!
-- Spannerbag
- Spannerbag
- Posts: 557
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Working lua need advice deciding which method is best
Thanks for taking the trouble to reply.Celtic_Minstrel wrote: ↑April 10th, 2024, 1:30 pm You don't need to make it translatable at all. Just concatenate if that feels easier for you, but keep in mind that when you do need something to be translatable that you must usestringx.vformat
(orstring.format
is fine too).
It's not so much that concatenate feels easier but the second method involved creating local variables just for a message which seemed to me to be unnecessarily complicated and wasteful - surely there's an easier, quicker and more elegant way to do this?
Ideally I'd like a way to create a
[message]
in lua that has (lua) variables embedded in it as simply as possible without extra bells and whistles.As in my previous post this is all new to me and I don't have a sense of what's right and wrong yet.
I can probably hack out code that works but I don't want to develop bad habits early on!
Again thanks for your advice.
Cheers!
-- Spannerbag
Re: Working lua need advice deciding which method is best
Well, yes? Isn't that basically what your second example was doing - concatenating strings usingSpannerbag wrote: ↑April 10th, 2024, 2:25 pm First, why does using bothstringx.vformat
and concatenation not make sense?
Canstringx.vformat
also concatenate and I missed it?
stringx.vformat
, without using the concatenation operator (..
)?I'm just going to try to simplify your examples a bit (skipping the translation for now):
Code: Select all
local x = 1
local y = 2
wml.fire("message", { speaker = "narrator", message = "X is " .. x .. " and y is " .. y })
wml.fire("message", { speaker = "narrator", message = stringx.vformat("X is $x and y is $y", {x=x,y=y}) })
wml.fire("message", { speaker = "narrator", message = string.format("X is %d and y is %d", x, y) })
X is 1 and y is 2
. The first one uses the concatenation operator (..
). The second one uses stringx.vformat
and does not use the concatenation operator. The third one is similar to the second but uses string.format
.There isn't really any reason you would want to use both the concatenation operator
..
and stringx.vformat
together.Does that make sense?
- Spannerbag
- Posts: 557
- Joined: December 18th, 2016, 6:14 pm
- Location: Yes
Re: Working lua need advice deciding which method is best
Yesgnombat wrote: ↑April 10th, 2024, 2:59 pmWell, yes? Isn't that basically what your second example was doing - concatenating strings usingSpannerbag wrote: ↑April 10th, 2024, 2:25 pm First, why does using bothstringx.vformat
and concatenation not make sense?
Canstringx.vformat
also concatenate and I missed it?stringx.vformat
, without using the concatenation operator (..
)?
I'm just going to try to simplify your examples a bit (skipping the translation for now):
Those three messages should all contain the exact same output:Code: Select all
local x = 1 local y = 2 wml.fire("message", { speaker = "narrator", message = "X is " .. x .. " and y is " .. y }) wml.fire("message", { speaker = "narrator", message = stringx.vformat("X is $x and y is $y", {x=x,y=y}) }) wml.fire("message", { speaker = "narrator", message = string.format("X is %d and y is %d", x, y) })
X is 1 and y is 2
. The first one uses the concatenation operator (..
). The second one usesstringx.vformat
and does not use the concatenation operator. The third one is similar to the second but usesstring.format
.
There isn't really any reason you would want to use both the concatenation operator..
andstringx.vformat
together.
Does that make sense?
First off, thanks for the example code, good to see all options grouped together.
That makes sense, what I was hoping might be possible would be to have something like the
stringx.vformat
but without the {...}
bit.I suppose I was hoping to be able to have a construct like:
wml.fire("message", { speaker = "narrator", message = "X is ?x and y is ?y })
where "?" is an operator like "$" in WML, i.e. "use the value of this variable".
I just wanted to be sure there wasn't a way of doing this (or a clever syntactical short-cut) that involved neither
..
nor {...}
*.Clearly there isn't, or you'd've mentioned it so I know my options now.
So thanks for your patience and clear examples, they helped. A lot.
* - What is the correct term for doing a
{...}
btw?Oh, no pressure or anything but if you do get chance (and aren't utterly bored with my stupidity) I'd still like to know what it was with
_
I got wrong.Let's see what I can break next...
Cheers!
-- Spannerbag
Re: Working lua need advice deciding which method is best
A table constructor.
Spannerbag wrote: ↑April 10th, 2024, 7:52 pm Oh, no pressure or anything but if you do get chance (and aren't utterly bored with my stupidity) I'd still like to know what it was with_
I got wrong.
_
is a function which should always take as its argument a single literal quoted string, which should generally be a complete sentence rather than a fragment of a sentence.Suppose you have two variables you want to use in a sentence:
Code: Select all
local color = "red"
local species = "dragon"
local sentence = "There is a " .. color .. " " .. species .. "."
Code: Select all
# WRONG: the argument to _() should be a single literal quoted string
local sentence = _("There is a " .. color .. " " .. species .. ".")
Code: Select all
# ALSO WRONG: the argument to _() should be a literal quoted string, not a variable
local sentence = "There is a " .. color .. " " .. species .. "."
sentence = _(sentence)
Code: Select all
# ALSO WRONG: the argument to _() should be a complete sentence, not a fragment of a sentence
local sentence = _("There is a ") .. color .. " " .. species .. "."
..
):Code: Select all
# THIS WORKS: the argument to _() is a single literal quoted string which represents a complete sentence
local sentence = stringx.vformat(_("There is a $color $species."), {color=color,species=species})
Re: Working lua need advice deciding which method is best
If you used global variables then
With local you need to explicitly add them.
Or use local v={}, v.color = "red", v.species = "dragon",
stringx.vformat(_("There is a $color $species."), _G)
something of this idea will work. _G is table of global variables.With local you need to explicitly add them.
Or use local v={}, v.color = "red", v.species = "dragon",
stringx.vformat(_("There is a $color $species."), v)
Re: Working lua need advice deciding which method is best
The stringx.vformat documentation also suggests using WML variables - then this should work:
Code: Select all
stringx.vformat(_("There is a $color $species."), wml.all_variables)
- Celtic_Minstrel
- Developer
- Posts: 2281
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Working lua need advice deciding which method is best
I wouldn't say there is no reason at all, but the case discussed in this thread is definitely not a reason to use them together.
What there's not point in doing is calling
vformat
with just a string as argument and no variable definitions. You're calling it just for it to do nothing because there was nothing to substitute. (Although in fact it'll delete all the variable references from the string, I think – or substituted default values where specified.)This doesn't actually work, as
vformat
requires a WML table as the argument.-
- Posts: 1296
- Joined: August 26th, 2018, 11:46 pm
- Location: A country place, far outside the Wire
Re: Working lua need advice deciding which method is best
Code: Select all
_("There is a $color $species.")
I don't mean to divert the thread, but it does seem like the choice the of "best" string formatting tool may depend on the string, particularly when translation is important.
Of course this is all academic since we should all be using sprintf-like tools, since that's the way I learned and therefore anything that works differently is wrong.
Speak softly, and carry Doombringer.
Re: Working lua need advice deciding which method is best
Yes, that's the idea - the translators could change the order of the variables for languages in which the noun would appear before the adjective.white_haired_uncle wrote: ↑April 11th, 2024, 2:14 amI only speak American, not even English, but that looks like a pain for translators. Would they re-order $color and $species as necessary (in which case this appears to be a preferable alternative to string.format, which I find much more readable)?Code: Select all
_("There is a $color $species.")
Yes, there could be other issues, too, but fortunately there is no such thing as an ...white_haired_uncle wrote: ↑April 11th, 2024, 2:14 am What about gender (a -> un or una depending on the unknown gender of $species). And even in American, a could be an for color=azure
https://en.wikipedia.org/wiki/Azure_Dragon
- Celtic_Minstrel
- Developer
- Posts: 2281
- Joined: August 3rd, 2012, 11:26 pm
- Location: Canada
- Contact:
Re: Working lua need advice deciding which method is best
None of that is handled, which is why you shouldn't construct translatable strings in this way. The only things that are safe to be substituted into a translatable sentence are numbers and proper nouns, and in the latter case you still need to have two copies of the string – one feminine and one masculine. (Substituting whole paragraphs into a string, or in some case full sentences, may also be fine.)white_haired_uncle wrote: ↑April 11th, 2024, 2:14 amI only speak American, not even English, but that looks like a pain for translators. Would they re-order $color and $species as necessary (in which case this appears to be a preferable alternative to string.format, which I find much more readable)? What about gender (a -> un or una depending on the unknown gender of $species). And even in American, a could be an for color=azure (I know I ran into a tool that handles that, though not in wesnoth, strings in Qt I think?).Code: Select all
_("There is a $color $species.")
You could certainly write code to automatically handle substitutions like this example. It would be complicated, and it would require different code for every language. Basically, the program would need to fully understand the systems of noun declension and verb conjugation in the target language. But Wesnoth's translation system makes no attempt to do this, so the solution is to keep your substitutions simple.
Re: Working lua need advice deciding which method is best
I'm not sure what you mean by "none of that is handled" - the point I was trying to make with that example is that re-ordering the variables is handled, which is why using a formatting function may be preferable to simply using the concatenation operator. Of course, there may be other translation issues that are not so easy to solve.Celtic_Minstrel wrote: ↑April 11th, 2024, 4:11 amNone of that is handled, which is why you shouldn't construct translatable strings in this way. The only things that are safe to be substituted into a translatable sentence are numbers and proper nouns, and in the latter case you still need to have two copies of the string – one feminine and one masculine. (Substituting whole paragraphs into a string, or in some case full sentences, may also be fine.)white_haired_uncle wrote: ↑April 11th, 2024, 2:14 amI only speak American, not even English, but that looks like a pain for translators. Would they re-order $color and $species as necessary (in which case this appears to be a preferable alternative to string.format, which I find much more readable)? What about gender (a -> un or una depending on the unknown gender of $species). And even in American, a could be an for color=azure (I know I ran into a tool that handles that, though not in wesnoth, strings in Qt I think?).Code: Select all
_("There is a $color $species.")