Log In  

Hello all.
I'm doing alright at the moment with the new Pico-8 and I'm typing away happily.
One problem though.... I seem to be typing 'self' a LOT and using loads of valuable characters and/or tokens.

Is there a simple way to cut back on the number of times I have to use 'self'?

Its probably really complicated and I thought I was doing well...

Many thanks in advance
Peej

P#95156 2021-07-21 21:42

I came across a thread a few days ago which might be helpful.

Token saving tip

P#95178 2021-07-22 09:51
:: Peej

Thanks jasondelaat.
I've seen that one too... I understood none of it unfortunately.

P#95179 2021-07-22 10:00
1

The gist of it is that you can change how variables are referenced on a per-function basis so you can cut down on having to use the dot. I'll see if I can simplify it.

Every Lua program has this thing called _ENV which references everything in the global scope: variables, functions, etc. Anytime you reference something in the global scope Lua, behind the scenes, actually translates it into a reference to _ENV. For example, let's say we define a new global variable.

some_var='blah'

Anytime we write 'some_var' in our code Lua translates that into '_ENV.some_var'. You can also do it manually to see how it's working.

print(some_var)
print(_ENV.some_var)

Those two lines both print 'blah' to the screen.

The trick is that _ENV is just a normal Lua table like any other so you can redefine it to whatever you want. Actually, we don't want to redefine it so much as point it at something else temporarily. To see how this works, here are a couple tables both with an 'a' and a 'b' field.

table_a={
   a=1,
   b=2
}

table_b={
   a=10,
   b=20
}

And here's a dummy function we want to pass the tables to.

function f(e)
   local _ENV=e
   if a == 1 then
      b = 100
   else
      b = 1000
   end
end

Notice that we don't refer to 'e.a' or 'e.b' but just 'a' and 'b' because Lua automatically converts those to '_ENV.a' and '_ENV.b' and we set _ENV=e. It's also important that you define _ENV using 'local' here. If you don't use local you'll overwrite the global _ENV and lose everything in it, including the PICO-8 API. A function will look for it's local _ENV first and then, only if it can't find it locally, use the global _ENV. This is called shadowing: You hide the global _ENV behind an identically named local variable so you can't see it.

Now we can use the function with our tables.

f(table_a)
f(table_b)

print(table_a.b)
print(table_b.b)

This prints 100, then 1000. So even though we only used 'a' and 'b' inside the function we still actually changed the properties on the tables themselves!

The downside of shadowing _ENV like this is that, while we're inside the function, we don't have access to any of the normal stuff in the global scope. For instance, this next example won't work as written:

function g(e)
   local _ENV=e
   print(a)
   print(b)
end

The reason it doesn't work is because 'print' is in the global scope (global _ENV) but we don't have access to it at the moment. There are a few things you can do to get around this. The linked thread above is using a clever method with metatables to make sure you still have access to the global scope even after you've redefined _ENV but you don't have to go that far depending on what you need or if you don't understand metatables. (I don't really understand metatables for what it's worth. Haven't needed them so far...)

If you only need one function from the global scope, say 'print', then you can just make a local "copy" before you reassign _ENV, like this:

function g(e)
   local print=print
   local _ENV=e
   print(a)
   print(b)
end

g(table_a)
g(table_b)

And that will work as expected. You can also just save the whole global scope in another variable and use whatever you need from it.

function h(e)
   local g=_ENV
   local _ENV=e
   g.print(a)
   g.print(b)
end

h(table_a)
h(table_b)

And again, that'll work just fine. For these simple cases you don't really gain much. In the last function, for instance, we've just traded off e.something for g.something and don't actually save any tokens. Actually we use more tokens because we have to define g and _ENV!

But if your function uses a whole bunch of e.somethings and only a couple prints (or whatever) then you'll end up saving tokens overall.

Finally, Lua objects are really just Lua tables with some extra fancy syntax so you can use these same tricks:

an_object={
   a=1,
   b=2
}

function an_object:a_method()
   local _ENV=self
   if a == 1 then  -- this is actually self.a in disguise
      -- do stuff
   end
   --[[
      rest of function...
   ]]
end

This may or may not be the token saving tip you were wanting but hopefully it clears things up a bit.

P#95182 2021-07-22 16:34
:: Peej

Brilliant reply there, jasondelaat, HUGE thanks for that.
I'll have to read it a few times over but it's much clearer now. Again, thank you.

P#95187 2021-07-22 19:17

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2021-09-20 17:39:05 | 0.012s | Q:14