Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Global functions, class inheritance and self (seems like a useful "trick")

in General Posts: 108

I was trying to find a way to make a function that I could reuse in different classes. I checked the lua manual and tried out some things, landing on the following working test:

-- TEST_GlobalSelf

function setup()
    a = y()
    print (a.x)
    a.test = testf
    a:test()
    print (a.x)
end

y = class()
function y:init()
    self.x = 0
end

function testf(self)
    self.x = 1
end

Seems like it could be a useful thing to others.
Maybe there are some other tips or related tricks?

My biggest curiousity I am currently trying to understand : meta-methods and __index

Comments

  • edited October 6 Posts: 102

    not totally sure what you're going for here, I'm also learning meta methods. basically you take a table and set a metatable, which can be the same table like so.

    --creates table kat, and gives it an empty metatable
    
    kat = setmetatable({}, {})
    x = getmetatable(kat)
    
    --slightly better
    mouse = setmetatable({15}, mouse)
    teal=setmetatable({},{__index=mouse})
    print(teal[1])
    
    --create table price, sub tables sell and buy, and make them their own metatable
    price = {}
    price.sell, price.buy = setmetatable({}, price.sell ), setmetatable({}, price.buy)
    
    -- this won't work, it can't pass the table price inside to the keys for some reason
    price = {sell=setmetatable({}, price.sell), buy=setmetatable({}, price.buy)}
    

    index means that if the index doesn't exist, then we check the metatable. if .__index is a table, then we check that table for the index. if it's a function, run that function instead.

    --here index is a table. if it doesn' find it in x, then it looks for the index in fallback
    fallback = {[0]='zero'}
    x = setmetatable({1,2,3}, fallback)
    fallback.__index = fallback
    print(x[0])--zero
    print(x[5])--nil
    
    --Index can also be a function.
    g = {myIndex=function() return 'No index found' end}
    x = setmetatable({10,20,30,[7]=70}, g)
    g.__index = g.myIndex
    print(x[5], x[6])
    
    -- it keeps going! look in x[5], then fallback[5], then double_fallback[5]
    double_fallback = {[5]='five'}
    fallback = setmetatable({[0]='zero'}, double_fallback)
    double_fallback.__index = double_fallback
    x = setmetatable({1,2,3}, fallback)
    fallback.__index = fallback
    print(x[0]) 
    print(x[5])
    
  • Posts: 108

    What I am mainly trying to do is find the best way to go about inheriting in class(), different levels of abstraction, in order to build a modular and efficient, yet easy to understand API, and there are some things I would love to figure out.

    In my earlier example, the "trick" I was pointing out is that a function can have 'self' as an input which can then be imported into classes and re-used. I should go back later and revise my initial post and explain, right now it makes no sense and is missing context, thank you for helping me to realize that.

    ~~~

  • Posts: 553

    I may not be totally getting your purpose here, bu are you aware that Codea's current class implementation already supports single inheritance?

    It seems like you're trying to create something like multiple inheritance?

    Otherwise I don't quite understand the purpose of the concept of re-importing methods one by one, since any function with global scope can already be accessed by any class that needs it.

  • edited November 4 Posts: 108

    Yes @UberGoober, like multiple inheritance, It seemed most logical in some things I am doing. I create different levels of abstraction that are repeated throughout different classes in different ways, for example the concept of position and size (seems ubiquitous in 2D GUI and GLSL, like in SODA and CIDER they both use a “FRAME” or “PANEL” or “WINDOW” class).

    I think I was working on two things that I found this multiple class inheritance flexibility useful toward the end of keeping my Table hierarchy tidy. In the GUI library I am making, I made a “value” class as the core of my structure, and a GUI class that makes callbacks to set “value”, and I had begun making a “number” widget which probably isn’t the best name for it, but it shows a “value” drawn in text that you can drag up and down or left and right to scrub like an endless slider, or tap to invoke a numeric direct entry, (maybe I will even add long press or double tap as a way to set min/max/default attributes)..

    anyway, because my number = class(value) only allowed inheriting the one “value” class, I tried making self.val = value() and self.gui = gui() in my number:init() for the class, but this made it a bit strange to access the value from the GUI and set with the touch because it was then self.val.val to get at the value and that’s the type of thing I get neurotic about toward the end of having a clean and non-redundant API.

    Thus I started looking into meta tables/metamethods as a solution, and when I hit a bit of confusion with that (still not quite grasping some details of __index, rawget, and mt, but I think I might take another crack at it today). I ended up looking a bit more into what is possible with ‘self’ since Lua does not have a class creation element inherently. Thus this post was my reflection on the internals of how Lua can use ‘self’ and create fully elemental class type structures. I can create a group of methods that use

    Function myFunction(self, x, y )
       Return self.value+x*y;
    End
    

    And anything can call that function with the syntactic sugar ‘:’ operator to pass itself into the self reference.

    myObject:myFunction( 1,2) —myObject is passed in as self by the ‘myObject ‘:’
    

    (I love that syntactic sugar phrase all over the Lua manual, syntax sugar sounds like delicious poison meant to kill inconvenience leaving a yummy aftertaste of clean elegant code )

    I agree that in most cases the current implementation of classes in CODEA is probably the best option, I guess if anything my post was maybe more so myself understanding the lower level way that Lua achieves class like method inheritance.. maybe it’s more relevant in raw Lua since CODEA has a good solution.

  • Posts: 108

    @xThomas I think the part that I don’t quite get still is the syntax of how these index meta tables are set up.
    In your example :

    mouse = setmetatable({15}, mouse)
    teal=setmetatable({},{__index=mouse})
    print(teal[1])
    

    why do you need to make
    mouse = setmetatable(...,mouse)
    And then index - mouse for teal.. I guess what is that first empty table passed to teal.. and does _index have Use outside of the context of metatables?

Sign In or Register to comment.