[sharing is fun] OO Objects for Max
Hello all,
As some of you may remember, there was a long discussion where we tried to apply object oriented (OO) principles to Max: https://cycling74.com/forums/index.php?t=msg&th=25272. In the end, John Pitcairn and I teamed up to address this issue.
You can now find the first official release of the OO Objects for Max on my user page:
We developed two simple but powerful externals, oo.method and oo.call, that enable you to apply OO techniques within Max. This vastly improves the manageability of complex Max patches.
The objects are Mac-only for now. So far they have been tested by a select group of experienced Max users but we are interested in more user experiences before we start the development for Windows. Max 5 versions will come as soon as Cycling '74 releases the Max 5 API.
All feedback is appreciated!
Cheers,
Mattijs
OMFG! This is great. Thanks Mattijs and John for this wonderful addition! Now, just have to wait for the Max5 version. I must admit, this will keep me attached to Max4 a little longer than anticipated ;)
Zachary
Absolutely fantastic, thank you very much.
Do you have any experience on performance, e.g. how does it compare to CPU utilisation of a ftm based system calling functions or methods stored in matrices and dictionaries?
On 12 Jun 2008, at 14:08, Sebastian Lexer wrote:
> Absolutely fantastic, thank you very much.
Agreed - it's quite sweet.
Just curious: is it thread-safe?
-- N.
Nick Rothwell / Cassiel.com Limited
www.cassiel.com
www.myspace.com/cassieldotcom
www.last.fm/music/cassiel
www.reverbnation.com/cassiel
www.linkedin.com/in/cassiel
www.loadbang.net
Thanks, guys.
Sebastian, we didn't compare directly to ftm based systems, but we did compare with send/receive/forward, pvar and the pattr family, as you can see in section 17 of the help patch. The oo objects are very fast, i.e. faster than pattr and pvar and only slightly slower than send/receive (which of course don't support all the extra functionality).
Nick, yes, they are thread-safe. We're not fooling with threads at all, we use the native event handling system. Although on load, some interesting things are going on, see section 15 of the help file: "loadbang limitations for oo objects".
Mattijs
I would love to try this. Is there a Windows version?
Quote: Mattijs wrote on Thu, 12 June 2008 04:58
----------------------------------------------------
> Max 5 versions will come as soon as Cycling '74 releases the Max 5 API.
>
I'm using Max 5 almost exclusively now so I'm really looking forward to the Max 5 version. I hope you and John get to beta test the Max 5 SDK. That would be a win-win situation for everyone.
It will be very interesting to see how people use these objects: which OO patterns are effective in Max and what do they look like in patch form? So please share (because it's fun!) and I will do the same :)
Quote: nick rothwell / cassiel wrote on Fri, 13 June 2008 01:20
----------------------------------------------------
> Just curious: is it thread-safe?
It should be thread-safe, if C74's internal hashtab and linklist handling is threadsafe. As Mattijs says, we don't use any internal threading of our own. We've tested on single and multiprocessor PPC and Intel Mac systems, overdrive on/off, and this release seems very stable. I'd certainly be interested in any crash results that indicate it isn't thread-safe.
these look very interesting. now that i'm beginning to work on a large complex patch i'm interested in learning more about these objects...
although i don't have a programming background, i have a general idea about what oop is. enough to see how it can simplify some patch building routines.
the problem i have now is that i've looked at the objects and the helps files, but i can't quite make the next step to use these objects. can someone post an example patch, using these in context? i know that would help me a great deal.
thanks
david
YOU BASTARD! :-)
totally have a copy of something like this running on my computer!
Thought I was a genius! I had nearly all of Javascript in max form.
Also, it operated like jitter where you could pass "max_object id" messages to other methods so you could operate on objects
Hi David,
as Adam Murray said, there are a lot of different ways in which you can use these objects, depending on the situation. In text-based languages people have defined a series of recurring programming patterns and I am certainly curious how those will relate to max.
On my user page you will also find the MPC Studio patch. This is a complex patch that would have been impossible to create as modular and clean as it is now without the oo objects. Feel free to use it as an example, but as it is with big patches, I can imagine it takes some time to plough through all the subpatchers and recognize the structure I used.
Adam, we definitely have to document the patterns you came up with during the beta tests. We could exchange some of them in this thread, I guess? That way others will have the opportunity to chime in. Maybe after a while we'll be able to bundle the examples and provide them on the user page together with the OO Objects.
Mattijs
Quote: david@5of4.com wrote on Thu, 12 June 2008 23:27
----------------------------------------------------
> these look very interesting. now that i'm beginning to work on a large complex patch i'm interested in learning more about these objects...
>
> although i don't have a programming background, i have a general idea about what oop is. enough to see how it can simplify some patch building routines.
>
> the problem i have now is that i've looked at the objects and the helps files, but i can't quite make the next step to use these objects. can someone post an example patch, using these in context? i know that would help me a great deal.
>
> thanks
> david
>
>
----------------------------------------------------
Quote: Anthony Palomba wrote on Thu, 12 June 2008 18:35
----------------------------------------------------
> I would love to try this. Is there a Windows version?
----------------------------------------------------
As I said in the initial post:
The objects are Mac-only for now. So far they have been tested by a select group of experienced Max users but we are interested in more user experiences before we start the development for Windows. Max 5 versions will come as soon as Cycling '74 releases the Max 5 API.
Mattijs
Haha! No way! I'm curious to see your system though. Do you have a preview of any kind that you could send me..?
Mattijs
Quote: Matthew Aidekman wrote on Thu, 12 June 2008 23:33
----------------------------------------------------
> YOU BASTARD! :-)
>
> totally have a copy of something like this running on my computer!
>
> Thought I was a genius! I had nearly all of Javascript in max form.
>
>
> Also, it operated like jitter where you could pass "max_object id" messages to other methods so you could operate on objects
>
>
----------------------------------------------------
The license makes this useless for me.
bt
Quote: barry threw wrote on Fri, 13 June 2008 10:47
----------------------------------------------------
> The license makes this useless for me.
What's the problem?
Quote: Matthew Aidekman wrote on Fri, 13 June 2008 09:33
----------------------------------------------------
> totally have a copy of something like this running on my
> computer! Thought I was a genius! I had nearly all of
> Javascript in max form.
Wow. As compiled max objects, java objects, js objects, or as abstractions?
We wound up ruling out js and abstractions for doing the heavy lifting due to abysmal performance and/or excessive load-time overhead for large patches. Switching to C speeded things up by at least an order of magnitude, but also slowed development time by a corresponding amount :-
> Adam, we definitely have to document the patterns you came up with during the beta tests. We could exchange some of them in this thread, I guess? That way others will have the opportunity to chime in. Maybe after a while we'll be able to bundle the examples and provide them on the user page together with the OO Objects.
Sure, that sounds good. I will probably host any of my patches on my website too. I need a bit of time to clean them up, maybe add some comments. I will post here in the not too distant future.
Quote: barry threw wrote on Fri, 13 June 2008 10:47
----------------------------------------------------
> The license makes this useless for me.
seems like a pretty flexible license to me...
I checked, its broken right now. It was like 2 years ago. I tried programming it from scratch three times. I had it kind of half working. Then called max "art that kills you" I was so touched by those words I decided to drop ir (at least this project) from my to do list
I included the very very first max based version
I'm going to rant here because this will be the last place this project lives.
this is how the last version went:
oom.instnace
//loaded a max patch with the code for the object inside.
oom.method
//where you defined a method inside your instance code. you could also instantiate it outside your oom_object patcher and it would forward the arguments to the corrisponding oom.method inside the oom_object patcher, then return the value from oom.return
oom.instancevalue
//like the v object in max but oom kept track of it. you could also instantiate it outside your oom_object patcher and it would refer to the correct value
oom.return
//where you sent the results of your method.
that should read: Then a friend called max...
Non-commercial.
bt
On Jun 12, 2008, at 5:03 PM, John Pitcairn wrote:
>
> Quote: barry threw wrote on Fri, 13 June 2008 10:47
> ----------------------------------------------------
>> The license makes this useless for me.
>
> What's the problem?
>
Quote: barry threw wrote on Fri, 13 June 2008 09:10
----------------------------------------------------
> Non-commercial.
>
> bt
>
No, not non-commercial. "Don't include the objects in commercial distributions without permission of the authors".
The thing is, we'd like to know about every commercial project that these objects get involved in up to a level where they need to be re-distributed.
I previously had a situation where the DAW Fruityloops (now called FL Studio) made a Jeskola Buzz wrapper, and included Buzz machines, some of which I made, in their main distribution without asking or even notifying the authors, selling copy after copy. And they must have made quite a bit of money out of that.
Mattijs
Re: OO patterns in Max
First up: the strategy pattern
Check out the attached zip. If the forum swallowed it, you can also get it here:
http://compusition.com/code/max/oo/strategy.pattern.zip
This pattern is about swappable behaviors. It can be used to construct generic subpatchers that do some sort of processing not defined ahead of time. A UI can be built to change the behavior on the fly.
The important thing to understand here is I'm passing around addresses to the oo.methods and deferring execution until the oo.call gets triggered by MIDI input.
It's worth noting that multiple transformer abstractions can be hooked up to the same transformation strategy. You can set two to "octave_up" in this patch. And you can open this patch multiple times without the kind of interference problems you'd have with send/receive.
In a structured OO language like Java, we'd be using an interface to make a well-defined the strategy. There's no way to enforce an interface here so it's up to the patch maker to ensure they all work the same way. My "interface" is to send the message [pitch velocity duration callback_address] and expect to receive [pitch velocity duration]. The callback stuff is needed when delays are involved (more info in the oo help file).
Barry Threw schrieb:
> Non-commercial.
So just ask for a commercial license, it doesn't mean you can't use it,
it only means you don't know the commercial license (yet)...
And it's exactly what is written there, they want you to ask first...
It is probably to prevent Microsoft to abuse it, make billions of
dollars with it but don't participate in the cost of the development.
I think its fair. But I'd recommend to Mattjis and John to look into
cc-licenses, there is a non-commercial variant, which is pretty robust
and checked by real lawyers...
Stefan
--
Stefan Tiedje------------x-------
--_____-----------|--------------
--(_|_ ----|-----|-----()-------
-- _|_)----|-----()--------------
----------()--------www.ccmix.com
Quote: Stefan Tiedje wrote on Fri, 13 June 2008 12:48
----------------------------------------------------
> But I'd recommend to Mattjis
That would be MattIJs. I remember you corrected me once because I wrote 'Stephan', now we're even ;)
> and John to look into
> cc-licenses, there is a non-commercial variant, which is pretty robust
> and checked by real lawyers...
I looked a bit into CC, but the first things I stumbled upon were all very much like GNU, which is all about open source, which these objects aren't. If you or someone else can find a CC license that has the same content as the current home-made one, I'd be happy to replace it.
Mattijs
Quote: Adam Murray wrote on Fri, 13 June 2008 09:46
----------------------------------------------------
> Re: OO patterns in Max
> First up: the strategy pattern
>
Wow, impressive! Clean and comprehensible, and a nice case too!
A thought: if I adopted this patch as a pattern I think I'd rather put the transformations in subpatchers instead of abstractions. 1) because it would be easier to debug, the idea of this pattern being of course that the transformations can become pretty complex, 2) because abstractions are typically used for functionality you need multiple copies of. One of the big strengths of your example is that there only has to be one copy of every transformation, while they are called in multiple locations (saving a lot of load time if the same transformations are used everywhere throughout a huge patch).
Also, but you have probably noticed this, the callback system is only necessary if a transformation is switched before the delay of the previous one ends. oo.method remembers its return address until it is called by a new oo.call. But in this case, with the midi notes, I can imagine a lot of fun with wild transformation switches at non-obvious moments in the note stream.
Mattijs
Quote: Mattijs wrote on Fri, 13 June 2008 09:12
----------------------------------------------------
> A thought: if I adopted this patch as a pattern I think I'd rather put the transformations in subpatchers instead of abstractions. 1) because it would be easier to debug, the idea of this pattern being of course that the transformations can become pretty complex,
Sure, that makes sense. And you can patch up some new transformations on the fly and hook them up to the rest of the patch without changing anything else, since there's no cable connections.
> 2) because abstractions are typically used for functionality you need multiple copies of.
I did it this way because I parameterized those abstractions - for example, the transpose abstraction needs to know how many semitones to transpose.
But I realized a much better way: When setting the transformation, also pass any parameters needed by the transformation. So instead of calling "transformer.set &octave_up" you call "transformer.set &transpose 12". That makes this technique even more flexible and completely removes redundancy in the patch. And seems like a good way to simulate a closure, one of the features that makes high level languages so powerful IMO.
Here's a simplified example:
Nice example. This made me "get it" a little more than the examples
that came with.
This is a nice way to work.
bt
Quote: barry threw wrote on Fri, 13 June 2008 20:52
----------------------------------------------------
> Nice example. This made me "get it" a little more than the examples
> that came with.
>
> This is a nice way to work.
>
> bt
>
>
>
----------------------------------------------------
And now an MVC example, Adam! ;)
Yes, I agree that examples like this are essential to understanding the oo objects, especially for maxers that are not familiar with oo programming.
Mattijs
Quote: Mattijs wrote on Fri, 13 June 2008 15:29
----------------------------------------------------
>
> And now an MVC example, Adam! ;)
>
I know what patch you want to see :) But you may not recognize it, it got seriously revamped.
This is the observer pattern. Use it to register "event listeners" that will be notified every time some state changes.
In bigger patches it's probably useful to put a pattr inside the "subject" object to store the state and get all the benefits of using pattrstorage (presets, saving/loading to a file, etc). Then you'd probably want a GUI to manage the pattr. But that would require two way communication between the GUI object and pattr, and this pattern only goes one way (from subject to observer). I played around with using oo.objects to go both ways, but I still feel that using [pattr @bindto] is the most straightforward (although slightly less efficient) way to do this. But that's a conversation for another day.
I have a question. The oo help file shows examples of calling methods relative to the current patch. I can go down (child.method) or up (parent.method or .method). Can I also reference objects absolutely from the top scope?
Observer pattern patch:
Quote: Adam Murray wrote on Sat, 14 June 2008 06:04
----------------------------------------------------
>
> This is the observer pattern. Use it to register "event listeners" that will be notified every time some state changes.
>
Again a great example! It has definitely evolved since the last time I saw it, and became even easier to understand.
> In bigger patches it's probably useful to put a pattr inside the "subject" object to store the state and get all the benefits of using pattrstorage (presets, saving/loading to a file, etc). Then you'd probably want a GUI to manage the pattr. But that would require two way communication between the GUI object and pattr, and this pattern only goes one way (from subject to observer). I played around with using oo.objects to go both ways, but I still feel that using [pattr @bindto] is the most straightforward (although slightly less efficient) way to do this. But that's a conversation for another day.
I have been working with a system that avoids pattrstorage but uses a simple coll to store presets. It also illustrates the max equivalent of how I do this two-way communication in my object oriented Java applications. I'll see if I can post an example soon.
>
> I have a question. The oo help file shows examples of calling methods relative to the current patch. I can go down (child.method) or up (parent.method or .method). Can I also reference objects absolutely from the top scope?
No, you can't. If that would be possible, the whole thing would lose its local aspect. But I'm curious where you would need that. The supposed way to do this is to pass a reference from the top scope to the scopes where you need them.
Although, there is one thing I have been thinking about. There is no way to store that location in a variable (for example 'main') and calling it directly, like [oo.call main.updateGui]. Maybe that is a feature we could add in the future.
Mattijs
Quote: Matthew Aidekman wrote on Fri, 13 June 2008 06:40
----------------------------------------------------
> I checked, its broken right now. It was like 2 years ago. I tried programming it from scratch three times. I had it kind of half working. Then called max "art that kills you" I was so touched by those words I decided to drop ir (at least this project) from my to do list
>
>
> I included the very very first max based version
>
>
> I'm going to rant here because this will be the last place this project lives.
>
Matthew, it looks like you have been going through very much the same process as we did. I assume you also found out that using abstractions is not the way to go due to excessive load times. We then turned to javascript, but it wasn't fast and stable enough, so we ended up writing our own externals.
I can imagine that you have some interesting and useful feedback for us, based on your own experiences. I would be happy to hear it.
Mattijs
Mattijs Kneppers schrieb:
> That would be MattIJs. I remember you corrected me once because I
> wrote 'Stephan', now we're even ;)
I see, I have to get to Ooraanje visit you and learn some dutch...
> I looked a bit into CC, but the first things I stumbled upon were all
> very much like GNU, which is all about open source, which these
> objects aren't. If you or someone else can find a CC license that has
> the same content as the current home-made one, I'd be happy to
> replace it.
It has nothing to do with open source, as the license is going with the
actual copy you distribute, if you don't give away a source, there is no
license for the source. You can also choose a license which prevents
changes if you want to...
Stefan
--
Stefan Tiedje------------x-------
--_____-----------|--------------
--(_|_ ----|-----|-----()-------
-- _|_)----|-----()--------------
----------()--------www.ccmix.com
Quote: Stefan Tiedje wrote on Sun, 15 June 2008 18:09
----------------------------------------------------
> Mattijs Kneppers schrieb:
> > That would be MattIJs. I remember you corrected me once because I
> > wrote 'Stephan', now we're even ;)
>
> I see, I have to get to Ooraanje visit you and learn some dutch...
You're always welcome, the beer is on me. Although, now with Oranje beating Italy and France in the European Soccer Championship you might want to wait a bit with coming this way. All the bars are orange.
>
> > I looked a bit into CC, but the first things I stumbled upon were all
> > very much like GNU, which is all about open source, which these
> > objects aren't. If you or someone else can find a CC license that has
> > the same content as the current home-made one, I'd be happy to
> > replace it.
>
> It has nothing to do with open source, as the license is going with the
> actual copy you distribute, if you don't give away a source, there is no
> license for the source. You can also choose a license which prevents
> changes if you want to...
Hm, I tried that, but didn't really get somewhere. On creativecommons.org, where you can choose a license, it starts with the absence of 'software' as a 'format of your work'. When I choose Interactive instead, and No for 'Allow modifications of your work?', in the final license I get "No Derivative Works. You may not alter, transform, or build upon this work.", which is not applicable. There is also a different link to Software, to the right, but when I click that I get only open source stuff, pointing me to GNU GPL.
>
> Stefan
>
> --
> Stefan Tiedje------------x-------
> --_____-----------|--------------
> --(_|_ ----|-----|-----()-------
> -- _|_)----|-----()--------------
> ----------()--------www.ccmix.com
>
>
>
----------------------------------------------------
Quote: Mattijs wrote on Sun, 15 June 2008 03:40
----------------------------------------------------
>
> I have been working with a system that avoids pattrstorage but uses a simple coll to store presets. It also illustrates the max equivalent of how I do this two-way communication in my object oriented Java applications. I'll see if I can post an example soon.
I'd like to see it. And I have to spend more time looking at your MPC Studio patch.
I thought of pattr when you brought up the topic of model-view-controller, because pattr was the way to go before the oo objects. It has some very nice features that might be a pain to recreate (like interpolation). But it also has some downsides the oo objects address. In a given patch I might use pattr, or oo, or a combination of the two. I haven't figured out my preferences yet.
> > Can I also reference objects absolutely from the top scope?
>
> No, you can't. If that would be possible, the whole thing would lose its local aspect. But I'm curious where you would need that. The supposed way to do this is to pass a reference from the top scope to the scopes where you need them.
>
> Although, there is one thing I have been thinking about. There is no way to store that location in a variable (for example 'main') and calling it directly, like [oo.call main.updateGui]. Maybe that is a feature we could add in the future.
I'm not sure I follow your 'main' example but that might be what I am looking for.
This is an issue with implementing the singleton pattern. Say I want some global object called "service" available everywhere so I put it in the topmost scope. And I'm writing abstractions that are used in various scopes throughout my patch. I need to call methods in "service" without knowing how far up it is.
Quote: Adam Murray wrote on Fri, 13 June 2008 19:46
----------------------------------------------------
> In a structured OO language like Java, we'd be using an
> interface to make a well-defined the strategy. There's no way
> to enforce an interface here so it's up to the patch maker to
> ensure they all work the same way.
Yeah. We haven't really considered things right down to the level of specifying interfaces, abstract/virtual methods or even argument/return typing yet, but we have had some preliminary discussions on formalizing the way inheritance should be handled, and interfaces would follow from that.
Nice example.
> This is the observer pattern. Use it to register "event
> listeners" that will be notified every time some state
> changes.
This has certainly been worked on since it was first prototyped in the original discussion thread!
We will likely be adding notifier/listener functionality to the core objects, possibly quite soon as the code already exists, it's just the specific manifestation as objects that needs to be worked out.
The end result will be that you get one-to-many messaging functionality (like send/receive) which is currently missing from the core OO objects unless you build it as you have done.
Quote: Adam Murray wrote on Sat, 14 June 2008 16:04
----------------------------------------------------
> I have a question. The oo help file shows examples of calling
> methods relative to the current patch. I can go down
> (child.method) or up (parent.method or .method). Can I also
> reference objects absolutely from the top scope?
Mattijs has explained why we decided against providing an explicit "top" specifier, but you can get a path to (or reference for) the top scope at any time, something like:
But it might be worthwhile in future if we add this as a native patcher method similar to "getmembers"?
Just bear in mind that in a highly dynamic application, you might get loaded in as a component of something else, so "top" may change. Storing it in a variable as above is therefore setting up for potential trouble.
Note this example exposes a bug in the oo.call errors setting - it shouldn't throw an error here, but does. Will fix for next release.
Quote: Mattijs wrote on Sun, 15 June 2008 22:40
----------------------------------------------------
> There is no way to store that location in a variable (for example
> 'main') and calling it directly, like [oo.call main.updateGui].
> Maybe that is a feature we could add in the future.
Do you recall the discussion we had about the hypothetical "oo.alias" or "oo.ref" (formerly oo.var) which would effectively be a pointer to another member? That's exactly how you'd use it.
Find reference to top (or any) member "parent.parent.(etc)".
Pass reference to local oo.alias "main".
Call "main.updateGUI".
Though the caveats against storing a reference to the presumed top scope in a dynamic system would still apply.
oo.alias would be very useful when passing references in patcher args via constructor methods, or in evaluated oo.call input.
Quote: johnpitcairn wrote on Sun, 15 June 2008 15:42
----------------------------------------------------
> Quote: Adam Murray wrote on Fri, 13 June 2008 19:46
> ----------------------------------------------------
> > In a structured OO language like Java, we'd be using an
> > interface to make a well-defined the strategy. There's no way
> > to enforce an interface here so it's up to the patch maker to
> > ensure they all work the same way.
>
> Yeah. We haven't really considered things right down to the level of specifying interfaces, abstract/virtual methods or even argument/return typing yet, but we have had some preliminary discussions on formalizing the way inheritance should be handled, and interfaces would follow from that.
>
I wasn't criticizing the lack of interface. These days I prefer using highly dynamic scripting languages for most of my programming, because it's easier to extend functionality and sometimes there are pleasant surprises in terms of emergent functionality (unplanned features) when you aren't locked into well-defined interfaces.
So I don't think I'd want interfaces to be well-defined in Max. For me, it's all about the open-ended message passing and fast prototyping...
But interested to see whatever you come up with.
To make this discussion a little more concrete, I'm trying to generalize that observer pattern to a larger patch. I want a single "event manager" object. Instead of attaching event listeners to specific "subject" objects, I'll subscribe to notifications for specific event types. So instead of using a [bag] like in my observer patch, there would be a [coll] that stores entries like: "event_type callback_1 ... callback_n". All events pass through the the global event manager, which triggers the appropriate callbacks.
For example, if I'm playing a MIDI keyboard, there might be a chord detector that sends "chord" events (like "chord major", "chord minor"). Other parts of my patch would subscribe to "chord" events, and then whenever anything generates a chord event, the listeners would receive messages like "major" or "minor". This is a many-to-many notification system (instead of one-to-many like my observer patch) and it could be a great way to build very flexible generative music patches.
If I was doing something like this in another programming language, I would have a singleton class with static methods for registering event listeners and generating events. I don't see a good way to translate that into the oo objects yet. The complication is I want to drop in abstractions that have initialization logic like:
1. find the event manager
2a. register as a listener for some event type
or
2b. generate events
I want to drop the abstraction in and have it initialize itself, because I might be dropping in abstractions on the fly. That's why I was asking how to find the top scope, because I can put the event manager there and anything can find it. I understand your warnings - I'll just make sure the event manager is always at the top. If you have any other ideas on how to do this, I'm all ears.
BTW thanks for sharing that patch to find the top scope.
Quote: johnpitcairn wrote on Sun, 15 June 2008 16:24
----------------------------------------------------
> Quote: Mattijs wrote on Sun, 15 June 2008 22:40
> ----------------------------------------------------
> > There is no way to store that location in a variable (for example
> > 'main') and calling it directly, like [oo.call main.updateGui].
> > Maybe that is a feature we could add in the future.
>
> Do you recall the discussion we had about the hypothetical "oo.alias" or "oo.ref" (formerly oo.var) which would effectively be a pointer to another member? That's exactly how you'd use it.
>
> Find reference to top (or any) member "parent.parent.(etc)".
> Pass reference to local oo.alias "main".
> Call "main.updateGUI".
>
> Though the caveats against storing a reference to the presumed top scope in a dynamic system would still apply.
>
> oo.alias would be very useful when passing references in patcher args via constructor methods, or in evaluated oo.call input.
----------------------------------------------------
Quote: Adam Murray wrote on Tue, 17 June 2008 09:31
----------------------------------------------------
> If I was doing something like this in another programming
> language, I would have a singleton class with static methods
> for registering event listeners and generating events. I don't
> see a good way to translate that into the oo objects yet.
I don't know if static members will be especially do-able in this environment, but we'll continue to think about that, they'd be pretty handy.
> The complication is I want to drop in abstractions that have
> initialization logic like:
> 1. find the event manager
> 2a. register as a listener for some event type
> or
> 2b. generate events
Thinking ...
First, rather than just blindly finding "top", it might be safer to try to call an event manager "discovery" method that returns a known magic value (maybe use the entry method?) in each parent, recursing up until you find it, ie:
.EventManager
..EventManager
...etc
Then:
2a: EventManager.attachListener as you've prototyped, or
2b: Pass the generated events to a handler method, EventManager.handleEvent.
You'd get a reference to this method returned from something like EventManager.getHandler, and use it to set a call in the generator.
You could pass the event type with each event generated for a generic handler, or use a separate handler method for each event type (perhaps passing the type in to getHandler).
Workable?
Quote: johnpitcairn wrote on Mon, 16 June 2008 15:42
----------------------------------------------------
>
> rather than just blindly finding "top", it might be safer to try to call an event manager "discovery" method that returns a known magic value (maybe use the entry method?) in each parent, recursing up until you find it, ie:
>
> .EventManager
> ..EventManager
> ...etc
>
[snip]
>
> Workable?
>
----------------------------------------------------
Yeah, I think so. Seems pretty reasonable.
I'll let you know how it goes. Might not have time to try this right away though.
Mattijs Kneppers schrieb:
> Hm, I tried that, but didn't really get somewhere. On
> creativecommons.org, where you can choose a license, it starts with
> the absence of 'software' as a 'format of your work'. When I choose
> Interactive instead, and No for 'Allow modifications of your work?',
> in the final license I get "No Derivative Works. You may not alter,
> transform, or build upon this work.", which is not applicable. There
> is also a different link to Software, to the right, but when I click
> that I get only open source stuff, pointing me to GNU GPL.
I just tried, and it'll give me BY-NC-ND...
Stefan
--
Stefan Tiedje------------x-------
--_____-----------|--------------
--(_|_ ----|-----|-----()-------
-- _|_)----|-----()--------------
----------()--------www.ccmix.com
Quote: Adam Murray wrote on Sun, 15 June 2008 20:39
----------------------------------------------------
> Quote: Mattijs wrote on Sun, 15 June 2008 03:40
> ----------------------------------------------------
> >
> > I have been working with a system that avoids pattrstorage but uses a simple coll to store presets. It also illustrates the max equivalent of how I do this two-way communication in my object oriented Java applications. I'll see if I can post an example soon.
>
> I'd like to see it.
I attached a simple patch that shows my current idea of a model-view-controller setup, including an easy way to store presets in a coll. It also has multiple views of the same data, and addresses the two-way interface (the same data can be adjusted in multiple locations). Not as polished as your examples, Adam, but hopefully still understandable.
I didn't use an observer system for the interface, although that would be a useful add-on when the patch gets more complex.
Mattijs
Quote: Stefan Tiedje wrote on Tue, 17 June 2008 08:51
----------------------------------------------------
> Mattijs Kneppers schrieb:
> > Hm, I tried that, but didn't really get somewhere. On
> > creativecommons.org, where you can choose a license, it starts with
> > the absence of 'software' as a 'format of your work'. When I choose
> > Interactive instead, and No for 'Allow modifications of your work?',
> > in the final license I get "No Derivative Works. You may not alter,
> > transform, or build upon this work.", which is not applicable. There
> > is also a different link to Software, to the right, but when I click
> > that I get only open source stuff, pointing me to GNU GPL.
>
> I just tried, and it'll give me BY-NC-ND...
>
> Stefan
>
What exactly did you just try? Clicking the separate software link or filling out the form with Interaction as a 'format of your work'?
Mattijs
So any news in Max 5 now SDK is out?
Mattijs and I have both been really busy for a few months, but I'm working on it now. No great problems, just a couple of things remain to update for Max 5 (as per my posts in the dev forum if you're interested). I'm hoping for a release later this month, stay tuned.
Quote: johnpitcairn wrote on Sat, 10 January 2009 23:41
----------------------------------------------------
> Mattijs and I have both been really busy for a few months, but I'm working on it now. No great problems, just a couple of things remain to update for Max 5 (as per my posts in the dev forum if you're interested). I'm hoping for a release later this month, stay tuned.
----------------------------------------------------
Seconded.
Mattijs
I'm looking forward to the updated oo objects. Thanks for your work on this, great initiative.
thank you for the continued work on the OO objects.
they are a very valuable addition to max.
regards,
klaas-jan
Any more news on this?
Would be really good for a project I'm working on now.
James.
James Drake wrote on Mon, 23 March 2009 15:43Any more news on this?
Would be really good for a project I'm working on now.
James.
Hi James,
Everything works except for edge cases that are not especially limiting. Although we do prefer to get rid of all the issues we know about before starting a beta test, I could send you a personal copy of the current distribution.
So if you feel like testing the current version please mail me off-list and I'll send you a zip.
Best,
Mattijs
@Adam Murray or Mattijs (or anyone else in fact)
Looking through the examples posted so far has been very helpful, thanks for everyone's work so far on this. There are still some things i'm not fully grasping that you might be able to shed some light on
Firstly: In (eg) Java, we might have a Class and instantiate objects from it. Using OO objects, how should i be imagining the equivalent? do we have one scoped patcher which we somehow create instances from at runtime? or is there no direct equivalent of a Class, and instances are represented by separate patchers that exist in the saved patch?
Secondly: an instance (i'll call it channel_group) might need to keep a list of references to other objects of a certain kind (channels), which it can use to call (currently unknown) methods on in the future. The group might have a public interface that allows channels to be added and removed from its internal list. The observer example seems to give some clues in this direction but the penny hasn't dropped yet for me. Is there already an example around of this kind of arrangement?
Quote:In (eg) Java, we might have a Class and instantiate objects from it. Using OO objects, how should i be imagining the equivalent?
Class definition = abstraction (patcher saved to disk).
Class instance = abstraction instantiated in patcher with @oo attribute
A (non-abstraction) subpatcher with an @oo attribute can be thought of as a singleton class instance with an implied class definition.
Quote:Secondly: an instance (i'll call it channel_group) might need to keep a list of references to other objects ... The observer example seems to give some clues in this direction but the penny hasn't dropped yet for me.
Essentially you'd define a class based on some object that can maintain a list of integers, giving it some public access oo.methods - add, remove, clear, dump, etc. Instantiate that inside your channel_group instance.
Bag, funbuff, table, coll, zl etc are all good candidate objects, depending on exactly what you need to store and how you need to access it.
Note that it needn't be a separate class, you can just use the object itself cabled inside your instance - wrapping the access to it with oo.methods if you want a consistent interface (ie you might change the object used in future).
bitbutter wrote on Mon, 30 March 2009 15:49do we have one scoped patcher which we somehow create instances from at runtime?
In addition to what John said: the oo objects do not provide a way to create instances of objects dynamically during 'runtime'. That is still done with Max, by hand, with scripting or using a poly~ object.
The oo objects do support auto-naming these dynamically created instances, see the help patch for more information about that.
Mattijs
Thanks for the clarifications, that makes sense.
Quote:Essentially you'd define a class based on some object that can maintain a list of integers, giving it some public access oo.methods - add, remove, clear, dump, etc. Instantiate that inside your channel_group instance.
Inside whichever storage object got used, would it be the numerical id's of the 'this' method of the channel instances that would get stored?
If i understood that correctly, then i understand how channel_group can call the 'this' method of its channel objects, but is there then a way for the channel_group object to (for instance) call the 'print_something' method on each of the objects represented in its store object instead?
Thanks again for your answers and apologies if these questions are very basic.
bitbutter wrote on Tue, 31 March 2009 10:40but is there then a way for the channel_group object to (for instance) call the 'print_something' method on each of the objects represented in its store object instead?
There is. Input the stored integer reference to 'this' of the destination object in the right inlet of oo.call, oo.call will translate it to the destination name. Then use [sprintf %s.print_something] to append the actual destination method, input the result in the right inlet of another oo.call, then use its left inlet to send data to your destined method.
Hope that helps, but if this is not clear send me a (preferably simplified) patch with your current state of affairs and I'll see if I can implement the solution for you.
Mattijs
Ahh i see, Thanks. I made this intermediate patch to help get an understanding of the conversion/deconversion process that would be involved in storing references to objects (which you could then call arbitrary methods on at a later time). Great stuff!
[patch removed]
bitbutter wrote on Tue, 31 March 2009 16:24I made this intermediate patch to help get an understanding of the conversion/deconversion process that would be involved in storing references to objects (which you could then call arbitrary methods on at a later time). Great stuff!
Thanks, and yes, that example is correct. But please let's take exchanging Max 5 patches off-list as long as we haven't released the oo objects for Max 5 yet.
No problem. Patch removed.
Mattijs wrote on Tue, 31 March 2009 23:51Input the stored integer reference to 'this' of the destination object in the right inlet of oo.call, oo.call will translate it to the destination name. Then use [sprintf %s.print_something] to append the actual destination method
Another way to handle it would be to do your own message despatch from the channel object's "this" method, based on an appended method name. zl ecils to get the method name and cable it to oo.call's right inlet, cabling the rest of the message to oo.call's left inlet.
As Max 4 (heh):
[oo.alias] is something we've discussed for a future version, it would store a reference and allow you to call that as if it was the original object referred to:
channel a = new channel;
alias b = a;
b.print_something() // calls a.print_something()
Is there currently (or are their any plans to implement) a way of intercepting calls to unimplemented methods in a scoped subpatcher? I was looking for a way to have a subpatcher relay all calls to methods that it doesn't implement, to another object (to have it act as a kind of proxy).
When faced with this sort of request, my usual response would be "why do you need to do that"?
Can you frame your question in terms of what you want to achieve, rather than how you expect to achieve it? The scoped patcher can already tell you what methods it implements, if that's of any use.
Alternately, what would be the equivalent in some other oo language?
Quote:Alternately, what would be the equivalent in some other oo language?
Ruby's method_missing
bitbutter wrote on Mon, 27 April 2009 01:06
Ruby's method_missing
Although I have found Ruby's method_missing hook incredibly useful in some situations, I'm having trouble seeing how to get the same benefit in Max. Wouldn't it be simpler to create an 'anything' method and [route] as needed based on the parameters?
Maybe you can describe a particular problem you are trying to solve.
We could posit some [oo.method missing] construct I suppose, but how would you expect oo.call to respond when an attempt is made to set a call to a non-existent method? Should it output the reference of [oo.method missing] instead of 0? Seems a bit ambiguous, and I hate ambiguity.
If you really want to go this way, you could use the "this" method and roll your own method despatch internally based on appended message arguments, as I outlined a few posts back in response to another question.
Or test at oo.call set if the method exists, and if not, set the call to some known default method instead? All the tools you need to do that exist, you'd just make an abstraction extending oo.call.
Or include your own method-discovery method inside your patchers, returning a reference to the method (if found) or to the default method (if not)?
As Adam suggests, I think a description of the problem you need to solve would be useful, rather than a request for a specific solution.
For the patch i was working on i scrapped the idea of using a missing_method type approach and used a simpler solution.
Thanks for the suggestions for emulating something like method_missing, I'll revist them next time I think it would be useful.
Hi,
For all you fans, we have done a silent release of the Max 5 and Windows versions of the oo objects:
This version, 0.41, is focused only on the transition to Max 5 and Windows. We've also been working on some other upgrades which we believe will make the oo objects easier to understand for new users. But these need more work before we will be ready to release them in 0.5 and 0.6.
With this version we included a folder called 'oo examples'. In the future we want to keep adding examples of how scope and object oriented principles can improve working with complex max patches.
If you have any questions or suggestions, let us know!
Cheers,
Mattijs and John
Hi,
I ran into some scoping trouble getting the oo objects (v0.41) to work in a poly~ under Max 5.0.7. Sorry if somebody's already asked you about this one, or if you already know!
In my patch I have a poly~ scoped as "test". Inside the poly~ are three subpatchers, scoped as "p1", "p2" and "p3". Each one contains a method named "rand". In p1 and p2 the rand methods are public, and in p3 it is private. There are four calls in the top level of the poly~ patcher - to p1.rand, p2.rand, p3.rand and test.rand.
What seems to happen is that _none_ of the subpatchers in the poly~ get registered using their @oo attributes, and the subpatcher "p3" get registered with the @oo attribute of the poly~ object itself (as "test"). The Max window shows the first two subpatchers also attempting to register as "test" and failing, I think:
"patcher: oo patcher: cannot register patcher as "test" in parent scope "test[1]", name is already in use"
So calls to p1.rand, p2.rand and p3.rand throw errors saying they can't find any such members, and a call to test.rand throws an error that the method is private.
Any thoughts? Here are the patches:
myPatch.maxpat
oopoly.maxpat
Hi Josiah,
Thanks for the elaborate description and example patches. I will look into this in the next few days.
Best,
Mattijs
The link for OO Objects no longer works. It looks like the share pages were taken down temporarily for the recent website redesign. Is there somewhere else we can get them until the share pages are restored?
Uh. Seems I don't have a complete Mac/Win distribution zip for 0.42 here either. Mattijs, I think we need you...
Estas parecen muy interesantes. ahora que estoy empezando a trabajar en un parche grande y compleja que estoy interesado en aprender más acerca de estos objetos ...
aunque no tengo conocimientos de programación, tengo una idea general sobre lo que es OOP. lo suficiente para ver cómo se puede simplificar algunas rutinas de revisión de la construcción.
el problema que tenemos ahora es que me he mirado los objetos y la ayuda a los archivos, pero yo no puedo dar el siguiente paso para utilizar estos objetos. ¿Puede alguien publique un parche ejemplo, el uso de estos en su contexto? Yo sé que me ayudaría mucho.
Can anyone translate that for those of us who have only English?
Don't think we released 0.42 yet, duh. I've put 0.41 up on the Opus Locus webserver:
Any news on these objects?
(Using Max 6.1.3 on Mac OS X 10.8.4 they don't work)
Thank you
Bernhard