One nice thing about objects is that objects set with the =
operator or as arguments are all 'linked' meaning, among other things, you can provide them as arguments for a function call and that function will be able to edit the local copy of that object and have it affect the original one too. But sometimes, you don't want that. Sometimes you want to copy an object, make changes to it, and then discard the new copy without affecting the old one. That's why I've created a little helper function for this circumstance. Actually, I've created several. Here's the fully-featured 'default' function:
function cpy_obj(obj,recursion) if type(obj)=="table" then local return_value={} for k,v in pairs(obj) do if recursion then v=cpy_obj(v,true) end return_value[k]=v end return return_value else return obj end end |
Usage: copy= cpy_obj(𝘰𝘣𝘫𝘦𝘤𝘵)
or function_call( cpy_obj(𝘰𝘣𝘫𝘦𝘤𝘵) )
return_value
is the new object being created. Note that since we are creating it a piece at a time, it has no affiliation with the previous object. If you give it something that is not an object, it will just give you the input variable back. recursion
is a boolean that asks if we want to make nested objects be decoupled as well. You usually want this if you have nested objects, but keep in mind that this comes with a performance cost, and although it's rather small, you might not want that if you're pushing up against the limits of PICO-8.
Variants
Every project is different, and with that comes different requirements. One person will be working on a game jam that has no risk of reaching the token limit, and another will be working on a 3D engine that needs to be as compact as possible. As such, I have a few different variants that may cater to your project's particular demands...
Forced recursion
This one shaves off five tokens (plus one every time you need recursion!), but comes at the downside of a forced performance cost. Still, this one is probably closer to being the more useful one than the default one due to the token savings.
No recursion
This one saves five more tokens than the previous one, but lacks recursion entirely. Of course, you won't always (and usually don't) need recursion, but if you do then this function won't cut it for you.
No non-object return values
This one save TEN more tokens than even the last one, but non-object inputs will result in a crash as the API function
pairs()
won't know what to do.
Ultra-cheap snippet
This one is cheaper than all of the others at just thirteen tokens, but must be copy-pasted everywhere you intend to use it meaning it only saves tokens if you only use it in one or two spots (which very well may be the case). Whatever you do, be sure to replace
𝘰𝘭𝘥_𝘰𝘣𝘫
and 𝘯𝘦𝘸_𝘰𝘣𝘫
with your object names.
Comparisons
Lastly, here's a list of the token costs of each function, assuming all arguments are one variable:
Default : 42 to define , 3 or 4 per call Forced recursion : 37 to define , 3 per call No recursion: : 32 to define , 3 per call No non-object return values : 22 to define , 3 per call Ultra-cheap snippet : no definition , 13 per call |
have you looked at prototypes? that’s how lua does inheritance, and is an interesting technique to know (imo better to have a good mental model of how one language works, rather than forcing concepts from other languages). see this:
function ref(tbl) return setmetatable({}, --tbl = prototype of ^ table {__index=tbl}) end function see(o) print(o.n,o.x,o.y) end cls() orig={x=10,y=20,n="o"} see(orig) clone=ref(orig) --search "x" in clone then orig print(clone.x,2,120) --set "x" in clone clone.x=70 clone.n="c" see(clone) --this works! clone.y+=32 --because it means this, which --searches in clone>orig and --sets in orig clone.y=clone.y+32 see(clone) |
in this approach
- creating tables is fast because there is no copy
- function is very few tokens
- prototypes can be chained
- the cost of finding properties is paid at each
clone.prop
access - it’s very dynamic, you can add or can change values on the prototype and see that reflected when accesing the property on descendent tables (as long as the prop wasn’t set there)
this is a good page with more background for this concept (and a great book too): https://gameprogrammingpatterns.com/prototype.html
[Please log in to post a comment]