Howdy, Stranger!

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

__index for sugar [Solved]

edited July 2013 in Questions Posts: 277

hello !

I have an instance of class (called obj after) who contains {w=10, h=10}.
I want access by 2 way : obj.w and obj.width.
I know about the __index function, but i don't know how write this =/

Comments

  • edited July 2013 Posts: 2,161

    (Warning: only tested on desktop lua.)

    a = {}
    mt = {}
    mt.__index = function(t,k)
      if k == "width" then 
        return k.w
      end
    end
    mt.__newindex = function(t,k,v)
      if k == "width" then
        rawset(t,"w",v)
      else
        rawset(t,k,v)
      end
    end
    setmetatable(a,mt)
    

    Testing:

    a.w = 10
    print(a.w)
    print(a.width)
    a.width = 20
    print(a.width)
    print(a.w)
    

    (Added)

    Note: if your initial object is an instance of a class then you don't want to overwrite its metatable as I do above because it already has some useful stuff in it. So you'd need to so mt = getmetatable(a) first instead of mt = {}. I'd also test to see if __index or __newindex are blank first - I don't remember what Codea's class does to objects' metatables.

  • Posts: 105

    Hm... am i missunderstanding you or have you just written:

    w=10, h=10
    

    without the self thing. Only the Main class variables does not have to contain self before them selves. So the only way to access he value of obj.w is to write "self." before "w".
    I hope I understood you right :)

  • edited July 2013 Posts: 277

    thanks a lot @Andrew_Stacey !
    and @MMGames, i have write a "bad example". A better example (with solution)

    Object = class(ObjectFather)
    Object.sugars = {width="w", height="h"}
     
    function Object:init()
       ObjectFather.init(self)
       self.w = 10
       self.h = 10
    end
     
    ------------------- At the end of file -------------------
    function Object:__index(k)
       if Object.k then return Object.k end
       for sugarKey, key in pairs(Object.sugars) do
          if k == sugarKey then
             return self[key]
          end
       end
    end
    function Object:__newindex(k,v)
       for sugarKey, value in pairs(Object.sugars) do
          if k == sugarKey then
             rawset(self, key, v)
          end
       end
       rawset(self, k, v)
    end
    -------------------------------------------------------

    Now :

    obj = Object()
    print(obj.w, obj.width) -- > 10, 10
    obj.w = 15
    print(obj.width) -- > 15
    
  • Posts: 2,161

    Are you sure you want the line: if Object.k then return Object.k end? Are you setting defaults as class variables?

  • edited July 2013 Posts: 277

    @Andrew_Stacey

    I think this is the last solution with a recusive system.

     
    Object = class(ObjectFather)
    Object.sugars = {width="w", height="h", x="pos.x", y="pos.y"}
     
    function Object:init()
       ObjectFather.init(self)
       self.w = 10
       self.h = 10
       self.pos = {}
       self.pos.x = 0
       self.pos.y = 0
    end
     
    ------------------- At the end of file -------------------
    function Object:__index(k)
       if Object[k] then return Object[k] end
       for sugarKey, key in pairs(Object.sugars) do
          if k == sugarKey then
             local arr = explode(".", key)
             if #arr == 1 then
                return self[key]
             else
                local result = self
                for _, v in pairs(arr) do
                   result = result[v]
                end
                return result
             end
          end
       end
    end
    function Object:__newindex(k,v)
       for sugarKey, value in pairs(Object.sugars) do
          if k == sugarKey then
             local arr = explode(".", key)
             if #arr == 1 then
                rawset(self, key, v)
             else
                local result = self
                for _, v in pairs(arr) do
                   beforeLastResult = result
                   result = result[v]
                end
                rawset(beforeLastResult, arr[#arr], v)
             end
          end
       end
       rawset(self, k, v)
    end
    -------------------------------------------------------
     
    function explode(div,str) -- credit: http://richard.warburton.it
      if (div=='') then return false end
      local pos,arr = 0,{}
      -- for each divider found
      for st,sp in function() return string.find(str,div,pos,true) end do
        table.insert(arr,string.sub(str,pos,st-1)) -- Attach chars left of current divider
        pos = sp + 1 -- Jump past current divider
      end
      table.insert(arr,string.sub(str,pos)) -- Attach chars right of last divider
      return arr
    end
  • Posts: 2,161

    Yes, I was just about to tell you that the class is the metatable for all of its instances so it's enough to define Class:__index and Class:__newindex.

  • @Andrew_Stacey, this is not that I do ?

  • Posts: 2,161

    @HyroVitalyProtago Yes, that is what you do. That was the meaning behind the "Yes, I was ...". It was to be read as "I see that you've figured this out for yourself, but I'll mention it anyway".

  • Ah, okay. Thanks !

Sign In or Register to comment.