Why/how is the .text argument/variable of display.newText always stored as a string?

Asking more out of curiosity. I setup a system where if the .text of any text objects are in a table format they’ll automatically refresh any variables they display.
I don’t need to update text that isn’t in table form, so I checked for tables but turns out they only get stored as strings regardless of the input.

local txt=display.newText({self,"health"}, 50, 40)
print(type(txt.text)) --str
print(txt.text) --blank...?

local itxt=display.newText("health", 50, 40)
print(type(itxt.text)) --str
print(itxt.text) --"health"

I ended up storing the state (whether its got the table or a string field), in the variable name itself via string.start(itxt, “itxt”). Could possibly just check for blank-space though, although unsure if conflicts somewhere.
But why do I have to do that? I thought .text would just be a variable entry of the object and print(txt.text) should show a table…can someone explain why/how it’s being turned into a string I don’t get that.

For proper usage you should consult the docs:

First off, to whet your curiosity, you should read what both the manual and the book have to say about metatables.


“But why do I have to do that?” Well, the short answer is, the text object needs to find a string (it does display text, after all), and so it expects to get a string. :slight_smile: And text is the delivery mechanism.

As you probably realized, Solar gives you display objects as tables. You can add entries to them and even inspect them with pairs() (although you should definitely not blindly muck with the stuff that’s already there! :smiley:). If you do that, you’ll see a “proxy” value.

There’s a native (C++) component to display objects as well, and these are coupled to the table, i.e. the Lua part, through its metatable, in particular its __index and __newindex metamethods.

Minus some glue, the __index part of text objects begins here and the __newindex follows that. You can see the case 0 in each of them, with the comments indicating it corresponds to text.


The upshot is that, since the tables don’t have a text field, accesses go through the __index and __newindex machinery. (You actually could use rawset() to assign this field, but there will be nothing but confusion and sadness. :smiley:)

I would probably err on this case being on the “it’s not a good idea” side, but since you’re “Asking more out of curiosity”, you can get something like what you want by writing your own metamethods.

In your __index, for the text key, if you detected (through some ancillary key, not text itself; my_text, for example), that there was table data, you could return the table’s text member. Otherwise, for this key or any other, just forward on to Solar’s behavior.

In the __newindex, if you encounter the text key, and it’s table data, save it in that ancillary key AND forward the string on to the built-in behavior. For anything else, just forward it on.

This is a little tricky since you probably don’t want to stomp on Solar’s own metatables—so you want to chain your own to one of those—and you need to make your own __index and __newindex do the forwarding.

I have code for this (undocumented, mea maxima culpa)…

…and here is an example of it being used, in this case to augment a circle object. (On first use it will rig everything up, then reuse the new metatable when it sees Warp again.) I probably have better examples elsewhere, but this shows adding methods and “read properties” at least.

I’ll assume you mean well, but the emote usage is insufferable. Unless the other person is using them, don’t use them.
I don’t fully follow what you are saying, but I get the jist of it. If someone wants to directly link it to the OP case that would be helpful, otherwise knowing its backend and related to the metables is useful enough for now. You are saying objects tables are using metatables by default is my understanding…and they come into play here. Not really understanding why type() is displaying the way it is, short of it not being designed to work in these cases.

Not only do objects use metatables “by default”, but that’s key to how they work.

Metamethods change certain built-in table behaviors, the relevant ones here being those of getting / setting fields that don’t exist.

Not finding a text field in the table, but seeing the Solar-provided __index metamethod, a lookup will call that, and find the string in the native-side object instead. Similarly for __newindex with assignment.

You nailed it with “not being designed to work in these cases”. The textbox doesn’t have a Lua string, but a C++ one as part of the native-side object. An assignment will copy the Lua string you supply into its native counterpart, or push the contents of what that contains when you do a lookup. If you give it a non-string, a “null” string gets copied, which I guess either clears the value or leaves it as is; in any case, this is why the type information gets lost.

And that’s generally the case with built-in display object properties, unless otherwise noted.

It sounds like you’re diving deep into meta tables! Using custom index and new index is a smart way to handle text without breaking Solar’s default behavior. Just be careful to chain your meta table to Solar’s and forward calls properly to avoid messing things up. It’s tricky but super powerful once you get it right!

1 Like