Jump to content


Photo

[solved] Class metamethods?


  • Please log in to reply
4 replies to this topic

#1 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1272 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 11 January 2017 - 16:05

It's a bit difficult finding documentation on luabind class syntax. I have two small questions:

1) Is there some way to make these support metamethods? (__index, __newindex)

I'm trying to make an alternative to the "viewbuilder" class, adding some behaviors and stuff that doesn't exist natively. For simplicity, I want this class to revert to using the standard renoise.ViewBuilder() whenever I haven't defined my own method that "overrides" it. Will I have to revert to oldschool Lua OO to access __index and make this possible?
 
Also tried this, but it doesn't work:
 

Spoiler


2) A small question in the comment below:
 

class 'MyClass'

function MyClass:__init(value)
  self.value = value
  return self -- this line is pretty useless, right? when would it be useful?
end

Edited by joule, 12 January 2017 - 10:54.


#2 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1272 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 11 January 2017 - 18:31

This concept with traditional OO kind of works, but it won't provide the friendliest syntax..
 


local jb = { }
jb.mt = { __call = function() return jb:new() end } -- jb() instead of jb:new()
setmetatable(jb, jb.mt)

function jb:new()
  local o = { }
  self.vb = renoise.ViewBuilder()
  setmetatable(o, self)
  self.__index = self
  return o
end

-- wrap all standard vb classes like this :(
function jb:row(args)
  return self.vb:row(args)
end

-- for the sake of sanity, these kind of methods could very well be externalized to their separate classes
-- bugger we'll then have to change all values with set() calls :(
function jb:my_element(args)
  local vb = self.vb
  local my_element = vb:row {
    vb:text {
      text = args.label },
    vb:minislider { min = args.min,
                    max = args.max,
                    value = args.value,
                  }
  }
  return my_element
end

local a = jb()
local test_content = a:row {
  a:my_element { min = 0, max = 100, value = 40, label = "slider label" }
}

local dialog = renoise.app():show_custom_dialog("test", test_content)

Edited by joule, 11 January 2017 - 18:33.


#3 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1272 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 12 January 2017 - 11:01

It seems only the __call method is available in classes.
 
Anyhow, I think I managed to make a transparent ViewBuilder wrapper like this. It's pretty nifty having the possibility of adding your own "viewbuilder classes" (combinations of stuff, or additional behaviors to the native classes), while maintaining a transparent syntax to the standard viewbuilder.

class 'NewBuilder'

NewBuilder.subclasses = { "bitmap", "button", "checkbox", "chooser", "column",
  "horizontal_aligner", "minislider", "multiline_text", "multiline_textfield",
    "popup", "rotary", "row", "slider", "space", "switch", "text", "textfield",
    "value", "valuebox", "valuefield", "vertical_aligner", "xypad", -- "slider_labeled"
  }

function NewBuilder:__init()
  self.vb = renoise.ViewBuilder()
  for _, sub_class in ipairs(self.subclasses) do
    NewBuilder[sub_class] = function(self, properties)
      -- override or return your own "viewbuilder class" here
      -- if sub_class == "slider_labeled" then
      --   print("creating a slider with attached label")
      --   return your object
      -- end
      return self.vb[sub_class](self.vb, properties)
    end
  end
end

NewBuilder.views = property(
  function(obj) return obj.vb.views end,
  function(obj, val) obj.vb.views = val end
)

--[[ quick test
local nb = NewBuilder() 
local my_row = nb:row { id = "test" }
oprint(nb)
rprint(nb.views) 
]]



#4 danoise

danoise

    Probably More God or Borg Than Human Member

  • Renoise Team
  • PipPipPipPipPipPipPipPipPipPipPipPipPipPipPip
  • 6001 posts
  • Gender:Male
  • Interests:wildlife + urban trekking

Posted 12 January 2017 - 13:29

It seems only the __call method is available in classes.

 

I was hesitant to give you a reply, as we are in largely uncharted territory here.

But __index  - yes, I think luabind is using that for it's own getter/setter interface.

 

In my experience, comparison and toString methods are working though -- especially the comparison could be interesting here? 

 

In your code, the missing _index shouldn't be much of a problem, should it? You're the "gatekeeper" of your own code, so you know what methods to expect, etc.

Otherwise cLib.reflection.lua has a few (pretty hacky) ways of scanning object properties :)


Tracking with Stuff. API wishlist | Soundcloud


#5 joule

joule

    Guruh Motha Fakka is Levitating and Knows Everything About Renoise Member

  • Normal Members
  • PipPipPipPipPipPipPipPipPipPipPipPipPip
  • 1272 posts
  • Gender:Not Telling
  • Location:Sweden
  • Interests:music, philosophy, engineering

Posted 12 January 2017 - 17:51

Well. What I'm really trying to do is create a class that is (close to) 100% compatible with how viewbuilder is used. An intermediate bridge, where custom classes can be added, so to speak. I want to use it as a general replacement for the ViewBuilder class, being "backwards" compatible syntax wise.

 

I concluded it's probably not possible. Simply put, I can't get it to support all of the below three syntaxes. But it's good enough so I'll leave it there.

-- Example 1: works just fine

local content = nb:row {
  nb:my_own_slider { label = "Volume", min = 0, max = 100 }
}
-- Example 2: doesn't work, since "element" must be a native vb object to support the syntax in example 1.

local element = vb:my_own_slider { label = "Volume", min = 0, max = 100 }
element.label = "Panning" -- not possible, of course.
-- Example 3: works thanks to building a custom "views" table. (could perhaps add a working add_child and remove_child even)

local element = nb:row {
  my_own_slider { id = "my_slider", label = "Volume" }
}
nb.views.my_slider.label = "Panning"

Edited by joule, 12 January 2017 - 17:53.