I was trying to get string indexing using brackets to work on pico-8.
I quickly found this discussion on lua-uers.org that discusses this problem in Lua 5.1 and 5.2.(See below)
However, after trying several solutions provided in the discussion I still can't get any to work in pico-8.
They work on my other Lua IDEs, but somehow pico-8 always returns runtime errors.
Current code:
--from lua-users.org getmetatable('').__index = function(str,i) return string.sub(str,i,i) end getmetatable('').__call = function(str,i,j) if type(i)~='table' then return string.sub(str,i,j) else local t={} for k,v in ipairs(i) do t[k]=string.sub(str,v,v) end return table.concat(t) end end --demo a="1234123512345" print(a[4]) |
Current results:
Does anybody know how to correctly implement this in pico-8?
PICO-8 Lua unfortunately doesn't have all the backing libraries etc. that you might expect to be available with other Lua implementations so it can behave a bit differently in some contexts. This seems to be one of them.
In the version of Lua they're using in that thread there's a string
module which implements the string 'class' (it's not really a class in the sense of say Java or C++ but whatever) and all its methods and meta-methods. But we don't have that in PICO-8. Strings are just a simple data type and, as such, don't have methods or an associated metatable.
If you run this...
x = getmetatable('') print(x) |
... you'll see that it prints [nil] which is why you're getting that 'attempt to index a nil value' error. Since it doesn't have a metatable you won't be able to set or override any of the metamethods because there aren't any.
You'll also notice that there are no methods on strings and instead we have function equivalents. So, for instance, instead of this:
s = 'hello' print(string.sub(s, 2, 2)) |
In PICO-8 we have this:
s = 'hello' print(sub(s, 2, 2)) |
All of which is sort of a long winded way of saying that if you really want to be able to index strings like this, you'll have to build it yourself from scratch. That's probably more trouble than it's worth. You'd need to implement a string metatable and a constructor function to create a string object from PICO-8's simple string type.
Here's a short example to give you the idea:
string = { new=function(s) str_obj={__the_string=s} setmetatable(str_obj, string) return str_obj end, __tostring=function(self) return self.__the_string end, __index=function(self, i) return sub(self.__the_string, i, i) end } s = string.new('hello') -- you have to explicitly create string objects print(s[2]) -- prints 'e' |
This is by no means complete but you get the idea. The major problem with this approach though is that the string objects and basic strings won't play nicely together. String concatenation won't work, for instance, unless you implement the __concat
method on the string metatable. Basically you're going to end up duplicating a whole lot of functions and using precious tokens for no real benefit.
Ahh, that makes a lot of sense... Haven't thought about this possibility yet, and thanks a lot for explaining it in such detail. To be honest, I am not a huge fan of object-oriented coding, I guess I would actually prefer the pico-8 implementation of strings purely from the perspective of a minimalist language design. I guess maybe I will just stick to the sub
function for now... I'll just accept it as some self-imposed inconvenience from using pico-8.
No worries, happy to help. I'm not a huge fan of object oriented programming either. Not that there's anything wrong with OOP per se it's really just personal preference. Lua's object model is more prototype based than class based which I tend to prefer if I am going to do OOP but in pico-8 I think the general consensus is that you run into diminishing returns really fast. For such relatively small projects your OOP implementation ends up costing you too many tokens for whatever benefits you might get from it. And frankly I think the benefits are often dubious at best. Although OOP claims that it's really good for abstraction and encapsulation but in my experience it mostly makes people think that they're creating good abstractions that are well encapsulated when, in fact, they're not because a programming paradigm isn't a substitute for design. Not that you can't write good code with OOP but it can be brittle if it's not done well. Nothing wrong with procedural/functional code in my book!
Anyway, sorry for the mini-rant which has nothing to do with your question! But I'm glad I could help.
in pico-8, strings can use the length operator just like tables...
#"asdf1234" -- 8 |
but cannot be indexed into it like a table...
("asdf1234")[1] -- attempt to index constant (a string value) |
so, as mentioned above, you can write some additional methods to make it work a little better. perhaps you can bind them to the global environment _G, but i wasn't able to get it working in time this morning.
alternatively, a string can be converted to table in a one-liner using SPLIT()
split("asdf1234","")[3] -- "d" |
To get one character, using sub will be more efficient than split
.
[Please log in to post a comment]