I would like to propose the following syntax extensions to PICO-8 for symmetry with the shorthand peek operators. Basically it means treating the peek operators result as an lvalue:
@x = y -- short for poke(x,y) %x = y -- short for poke2(x,y) $x = y -- short for poke4(x,y) @x += z -- short for poke(x, @x + z) %12 |= %42 -- short for poke2(12, %12 | %42) $x >><= 4 -- short for poke4(x, $x >>< 4)
Would they actually be faster though? The reason we're given peek operators that cost fewer virtual cycles is to encourage us to use them, because the interpreter can handle them much faster than the old peek() calls. But this is because adding a unary op to the interpreter is easy and involves adding an actual opcode that can be interpreted directly, rather than having the overhead of a Lua function call, which does happen with peek() even though the guts of the function are presumably C code. It still has to handle Lua's custom stack/ABI for passing the address argument, whereas the opcode just gets its operand direct from the code stream with no shimming required.
Adding a new kind of lvalue that, instead of assigning to a lua variable, writes to custom "memory", probably isn't as easy, so I worry that it'd just end up as a search/replace for poke() and thus wouldn't be any faster under the hood, so we wouldn't be given a cycle incentive to use it.
That being said, it would still just be nice if it were orthogonal like that, even if it weren't any better perf-wise. :)
Good point, @Felice. I'm hoping the shorthand poke() syntax could also be swapped with faster opcodes, since peek() already seems like a non-standard feature for Lua. Like, instead of just find/replacing @x=y with poke(x,y) and getting the function call overhead back, maybe it could pre-convert @x=y into [email protected]=y (to qualify for operator overloading), or just use an inline assignment? That syntax would be less intuitive, but could also be more optimizable.
Just on intuition, I thought this was why the peek operators were more efficient than the function calls, likely because it's inlined or those kinds of overloaded ops get cached somehow. It sounds like you have a better understanding of how the internals work, though, so I'll defer to your experience.
Actually I just tried to implement this for fun and while the opcode part was not as challenging as I thought, the problem is the parsing inconsistencies it creates: for instance “x=0 %x=y” is invalid because it is first parsed as “x=0 %x” which is valid Lua, then the “=y” part causes a syntax error. The choice of operators here makes it impossible to implement this in a consistent way.
[Please log in to post a comment]