Can you cache another class's method locally?

After some extensive googling, I can't find an answer to this, maybe because I don't know how to ask it!

I know you can cache a function from a table as a local to save lookups. For example, we can draw a 10 by 10 rectangle at 0,0 with a cached function, like this:

local drawRect = playdate.graphics.drawRect
drawRect(0, 0, 10, 10)

This works so long as you omit the () from the end of the local declaration. However, I can't figure out how to do the same thing with a Class object's method! In this example, pb.UI is a CoreLibs/object, class('pbUI').extends(playdate.graphics.sprite). I guess since methods are invoked with : instead of dot notation, this results in an error:

local activateSpeechbox = pb.UI:activateSpeechbox

Trying to cache pb.UI:activateSpeechbox(event_name) in a local throws the compile error function arguments expected near 'local'. But I can't figure out where to put function arguments without inadvertently invoking the method at declaration time, which I obviously don't want.

Is there a way to do this? Thanks for any help!

It's probably useful to know that the color : in lua is just a shortcut when calling a function with the object as the first argument (to add a little touch of object oriented programming)

So
myObject:draw(10)
is exactly the same as
myObject.draw( myObject, 10)

which mean you can put a function as a local variable:
local activateSpeechbox = pb.UI.activateSpeechbox

but you need to call is with the object
activateSpeechbox(pb.Ui, event_name)

So the best is to cache both the object and the function

local ui = pb.UI
local activateSpeechbox = ui.activateSpeechbox
activateSpeechbox( ui, more_arguments)
2 Likes

Thanks. I was afraid that might be the case! I mean, it's not so bad to just add that extra argument, and performance-wise this is probably a lot better than calling the full nested-table method lookup every time I need to use it elsewhere.

So, technically speaking, when you use the colon, it's... sort of invoking the method, even without the (), just missing the other expected arguments? Or rather, if you use :, the compiler just won't parse it without the (args).

Just thinking this through, would caching the object and function be better than wrapping the standard call in a local function? Such as

local ui = pb.UI
local function activateSpeechbox(event_name)
  ui:activateSpeechbox(event_name)
end

Or is this basically the same? Worse? It would simplify the function call so you wouldn't need to put ui as the first argument, but then isn't actually caching the method locally, so you're not saving that lookup.

I could do

local ui = pb.UI
local cachedActivateSpeechbox = ui.activateSpeechbox
local function activateSpeechbox(event_name)
  cachedActivateSpeechbox(ui, event_name)
end

If my priority is to prevent forgetting the extra argument in future usage, to keep it from differing from the invocation inside the class itself.

Just wondering about this in the abstract from a convenience perspective; your solution will work perfectly-fine for my needs. Thanks, Nic! :smiley:

On my list of things to look into is memoize() which can cache the results of functions.

https://www.lua.org/pil/17.1.html
17.1 – Memoize Functions - Lua

The Lua manual isn't really as readable as I'd like.

Yeah! I think the PIL book is great for the first ~10 chapters or so, as an explanation of reasoning and syntax. But the later examples definitely feel like out-of-context snippets that often leave me scratching my head a little.

Memoization is great; that's basically what @shaun did in his implementation of an AssetManager in this thread, which works great. It creates images, etc at the last-possible moment, but then reuses them once they've been created.

I don't think memoization would help in this case (this activateSpeechbox() method accepts a key, which sets up and then starts a dialogue box system that runs itself afterward, and which in most cases will only call a given event once. So, lots of different results from the same function call, rather than commonly-repeated results. Right? I should definitely memoize a LOT more of my common functions, though, because I think a lot of our in-game logic produces a fairly small number of possible results repeatedly.

1 Like

I keep meaning to check out this book for more in-depth code: Lua Programming Gems

And, sometimes I forget there are two basic Lua books, the Reference Manual as well as Programming in Lua.

I knew from reading those that : was a convenience to avoid setting self explicitly in every call, but none of my reading had made it clear that there was no direct way to cache a method call without caching its components separately. Anyway! Thanks for your help, everybody. I'll give in and set self manually :slight_smile: