Forums > MaxMSP

How to apply oo within Max

March 24, 2007 | 7:35 pm

Hi all,

This one goes out to all object oriented programmers that use Max.

When patches get bigger, the need increases for a design principle that keeps you in charge. It would be great to construct a document/tutorial/convention that lays out the most efficient way to apply oo principles to programming in Max, if possible at all.

I am very interested to hear your thoughts about possible comparisons and how you use your oo experience in your patches.

Regards,
Mattijs


March 24, 2007 | 7:49 pm

I’ll kick off with an attempt to an ‘oo to max’ glossary:

* class -> abstraction or subpatcher prototype;
* instance -> an instantiated abstraction or one copy of a subpatcher prototype;
* variable -> pv;
* access to a public variable from outside its scope -> impossible
* private method call -> subpatcher inlet;
* public method call with one argement -> pattr;
* scope -> subpatcher level;
* namespace -> pattrmarker;
* inheritance -> pattr bound to parent, pv;
* polymorphism -> subpatcher arguments;
* method with return -> grab with unique name (using #0)
* data type -> only 4 options: int, float, list, symbol
* return type -> irrelevant
* abstract class -> ..
* static method -> ..
* typecasting -> ..
* ..

Feel free to fill in the gaps, or remake the whole thing.

Cheers,
Mattijs


March 24, 2007 | 11:10 pm

Are class constructors at all possible with max sub patching?


March 24, 2007 | 11:30 pm

Quote: adamsynnott wrote on Sun, 25 March 2007 00:10
—————————————————-
> Are class constructors at all possible with max sub patching?
—————————————————-

Yeah, like this, for example:

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 211 103 45 9109513 instance;
#P comment 211 81 45 9109513 instance;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 38 103 161 9109513 p instance_Filter @cutoff 300 @q 5.;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 38 81 171 9109513 p instance_Filter @cutoff 3000 @q 1.5;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 38 45 64 9109513 p class_Filter;
#P comment 104 45 32 9109513 class;
#P window clipboard copycount 6;

Mattijs




March 25, 2007 | 12:57 pm

Quote: Gregory Taylor wrote on Sun, 25 March 2007 10:01
—————————————————-
> http://jamoma.org/
>
>
> http://www.cycling74.com/forums/index.php?t=msg&goto=97531&rid=0&srch=Jamoma#msg_97531
>
>
—————————————————-

Thanks for the input Gregory.

However it seems that both Arne’s article and Jamoma do not address object oriented principles. Both approaches have an inside-out focus, i.e. working with the Max idiom and optimizing from there.

Although both are very valueable initiatives, I prefer to look at Max in the context of standard programming conventions. Computer programming has been here for a longer time than max patching and posesses a much higher manageability/complexity ratio. Whenever I have a decision to make about structure or organization in my patches, I first think about the way I would do it in Java or C++ and make my decisions from there. This way I am able to realize far more complex patches than, well.., others.

Cheers,
Mattijs


March 25, 2007 | 2:33 pm


March 25, 2007 | 6:52 pm

Agreed, JAMOMA is about standaridizing a Max api. OO is about
the the structuring and organizatrion of thought. It is a sciecne all
its own. I think OO Max would be a great idea. Being a software engineer,
I understand how OO design can help manage huge projects and
reduce the amount of owrk involved in buiding on existing projects.
It would only make sense that I would want to apply those skills to
my musical abstractions and systems. I think we should create some
examples that demonstarte these concepts.

Actually you can access to a public variable from outside its scope.
pattr not only allows me to address parent data, but child data as well.
Interestingly enough, pattr won’t let me bind to data members that are
initialized with patcherargs. See examples below…

Anthony

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 67 186 172 9109513 public data accessor;
#P comment 233 208 172 9109513 < - doesn't work!;
#P number 65 278 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 65 252 165 9109513 pattr @bindto instance_Filter3::cutoff;
#X prestore 1 0 2976.;
#P objectname u674000018;
#P number 65 230 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#N vpatcher 741 304 1225 744;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname numbox2;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop 1;
#P newobj 44 131 82 9109513 p instance_Filter3;
#P objectname instance_Filter3;
#P newex 65 204 165 9109513 pattr @bindto instance_Filter2::cutoff;
#X prestore 1 0 0;
#P objectname u191000019;
#P comment 217 107 45 9109513 instance;
#P comment 217 85 45 9109513 instance;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop 1;
#P newobj 44 107 166 9109513 p instance_Filter2 @cutoff 300 @q 5.;
#N vpatcher 539 178 1023 618;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname numbox2;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 44 85 171 9109513 p instance_Filter @cutoff 3000 @q 1.5;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 44 49 64 9109513 p class_Filter;
#P comment 110 49 32 9109513 class;
#P window linecount 3;
#P comment 239 253 172 9109513 but this does , it woiuld seem that pattr
won’t bind to data members that are initialized with patcher args!;
#P connect 7 0 9 0;
#P connect 10 0 11 0;
#P window clipboard copycount 14;

—– Original Message —–
From: "Mattijs Kneppers"
To:
Sent: Sunday, March 25, 2007 6:57 AM
Subject: [maxmsp] Re: How to apply oo within Max

>
> Quote: Gregory Taylor wrote on Sun, 25 March 2007 10:01
> —————————————————-
> > http://jamoma.org/
> >
> >
> >
http://www.cycling74.com/forums/index.php?t=msg&goto=97531&rid=0&srch=Jamoma
#msg_97531
> >
> >
> —————————————————-
>
>
> Thanks for the input Gregory.
>
> However it seems that both Arne’s article and Jamoma do not address object
oriented principles. Both approaches have an inside-out focus, i.e. working
with the Max idiom and optimizing from there.
>
> Although both are very valueable initiatives, I prefer to look at Max in
the context of standard programming conventions. Computer programming has
been here for a longer time than max patching and posesses a much higher
manageability/complexity ratio. Whenever I have a decision to make about
structure or organization in my patches, I first think about the way I would
do it in Java or C++ and make my decisions from there. This way I am able to
realize far more complex patches than, well.., others.
>
> Cheers,
> Mattijs
>
>
>
>
> –
> SmadSteck – http://www.smadsteck.nl
> Interactive audiovisual sampling soft- and hardware
>



jln
March 25, 2007 | 8:10 pm


March 25, 2007 | 9:13 pm


March 25, 2007 | 9:29 pm



jln
March 25, 2007 | 10:21 pm


March 26, 2007 | 11:42 am

> That’s right, patcherargs are triggered after all loadbangs, but in ‘random’ order. In fact the order is determined by the order in which you created the subpatchers. The last one you created comes first.

Not sure if it is the same with pattr, but generally speaking you can play with this order.

_
johan

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 170 202 100 196617 first is first;
#P message 53 202 113 196617 script sendtoback first;
#P message 39 166 119 196617 script bringtofront first;
#N thispatcher;
#Q end;
#P newobj 39 232 61 196617 thispatcher;
#P newex 387 214 32 196617 print;
#P newex 441 139 84 196617 loadmess second;
#P comment 159 166 100 196617 first is second;
#P newex 345 135 75 196617 loadmess first;
#P objectname first;
#P connect 0 0 3 0;
#P connect 2 0 3 0;
#P connect 5 0 4 0;
#P connect 6 0 4 0;
#P window clipboard copycount 8;


March 26, 2007 | 12:57 pm

Quote: jvkr wrote on Mon, 26 March 2007 13:42
—————————————————-
>
> > That’s right, patcherargs are triggered after all loadbangs, but in ‘random’ order. In fact the order is determined by the order in which you created the subpatchers. The last one you created comes first.
>
> Not sure if it is the same with pattr, but generally speaking you can play with this order.
>
> _
> johan
>
>
> #P window setfont "Sans Serif" 9.;
> #P window linecount 1;
> #P comment 170 202 100 196617 first is first;
> #P message 53 202 113 196617 script sendtoback first;
> #P message 39 166 119 196617 script bringtofront first;
> #N thispatcher;
> #Q end;
> #P newobj 39 232 61 196617 thispatcher;
> #P newex 387 214 32 196617 print;
> #P newex 441 139 84 196617 loadmess second;
> #P comment 159 166 100 196617 first is second;
> #P newex 345 135 75 196617 loadmess first;
> #P objectname first;
> #P connect 0 0 3 0;
> #P connect 2 0 3 0;
> #P connect 5 0 4 0;
> #P connect 6 0 4 0;
> #P window clipboard copycount 8;
>
—————————————————-

Nice trick :) Not a solution for a modular environment, but still.

Mattijs


March 26, 2007 | 1:07 pm


March 26, 2007 | 1:49 pm


March 26, 2007 | 2:11 pm


March 26, 2007 | 3:04 pm

Quote: Anthony Palomba wrote on Mon, 26 March 2007 15:49
—————————————————-
> Thats why I would say pv should be the OO equivalent of a
> private variable. "pattr @bindto" can access those data members
> that are public.

I agree, then pv should be the private variable. I think we don’t really need a public variable. We do need a method that changes the value of the private variable. I agree that this could be pattr. I made a small example below, let me know what you think.

Mattijs

In fact a pattr might even act like a get and set method at the same time (not illustrated in the example).

#P window setfont "Sans Serif" 9.;
#P flonum 275 53 71 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 1;
#P newex 275 71 186 196617 pattr @bindto Filter[1]::method_cutoff;
#X prestore 1 0 0;
#P objectname u334001904;
#N vpatcher 69 54 532 639;
#P window setfont "Sans Serif" 9.;
#P window linecount 3;
#P comment 268 149 66 196617 initialization done by constructor;
#P window linecount 0;
#N vpatcher 50 119 480 319;
#P window setfont "Sans Serif" 9.;
#P newex 50 48 20 196617 t b;
#P newex 269 76 92 196617 pv var_filterType;
#P newex 170 76 51 196617 pv var_q;
#P newex 50 76 73 196617 pv var_cutoff;
#P newex 269 96 62 196617 prepend set;
#P inlet 50 30 15 0;
#P outlet 50 116 15 0;
#P outlet 170 116 15 0;
#P outlet 269 116 15 0;
#P connect 3 0 8 0;
#P fasten 8 0 5 0 55 70 55 70;
#P connect 5 0 2 0;
#P fasten 8 0 6 0 55 70 175 70;
#P connect 6 0 1 0;
#P fasten 8 0 7 0 55 70 274 70;
#P connect 7 0 4 0;
#P connect 4 0 0 0;
#P pop;
#P newobj 51 483 102 196617 p method_doProcess;
#P window linecount 1;
#P comment 16 468 75 196617 private method;
#P comment 13 30 63 196617 constructor;
#P flonum 51 519 52 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P message 51 536 63 196617 lowpass;
#P flonum 51 502 52 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 14 410 27 196617 t b l;
#P newex 31 430 92 196617 pv var_filterType;
#P newex 14 390 193 196617 pattr method_filterType @autorestore 0;
#X prestore 1 0 0;
#P objectname method_filterType;
#P newex 15 322 29 196617 t b f;
#P newex 34 342 51 196617 pv var_q;
#P newex 15 302 152 196617 pattr method_q @autorestore 0;
#X prestore 1 0 0;
#P objectname method_q;
#P window linecount 0;
#P newex 15 235 29 196617 t b f;
#P window linecount 1;
#P newex 34 255 73 196617 pv var_cutoff;
#P window linecount 0;
#P newex 15 215 174 196617 pattr method_cutoff @autorestore 0;
#X prestore 1 0 0;
#P objectname method_cutoff;
#P window linecount 1;
#P newex 267 125 92 196617 pv var_filterType;
#P newex 267 105 51 196617 pv var_q;
#P window linecount 0;
#P newex 267 85 73 196617 pv var_cutoff;
#P newex 267 65 144 196617 route cutoff q filterType done;
#P newex 12 45 265 196617 patcherargs @cutoff 20000 @q 0.7 @filterType lowpass;
#P comment 15 197 94 196617 public set methods;
#P connect 12 0 14 0;
#P connect 6 0 8 0;
#P connect 9 0 11 0;
#P connect 14 1 13 0;
#P connect 8 1 7 0;
#P connect 11 1 10 0;
#P fasten 2 3 20 0 371 456 56 456;
#P fasten 8 0 20 0 20 278 56 278;
#P fasten 11 0 20 0 20 365 56 365;
#P fasten 14 0 20 0 19 456 56 456;
#P connect 20 0 15 0;
#P connect 20 1 17 0;
#P connect 20 2 16 0;
#P connect 1 1 2 0;
#P connect 2 0 3 0;
#P connect 2 1 4 0;
#P connect 2 2 5 0;
#P pop;
#P newobj 31 40 72 196617 p class_Filter;
#P objectname Filter;
#N vpatcher 69 54 532 639;
#P window setfont "Sans Serif" 9.;
#P window linecount 3;
#P comment 268 149 66 196617 initialization done by constructor;
#P window linecount 0;
#N vpatcher 50 119 480 319;
#P window setfont "Sans Serif" 9.;
#P newex 50 48 20 196617 t b;
#P newex 269 76 92 196617 pv var_filterType;
#P newex 170 76 51 196617 pv var_q;
#P newex 50 76 73 196617 pv var_cutoff;
#P newex 269 96 62 196617 prepend set;
#P inlet 50 30 15 0;
#P outlet 50 116 15 0;
#P outlet 170 116 15 0;
#P outlet 269 116 15 0;
#P connect 3 0 8 0;
#P fasten 8 0 5 0 55 70 55 70;
#P connect 5 0 2 0;
#P fasten 8 0 6 0 55 70 175 70;
#P connect 6 0 1 0;
#P fasten 8 0 7 0 55 70 274 70;
#P connect 7 0 4 0;
#P connect 4 0 0 0;
#P pop;
#P newobj 51 483 102 196617 p method_doProcess;
#P window linecount 1;
#P comment 16 468 75 196617 private method;
#P comment 13 30 63 196617 constructor;
#P flonum 51 519 52 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P message 51 536 63 196617 lowpass;
#P flonum 51 502 52 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 14 410 27 196617 t b l;
#P newex 31 430 92 196617 pv var_filterType;
#P newex 14 390 193 196617 pattr method_filterType @autorestore 0;
#X prestore 1 0 0;
#P objectname method_filterType;
#P newex 15 322 29 196617 t b f;
#P newex 34 342 51 196617 pv var_q;
#P newex 15 302 152 196617 pattr method_q @autorestore 0;
#X prestore 1 0 0;
#P objectname method_q;
#P window linecount 0;
#P newex 15 235 29 196617 t b f;
#P window linecount 1;
#P newex 34 255 73 196617 pv var_cutoff;
#P window linecount 0;
#P newex 15 215 174 196617 pattr method_cutoff @autorestore 0;
#X prestore 1 0 0;
#P objectname method_cutoff;
#P window linecount 1;
#P newex 267 125 92 196617 pv var_filterType;
#P newex 267 105 51 196617 pv var_q;
#P window linecount 0;
#P newex 267 85 73 196617 pv var_cutoff;
#P newex 267 65 144 196617 route cutoff q filterType done;
#P newex 12 45 265 196617 patcherargs @cutoff 20000 @q 0.7 @filterType lowpass;
#P comment 15 197 94 196617 public set methods;
#P connect 12 0 14 0;
#P connect 6 0 8 0;
#P connect 9 0 11 0;
#P connect 14 1 13 0;
#P connect 8 1 7 0;
#P connect 11 1 10 0;
#P fasten 14 0 20 0 19 456 56 456;
#P fasten 11 0 20 0 20 365 56 365;
#P fasten 8 0 20 0 20 278 56 278;
#P fasten 2 3 20 0 371 456 56 456;
#P connect 20 0 15 0;
#P connect 20 1 17 0;
#P connect 20 2 16 0;
#P connect 1 1 2 0;
#P connect 2 0 3 0;
#P connect 2 1 4 0;
#P connect 2 2 5 0;
#P pop;
#P newobj 31 74 86 196617 p instance_Filter;
#P objectname Filter[1];
#P window linecount 4;
#P comment 133 38 100 196617 Note: the difference between a class and an instance is in the object name;
#P connect 4 0 3 0;
#P window clipboard copycount 5;


March 26, 2007 | 3:26 pm

Quote: lists@lowfrequency.or wrote on Mon, 26 March 2007 16:11
—————————————————-
> for public variables, you have pattrmarker to create globally-
> accessible namespaces for patchers.
>

For a global namespace pattrmarker is a great candidate. It was in my glossary attempt earlier in this thread.

But for a public variable a global mechanism wouldn’t work. We explicitly need variables to be local.

Cheers,
Mattijs


March 27, 2007 | 8:40 am

Mattijs Kneppers schrieb:
> I first think about the way I would do it in Java or C++ and
> make my decisions from there. This way I am able to realize far more
> complex patches than, well.., others.

But maybe the solutions could be less complex if you would not restrict
yourself to "official" oo-thinking… ;-)

I learned programming, first as spaghetti with Fortran, then procedural
with Pascal and especially Modula II. Then there was Oberon, and there
where some interesting ancient discussions. Nicolas Wirth claimed that
Oberon (the successor to Modula II) is an object oriented language. The
interesting for me was, that he just showed how to translate those
"official" oo-talk into the concepts behind Oberon. And the Oberon way
of thinking is much more intuitive, as the Max way of thinking is (for
me at least ;-).
Many of the pictures which are used to explain oo-talk could be easily,
without need of explanation, be done in a signal flow language like Max.
The picture and the program are the same, as you can translate those
fancy flowcharts directly into working patches…

You already translated some oo-talk into Max-talk, and reading Arne’s
article is easy to map to oo-thinking. You’d might make things more
complicated than they need to be eventually…

by the way your list could need an update with two lines:

* variable -> pv;
* access to a public variable from outside its scope -> impossible

to

* local variable -> pv; (as its local ther is no access from outside)
* global variable -> pattr, value, any named object;
* access to a public variable from outside its scope -> pattr, pattrforward;

I’d rather think of information flow between objects, than of objects…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


March 27, 2007 | 8:52 am

Mattijs Kneppers schrieb:
> When you want an object to be instatiated for example before it
> receives a loadbang from ‘outside’, you’ll have to use a loadbang to
> trigger patcherargs, which is shady.

If you place this inside, you should be able to sort it…
Its only a workaround, but should be fine even if the behavior will
change in the future…

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 218 183 67 196617 zl reg;
#P newex 134 184 38 196617 zl reg;
#P newex 162 102 66 196617 patcherargs;
#P newex 218 153 50 196617 onebang;
#P newex 218 127 67 196617 route done;
#P newex 162 75 50 196617 loadbang;
#P fasten 2 0 4 0 223 176 139 176;
#P connect 2 0 5 0;
#P connect 1 1 5 1;
#P connect 3 0 4 1;
#P connect 0 0 3 0;
#P fasten 0 0 2 1 167 97 167 97 263 97;
#P connect 3 1 1 0;
#P connect 1 0 2 0;
#P window clipboard copycount 6;


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


March 27, 2007 | 8:56 am

Anthony Palomba schrieb:
> Interestingly enough, pattr won’t let me bind to data members that are
> initialized with patcherargs. See examples below…

Wrong, you didn’t name the subpatcher. It perfectly works here…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com



_j
March 27, 2007 | 9:03 am

Quote: Stefan Tiedje wrote on Tue, 27 March 2007 01:56
—————————————————-
> Anthony Palomba schrieb:
> > Interestingly enough, pattr won’t let me bind to data members that are
> > initialized with patcherargs. See examples below…
>
> Wrong, you didn’t name the subpatcher. It perfectly works here…
>
> Stefan
>
> —
> Stefan Tiedje————x——-
> –_____———–|————–
> –(_|_ —-|—–|—–()——-
> — _|_)—-|—–()————–
> ———-()——–www.ccmix.com
>
>
—————————————————-

PWNED!! =)


March 27, 2007 | 9:29 am

Quote: Stefan Tiedje wrote on Tue, 27 March 2007 10:40
—————————————————-
> Mattijs Kneppers schrieb:
> > I first think about the way I would do it in Java or C++ and
> > make my decisions from there. This way I am able to realize far more
> > complex patches than, well.., others.
>
> But maybe the solutions could be less complex if you would not restrict
> yourself to "official" oo-thinking… ;-)

I think this is hard to determine if you don’t know which level of complexity we’re talking about. I can assure you that from a certain level patches are impossible to manage if you didn’t work with very strict conventions and an overall structure. oo is one possible structure, but it happens to be one that is currently used by literally every major software company.

>
> I learned programming, first as spaghetti with Fortran, then procedural
> with Pascal and especially Modula II. Then there was Oberon, and there
> where some interesting ancient discussions. Nicolas Wirth claimed that
> Oberon (the successor to Modula II) is an object oriented language. The
> interesting for me was, that he just showed how to translate those
> "official" oo-talk into the concepts behind Oberon. And the Oberon way
> of thinking is much more intuitive, as the Max way of thinking is (for
> me at least ;-).
> Many of the pictures which are used to explain oo-talk could be easily,
> without need of explanation, be done in a signal flow language like Max.
> The picture and the program are the same, as you can translate those
> fancy flowcharts directly into working patches…

You seem to have some kind of grudge against oo, I can’t imagine what it could be but perhaps it would be good to first get into it a bit more before rejecting it..?

>
> You already translated some oo-talk into Max-talk, and reading Arne’s
> article is easy to map to oo-thinking. You’d might make things more
> complicated than they need to be eventually…

I really don’t think Arne article has anything to do with oo. He talks about general optimization and patching principles, which will definitly help you when working towards more complex patches. But it’s not a general template that lets you manage a big program. As he states in the beginning of his article, he’s not a programmer.

Of course there is always the danger of making things more complicated than necessary (k.i.s.s.) but that’s a separate issue. When programming a simple patch there is no need for any structure, needless to say oo. But when things get complex it’s different.

>
> by the way your list could need an update with two lines:

Thanks for the input:

> * local variable -> pv; (as its local ther is no access from outside)

agreed (as stated earlier)

> * global variable -> pattr,

not agreed, I think the local character of pattr is much more useful

> value,

agreed

> any named object;

not agreed, see pattr

> * access to a public variable from outside its scope -> pattr, pattrforward;

See earlier posts. I vote for pattr to be more like a function.

Cheers,
Mattijs

Btw, your idea to derive an instance number out of the object name (where the index appears within [] and is automatically updated by max) is very valueable for this discussion. I think I will include the javascript we discussed at that time in the next example.


March 27, 2007 | 10:16 am

Almost right. patcherargs outputs the attributes sequentially so the zl reg won’t work. This one should:

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 101 120 29 196617 gate;
#P newex 45 76 40 196617 t 0 b 1;
#P newex 45 120 29 196617 gate;
#P newex 64 98 66 196617 patcherargs;
#P newex 45 56 50 196617 loadbang;
#P connect 0 0 3 0;
#P connect 3 2 2 0;
#P connect 3 0 2 0;
#P connect 3 1 1 0;
#P connect 1 0 2 1;
#P connect 3 0 4 0;
#P connect 3 2 4 0;
#P connect 1 1 4 1;
#P window clipboard copycount 5;

But in general, when triggering patcherargs with loadbang, another problem rises, see

http://www.cycling74.com/forums/index.php?t=msg&rid=3579&S=1db647feb72af7a35983cb84e6783cfe&th=22677&goto=84668#msg_84668

Mattijs

Quote: Stefan Tiedje wrote on Tue, 27 March 2007 10:52
—————————————————-
> Mattijs Kneppers schrieb:
> > When you want an object to be instatiated for example before it
> > receives a loadbang from ‘outside’, you’ll have to use a loadbang to
> > trigger patcherargs, which is shady.
>
> If you place this inside, you should be able to sort it…
> Its only a workaround, but should be fine even if the behavior will
> change in the future…
>
> #P window setfont "Sans Serif" 9.;
> #P window linecount 1;
> #P newex 218 183 67 196617 zl reg;
> #P newex 134 184 38 196617 zl reg;
> #P newex 162 102 66 196617 patcherargs;
> #P newex 218 153 50 196617 onebang;
> #P newex 218 127 67 196617 route done;
> #P newex 162 75 50 196617 loadbang;
> #P fasten 2 0 4 0 223 176 139 176;
> #P connect 2 0 5 0;
> #P connect 1 1 5 1;
> #P connect 3 0 4 1;
> #P connect 0 0 3 0;
> #P fasten 0 0 2 1 167 97 167 97 263 97;
> #P connect 3 1 1 0;
> #P connect 1 0 2 0;
> #P window clipboard copycount 6;
>
>
>
>
> —
> Stefan Tiedje————x——-
> –_____———–|————–
> –(_|_ —-|—–|—–()——-
> — _|_)—-|—–()————–
> ———-()——–www.ccmix.com
>
>
—————————————————-


March 27, 2007 | 10:41 am

Ah you’re right Stefan. I missed this one too.

Phew.. one less issue to worry about.

Mattijs

Quote: Stefan Tiedje wrote on Tue, 27 March 2007 10:56
—————————————————-
> Anthony Palomba schrieb:
> > Interestingly enough, pattr won’t let me bind to data members that are
> > initialized with patcherargs. See examples below…
>
> Wrong, you didn’t name the subpatcher. It perfectly works here…
>
> Stefan
>
> —
> Stefan Tiedje————x——-
> –_____———–|————–
> –(_|_ —-|—–|—–()——-
> — _|_)—-|—–()————–
> ———-()——–www.ccmix.com
>
>
—————————————————-


March 27, 2007 | 5:06 pm

awww man, I got served! Indeed I did not name the subpatcher.
Here is the corrected version

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 67 186 172 9109513 public data accessor;
#P number 65 278 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 65 252 165 9109513 pattr @bindto instance_Filter3::cutoff;
#X prestore 1 0 2970.;
#P objectname u592000003;
#P number 65 230 35 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#N vpatcher 741 304 1225 744;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname numbox2;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P window linecount 1;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop 1;
#P newobj 44 131 82 9109513 p instance_Filter3;
#P objectname instance_Filter3;
#P newex 65 204 165 9109513 pattr @bindto instance_Filter2::cutoff;
#X prestore 1 0 300.;
#P objectname u197000004;
#P comment 217 107 45 9109513 instance;
#P comment 217 85 45 9109513 instance;
#N vpatcher 652 272 888 474;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 44 107 166 9109513 p instance_Filter2 @cutoff 300 @q 5.;
#P objectname instance_Filter2;
#N vpatcher 539 178 1023 618;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname numbox2;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P objectname cutoff;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 44 85 171 9109513 p instance_Filter @cutoff 3000 @q 1.5;
#N vpatcher 450 286 686 488;
#P window setfont "Sans Serif" 9.;
#P flonum 96 118 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P flonum 68 99 55 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 68 76 66 9109513 route cutoff q;
#P newex 21 54 57 9109513 patcherargs;
#P connect 0 1 1 0;
#P connect 1 0 2 0;
#P connect 1 1 3 0;
#P pop;
#P newobj 44 49 64 9109513 p class_Filter;
#P comment 110 49 32 9109513 class;
#P connect 9 0 10 0;
#P connect 6 0 8 0;
#P window clipboard copycount 12;

—– Original Message —–
From: jamez
Date: Tuesday, March 27, 2007 3:05 am
Subject: [maxmsp] Re: Re: How to apply oo within Max

>
> Quote: Stefan Tiedje wrote on Tue, 27 March 2007 01:56
> —————————————————-
> > Anthony Palomba schrieb:
> > > Interestingly enough, pattr won’t let me bind to data members
> that are
> > > initialized with patcherargs. See examples below…
> >
> > Wrong, you didn’t name the subpatcher. It perfectly works here…
> >
> > Stefan
> >
> > —
> > Stefan Tiedje————x——-
> > –_____———–|————–
> > –(_|_ —-|—–|—–()——-
> > — _|_)—-|—–()————–
> > ———-()——–www.ccmix.com
> >
> >
> —————————————————-
>
>
> PWNED!! =)
>


March 27, 2007 | 10:10 pm

Mattijs Kneppers schrieb:
> You seem to have some kind of grudge against oo, I can’t imagine what
> it could be but perhaps it would be good to first get into it a bit
> more before rejecting it..?

You’re absolutely right here… (I don’t reject it, I am just jealous if
someone can talk oo… I have enough difficulties with French already… ;-)

>> * global variable -> pattr,
>
> not agreed, I think the local character of pattr is much more useful

But you can use it for both, its a matter of how you place them in
combination with pattrmarker.

> See earlier posts. I vote for pattr to be more like a function.

For me a function does something, pattr doesn’t "do" anything but
storing, in my nomenclatura thats a variable and not a function…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


March 28, 2007 | 8:43 am

Quote: Stefan Tiedje wrote on Wed, 28 March 2007 00:10
—————————————————-
> Mattijs Kneppers schrieb:
> > You seem to have some kind of grudge against oo, I can’t imagine what
> > it could be but perhaps it would be good to first get into it a bit
> > more before rejecting it..?
>
> You’re absolutely right here… (I don’t reject it, I am just jealous if
> someone can talk oo… I have enough difficulties with French already… ;-)

Ah, mais vraiment, ce n’est pas trop difficile. If you accidentally program some Java now and then, you automatically run into the vocabulary. And without the language barrier the principles behind it make simple sense. Thanks by the way for coping with my incomplete english all this time ;)

>
> >> * global variable -> pattr,
> >
> > not agreed, I think the local character of pattr is much more useful
>
> But you can use it for both, its a matter of how you place them in
> combination with pattrmarker.

You are right about that. Anyways strictly speaking global variables aren’t used in an oo program. Variables always belong to an object. But sometimes it can be practical to have them nonetheless ;)

>
> > See earlier posts. I vote for pattr to be more like a function.
>
> For me a function does something, pattr doesn’t "do" anything but
> storing, in my nomenclatura thats a variable and not a function…

Indeed it’s better to speak of pattr as the function -call-, not the body of the function. It stores data too, which is not necessary when used as a function call. But I know no other local object that can be triggered from outside a subpatcher but pattr. Have a look at the example I posted earlier to see how I was planning to use pattr as a function call.

Two more issues:

- there is still the problem of having a function return something. A local grab that works on a subpatcher would be good :))

- using pv for a private variable has one drawback; it can’t be overridden :/

Any ideas?

Best,
Mattijs


March 28, 2007 | 12:17 pm


March 28, 2007 | 1:25 pm


March 28, 2007 | 1:47 pm


March 28, 2007 | 3:27 pm

"there is still the problem of having a function return something. A
local grab that works on a subpatcher would be good"

This is something I have always wanted. It would be nice to be able
to have one instance of an object and be able to execute a subpatcher
in that object and get the result back. The imporant thing is that
it needs to be synchronous. It would be nice if one could use pattr
to trigger a subpatcher, passing any arguments as attributes.

Anthony

—– Original Message —–
From: Mattijs Kneppers
Date: Wednesday, March 28, 2007 2:44 am
Subject: [maxmsp] Re: Re: Re: How to apply oo within Max

>
> Quote: Stefan Tiedje wrote on Wed, 28 March 2007 00:10
> —————————————————-
> > Mattijs Kneppers schrieb:
> > > You seem to have some kind of grudge against oo, I can’t
> imagine what
> > > it could be but perhaps it would be good to first get into it
> a bit
> > > more before rejecting it..?
> >
> > You’re absolutely right here… (I don’t reject it, I am just
> jealous if
> > someone can talk oo… I have enough difficulties with French
> already… ;-)
>
> Ah, mais vraiment, ce n’est pas trop difficile. If you
> accidentally program some Java now and then, you automatically run
> into the vocabulary. And without the language barrier the
> principles behind it make simple sense. Thanks by the way for
> coping with my incomplete english all this time ;)
>
> >
> > >> * global variable -> pattr,
> > >
> > > not agreed, I think the local character of pattr is much more
> useful>
> > But you can use it for both, its a matter of how you place them
> in
> > combination with pattrmarker.
>
> You are right about that. Anyways strictly speaking global
> variables aren’t used in an oo program. Variables always belong to
> an object. But sometimes it can be practical to have them
> nonetheless ;)
>
> >
> > > See earlier posts. I vote for pattr to be more like a function.
> >
> > For me a function does something, pattr doesn’t "do" anything
> but
> > storing, in my nomenclatura thats a variable and not a function…
>
> Indeed it’s better to speak of pattr as the function -call-, not
> the body of the function. It stores data too, which is not
> necessary when used as a function call. But I know no other local
> object that can be triggered from outside a subpatcher but pattr.
> Have a look at the example I posted earlier to see how I was
> planning to use pattr as a function call.
>
>
> Two more issues:
>
> – there is still the problem of having a function return
> something. A local grab that works on a subpatcher would be good :))
>
> – using pv for a private variable has one drawback; it can’t be
> overridden :/
>
> Any ideas?
>
> Best,
> Mattijs
>
> –
> SmadSteck – http://www.smadsteck.nl
> Interactive audiovisual sampling soft- and hardware
>
>



jln
March 28, 2007 | 4:40 pm


March 28, 2007 | 5:05 pm


March 29, 2007 | 11:42 pm

Quote: Anthony Palomba wrote on Thu, 29 March 2007 05:05
—————————————————-
> It would be
> nice to not have to use send and recv pairs.

I don’t understand the "no send/receive" stuff. Sure, if you populate your patcher/abstraction (object) with lots of send/receive entry/exit points, that’s asking for trouble, but what’s wrong with scripting receives and sends (or forward) into place at instantiation, with unique send/receive names taken from an argument? Y’know:

[r myobject.input1] and [s myobject.output1]

How is sending a message to that myobject.input1 different from connecting to a patcher input and sending a message?

If listening for a message from the object’s output send is problematic, and you need the object to explicitly message another named receive (which may change), then what’s wrong with [forward], with the destination set on the fly, either as an argument to the input message, or as a "set output1" message (which could alternately delete/create the send if better performance is crucial)?

Connecting everything by patchcords strikes me as imposing considerable constraints on the app structure. Patchcords are certainly desirable in smaller structures to visualise the data flow, but if an object deep inside a heirarchical structure needs to communicate with another object somwhere else, how are you supposed to handle that with patchcords?

What am I not getting?


March 30, 2007 | 12:03 am

On 29/03/07, John Pitcairn wrote:
> Connecting everything by patchcords strikes me as imposing considerable constraints on the app structure…. if an object deep inside a heirarchical structure needs to communicate with another object somwhere else, how are you supposed to handle that with patchcords?

I agree, with a caveat.

I store data into value objects for use (as global variables) by other
patchers/functions. But when I need instantaneous notification, such
as a bang, I need to use send/receive pairs.

But the problem, in my mind, is not knowing what will happen at the
other end. A single bang sent "blindly" can inadvertently trigger a
multitude of actions if I’m not careful (further due to Max’s
modularity via encapsulated patchers).

Yes, I can trace this by command-clicking on the send object, but still…


March 30, 2007 | 12:03 am

Sorry, my post mutated somewhat during writing, and I meant to take the quote out of the above since it appears we’re barking up roughly the same tree (no Max on this machine so can’t look at your patch), but now I can’t edit it. Is this the most annoying forum software around or what?


March 30, 2007 | 1:35 am

Quote: arne wrote on Fri, 30 March 2007 12:03
—————————————————-
> A single bang sent "blindly" can inadvertently trigger a
> multitude of actions if I’m not careful (further due to Max’s
> modularity via encapsulated patchers).

If I need to send to multiple object inputs, I either use multiple unique sends (where the receivers are known and constant), or I use forward in conjunction with a coll containing the unique receive names, dump the coll, and send my message/bang after each coll output has set the destination. Either way, you have the destinations available to view in the source object.

So an OO way to handle your notifications might be to have every object that wants to be notified add their unique receive name to a coll in the notifier object. You’d send an "add receivename" message to the notifier object’s unique receive name, rather than addressing the coll directly via a shared global coll. Then have the notifier process use the forwarding mechanism outlined above.

So you’d always have an explicit list of listeners, owned, set and managed by the notifier.

The use of the coll-forward mechanism does however incur some overhead compared to a straight single-send, multiple-receive mechanism.


March 30, 2007 | 2:38 am

Quote: johnpitcairn wrote on Fri, 30 March 2007 13:35
—————————————————-
The use of the coll-forward mechanism does however incur some overhead compared to a straight single-send, multiple-receive mechanism.
—————————————————-

Though if that’s troublesome, ie you’re sending dense realtime data rather than config/setup messages, have your notifier object script the appropriate unique send into place and connect it, on receipt of the "add receivername" message. Make sure you also give that send a scripting name the same as its receivername (and store it in a coll), so a "remove" message can remove it.


March 30, 2007 | 3:47 am

My point is that send/recv is an asynchronous operation. Having to design
a patcher around this fact can make for some complexity that would
be unnecessary if you could use something like pattr. Pattr is an atomic
operation, you send a bang, you get the answer back. It is a mute
point because patter can not execute a subpatcher. Given that
fact, I guess one could use send/to simulate a function call.

Although come to think of it, is it really a good idea to have a global
object that I can call in to from any place? Or would it be more OO
like to instantiate an object and use inlets to execute functions?

Anthony

—– Original Message —–
From: "John Pitcairn"
To:
Sent: Thursday, March 29, 2007 5:42 PM
Subject: [maxmsp] Re: Re: Re: Re: How to apply oo within Max

>
> Quote: Anthony Palomba wrote on Thu, 29 March 2007 05:05
> —————————————————-
> > It would be
> > nice to not have to use send and recv pairs.
>
> I don’t understand the "no send/receive" stuff. Sure, if you populate your
patcher/abstraction (object) with lots of send/receive entry/exit points,
that’s asking for trouble, but what’s wrong with scripting receives and
sends (or forward) into place at instantiation, with unique send/receive
names taken from an argument? Y’know:
>
> [r myobject.input1] and [s myobject.output1]
>
> How is sending a message to that myobject.input1 different from connecting
to a patcher input and sending a message?
>
> If listening for a message from the object’s output send is problematic,
and you need the object to explicitly message another named receive (which
may change), then what’s wrong with [forward], with the destination set on
the fly, either as an argument to the input message, or as a "set output1"
message (which could alternately delete/create the send if better
performance is crucial)?
>
> Connecting everything by patchcords strikes me as imposing considerable
constraints on the app structure. Patchcords are certainly desirable in
smaller structures to visualise the data flow, but if an object deep inside
a heirarchical structure needs to communicate with another object somwhere
else, how are you supposed to handle that with patchcords?
>
> What am I not getting?
>


March 30, 2007 | 4:41 am

Quote: Anthony Palomba wrote on Fri, 30 March 2007 15:47
—————————————————-
> Although come to think of it, is it really a good idea to have
> a global object that I can call in to from any place? Or would
> it be more OO like to instantiate an object and use inlets to
> execute functions?

Sure, and use an argument to choose one of the object’s different public methods – like the zl object.

For the method to return something to the caller, if instantiated as a discrete instance, you’d just connect the object outlet to wherever you needed it in the calling object.

But this gets into some potentially heavy overhead if you instantiate, connect and de-instantiate an object by scripting on the fly just to call a public method.

Better to have the object created in the calling patch from the get-go, ie what we’re all doing anyway – Max is already OO in this respect.

If, however, it needs to be more like a single static class that provides public utility methods (there are plenty of these in OO-land), and you never instantiate an instance of the class, we can choose among public methods with an explicit message and use route internally, but we don’t have a mechanism to return anything to the caller, because a Max object has no idea where its input is coming from (2-way patchcords, anyone?).

So there would need to be an argument supplied with the input message that provides a return destination – I guess this would be a uniquely named receive or value in the calling object – and have the method either instantiate and set the value (um, overhead again?), or send via a forward.

The equivalent of calling a public method in a static class, passing in a reference to a variable that the method will stash a result in, with the caller owning the referenced variable…?


March 30, 2007 | 5:42 am

On Mar 29, 2007, at 8:47 PM, Anthony Palomba wrote:

> My point is that send/recv is an asynchronous operation.

Not going to get deeply involved in this thread, but I’d like to
clarify that send/recv is a *synchronous* operation. It is simply
ambiguous as to ordering. Empirical tests should demonstrate this.

Otherwise, there’s some interesting points here, many of which have
been tossed around at C74 in various forms. Basically, I think I can
say that there is a general move towards some of the OO ideas under
discussion without a lot of the OO dogma, the latter of which I
personally don’t believe leads to any benefits except for those that
rely on conceptual aesthetics (who can blame those with such
fetishes, as it’s arguably just a byproduct of our maladjusted
libido :) ). One can program OO in assembly language if one wishes.
Language constructs are simply conveniences.

However, I will say we are working very hard to make Max programming
a little more convenient. In the meantime, I would suggest figuring
out ways to work with Max as it is, or write external objects to
solve the problems which we have not solved to your satisfaction.

Happy Maxing,
Joshua


March 30, 2007 | 10:00 am

Couldn’t you make use of send/receive for this – send a list to a
named receive (the function input) – the list includes the input
parameters required by the function, and, most importantly, the
address of a receive in the calling function, which sets the send in
the called function to return its data _only_ to the calling function.

I think there are all sorts of virtues in send/receive – it just
needs clear thinking about how you use them – but good programming
needs that whatever system you use :-)>

Best

L

On 30 Mar 2007, at 05:41, John Pitcairn wrote:

> If, however, it needs to be more like a single static class that
> provides public utility methods (there are plenty of these in OO-
> land), and you never instantiate an instance of the class, we can
> choose among public methods with an explicit message and use route
> internally, but we don’t have a mechanism to return anything to the
> caller, because a Max object has no idea where its input is coming
> from (2-way patchcords, anyone?).
>
> So there would need to be an argument supplied with the input
> message that provides a return destination – I guess this would be
> a uniquely named receive or value in the calling object – and have
> the method either instantiate and set the value (um, overhead
> again?), or send via a forward.

Lawrence Casserley – lawrence@lcasserley.co.uk
Lawrence Electronic Operations – http://www.lcasserley.co.uk
Colourscape Music Festivals – http://www.colourscape.org.uk


March 30, 2007 | 10:37 am

interesting thread.
for me, an easier way of inheritance would be nice, though i wouldn’t
know how to implement this.
i don’t think "forcing" max to use oo concepts would lead to a more
oo-efficient way of working. the hassle of working around things
overturns the benefits of the oo approach imo.
but that’s maybe because i’m not very proficient in oo and the
concept is still new to me.
that said, even the basics of it have some nice conceptual
advantages, especially as the structural visual approach of max loses
it’s advantage when patches grow and the diagram feel is lost.

>
> However, I will say we are working very hard to make Max
> programming a little more convenient. In the meantime, I would
> suggest figuring out ways to work with Max as it is, or write
> external objects to solve the problems which we have not solved to
> your satisfaction.
>
> Happy Maxing,
> Joshua

is it me or are the max 5 teasers ramping up?


March 30, 2007 | 11:53 am

also don’t forget (or maybe people don’t know) that in jitter you
have the "in2_name" property where you can refer explicitly to a
jit.matrix name without needing to use patch cords and the ever-
loving [t b l] object to trigger output.

i find jitter in general a bit more OO, with it’s "@ttributes" that
make figuring out the name of your arguments to an object so much
easier (yes I’m mixing terms here, arguments are different than
attributes)

but unfortunately, given limited screen size, long names inside
objects can in the end make then fairly unreadable. it’s tough to
hit that balance of readability, patching aesthetics, and usefulness,
that is part of any visual programming language with limited screen
space.

but as a side note, using OS X’s built-in screen zoom function can be
very useful, especially during presentations.

cheers
evan

On Mar 30, 2007, at 11:00 AM, lawrence casserley wrote:

> Couldn’t you make use of send/receive for this – send a list to a
> named receive (the function input) – the list includes the input
> parameters required by the function, and, most importantly, the
> address of a receive in the calling function, which sets the send
> in the called function to return its data _only_ to the calling
> function.
>
> I think there are all sorts of virtues in send/receive – it just
> needs clear thinking about how you use them – but good programming
> needs that whatever system you use :-)>
>
> Best
>
> L
>
> On 30 Mar 2007, at 05:41, John Pitcairn wrote:
>
>> If, however, it needs to be more like a single static class that
>> provides public utility methods (there are plenty of these in OO-
>> land), and you never instantiate an instance of the class, we can
>> choose among public methods with an explicit message and use route
>> internally, but we don’t have a mechanism to return anything to
>> the caller, because a Max object has no idea where its input is
>> coming from (2-way patchcords, anyone?).
>>
>> So there would need to be an argument supplied with the input
>> message that provides a return destination – I guess this would be
>> a uniquely named receive or value in the calling object – and have
>> the method either instantiate and set the value (um, overhead
>> again?), or send via a forward.
>
> Lawrence Casserley – lawrence@lcasserley.co.uk
> Lawrence Electronic Operations – http://www.lcasserley.co.uk
> Colourscape Music Festivals – http://www.colourscape.org.uk
>
>



jln
March 30, 2007 | 12:37 pm


March 30, 2007 | 2:26 pm


March 30, 2007 | 3:24 pm


March 30, 2007 | 3:52 pm

Hmm, I have a working example, but it has quite some deficiencies. I think the principle is interesting though, I decided to post it so that people can comment.

The biggest point of criticism I have is that passing id’s is done by patch cords. I tried hiding and coloring some of them but even in an example as simple as this it clearly gets messy and hard to understand.

Cheers,
Mattijs


March 30, 2007 | 4:04 pm

Quote: lawrence casserley wrote on Fri, 30 March 2007 17:24
—————————————————-

> Can anyone _really_ show that this way of thinking is intrinsically
> less satisfactory than an oo structure. I can see the benefits of oo
> at the conceptual level, but I think you can be just as strucutured
> with an inline approach. At the end of the day it needs disciplined
> and consistent thinking to produce a manageable program, whichever
> approach you use.
>

Lawrence, it is not about complex algorithms in relatively small amount of code. It is about relatively simple operations but an awful lot of different ones that all have to work together in a complex way.

Please bear in mind that effectively -every- software company (including Cycling 74) currently uses oo.

Best,
Mattijs



jln
March 30, 2007 | 5:10 pm


March 30, 2007 | 5:25 pm

On 30 Mar 2007, at 17:04, Mattijs Kneppers wrote:

> Lawrence, it is not about complex algorithms in relatively small
> amount of code. It is about relatively simple operations but an
> awful lot of different ones that all have to work together in a
> complex way.

Which is part of my point – the amount of code doesn’t really matter
much, so reusing abstractions is no problem – a good abstraction will
usually be a fairly simple operation, and using it inline is clear
and easy to understand. I don’t see that the structure I suggested
for mimicking calling a subroutine is _necessarily_ an improvement,
and it does make some complications – I think there are situations
where such a structure might be useful, but I would hate to impose it
in all circumstances. Max is a visual language and we should take
advantage of this, and when we obscure that visual flow, then it must
be for a really good reason.

My point about the assembler dsp was similar – repeating the code
didn’t matter, but in that case (getting the absolute maximum out of
a what seem today to be a ridiculously slow processor was paramount)
the inline thinking was very important.

All of which may seem to imply that I always use only patchcords,
whereas in fact I find send/receives (with easy-to-understand names!)
frequently actually improve understandability. And anyway, I love to
play devil’s advocate! ;-)>

Best

L

Lawrence Casserley – lawrence@lcasserley.co.uk
Lawrence Electronic Operations – http://www.lcasserley.co.uk
Colourscape Music Festivals – http://www.colourscape.org.uk


March 30, 2007 | 5:58 pm

Quote: jkc wrote on Thu, 29 March 2007 23:42
—————————————————-

> Otherwise, there’s some interesting points here, many of which have
> been tossed around at C74 in various forms. Basically, I think I can
> say that there is a general move towards some of the OO ideas under
> discussion without a lot of the OO dogma.
> One can program OO in assembly language if one wishes.
> Language constructs are simply conveniences.
> However, I will say we are working very hard to make Max programming
> a little more convenient.

It’s good to read that. Many people learn OO approach through LISP (or Scheme…) Looking forward to discovering Max 5…
Jean-Francois.


March 31, 2007 | 12:48 am

Quote: lawrence casserley wrote on Fri, 30 March 2007 22:00
—————————————————-
> Couldn’t you make use of send/receive for this – send a list
> to a named receive (the function input) – the list includes
> the input parameters required by the function, and, most
> importantly, the address of a receive in the calling function,
> which sets the send in the called function to return its data
> _only_ to the calling function.

Um, yeah, isn’t that what I said, except use a forward rather than a send to return (unless you want to be deleting/instantiating sends all the time for different callers)? I certainly thought it was ;-)

> I think there are all sorts of virtues in send/receive – it
> just needs clear thinking about how you use them – but good
> programming needs that whatever system you use :-)>

Yes indeed. Send/receive can get a beginner into a lot of trouble…


March 31, 2007 | 1:32 am

Quote: Mattijs wrote on Sat, 31 March 2007 02:26
—————————————————-
> To johnpitcairn: you’re right that send/receives are very
> usable (and a good choice performancewise, see the ‘pattr
> performance’ thread), but only if you can make sure that there
> are no duplicate names involved. Imo, this is only possible by
> using generated unique id’s in s/r names. You talk about
> having a coll with all unique send/receives, but I’d say OO
> involves having -a unique reference- (in whatever form) to all
> registered objects.

Sure, and since it’s the "listener" object that tells the "notifier" to register it, the listener could supply the unique reference, using #0 to generate that at instantiation. I was omitting that for simplicity/brevity. So the coll inside the notifier would indeed contain unique references, generated by the lister and supplied to the notifier.

Example:

save as "listener.mxt"
———————
max v2;
#N vpatcher 619 208 1219 608;
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 88 113 31 196617 t b s;
#P newex 255 223 66 196617 prepend send;
#P newex 47 112 31 196617 t b s;
#P newex 47 80 92 196617 route add remove;
#N comlet list: add/remove (notifier);
#P inlet 47 49 15 0;
#P newex 223 296 50 196617 forward;
#P newex 383 110 87 196617 print $0_listener;
#P newex 383 84 87 196617 r $0_notifyme;
#P message 139 223 109 196617 remove $0_notifyme;
#P message 47 223 84 196617 add $0_notifyme;
#P connect 5 0 6 0;
#P connect 6 0 7 0;
#P connect 7 0 0 0;
#P connect 6 1 9 0;
#P connect 9 0 1 0;
#P connect 8 0 4 0;
#P connect 0 0 4 0;
#P connect 1 0 4 0;
#P connect 7 1 8 0;
#P connect 9 1 8 0;
#P connect 2 0 3 0;
#P pop;

save as "notifier.mxt"
———————-
max v2;
#N vpatcher 334 167 948 733;
#P window setfont "Sans Serif" 9.;
#P newex 75 378 20 196617 b 1;
#P newex 389 197 80 196617 prepend remove;
#P newex 231 319 69 196617 prepend send;
#P newex 231 296 69 196617 route symbol;
#P newex 231 224 69 196617 t renumber l;
#P newex 231 176 50 196617 pack s s;
#P message 88 193 34 196617 dump;
#P newex 88 141 50 196617 loadbang;
#P newex 231 198 140 196617 prepend nstore 2147483647;
#N coll ;
#P newobj 231 271 84 196617 coll;
#P newex 231 476 50 196617 forward;
#P message 75 401 145 196617 notification from $1;
#P newex 88 166 67 196617 metro $2;
#P newex 271 58 97 196617 r $1;
#P newex 271 85 98 196617 route add remove;
#P connect 12 0 14 0;
#P connect 14 0 3 0;
#P connect 7 0 2 0;
#P connect 2 0 8 0;
#P connect 0 0 9 0;
#P connect 9 0 6 0;
#P connect 6 0 10 0;
#P connect 13 0 5 0;
#P connect 10 1 5 0;
#P connect 10 0 5 0;
#P connect 8 0 5 0;
#P connect 5 0 11 0;
#P connect 11 0 12 0;
#P connect 3 0 4 0;
#P connect 12 0 4 0;
#P connect 1 0 0 0;
#P connect 0 0 9 1;
#P connect 0 1 13 0;
#P pop;

paste as new patch
——————
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 37 140 137 196617 notifier.mxt notifier2 3000;
#P newex 37 91 138 196617 notifier.mxt notifier1 2000;
#P message 512 135 84 196617 remove notifier2;
#P message 484 115 70 196617 add notifier2;
#P message 469 92 84 196617 remove notifier1;
#P message 441 72 70 196617 add notifier1;
#P newex 441 207 65 196617 listener.mxt;
#P message 345 135 84 196617 remove notifier2;
#P message 317 115 70 196617 add notifier2;
#P message 302 92 84 196617 remove notifier1;
#P message 274 72 70 196617 add notifier1;
#P newex 274 207 67 196617 listener.mxt;
#P comment 273 46 242 196617 Add/remove notifiers and watch the Max window…;
#P connect 10 0 6 0;
#P connect 9 0 6 0;
#P connect 8 0 6 0;
#P connect 7 0 6 0;
#P connect 2 0 1 0;
#P connect 3 0 1 0;
#P connect 4 0 1 0;
#P connect 5 0 1 0;
#P window clipboard copycount 13;


March 31, 2007 | 1:44 am

Quote: lawrence casserley wrote on Sat, 31 March 2007 03:24
—————————————————-
> the function called in this way isn’t
> really any different to an abstraction inserted into the patch
> inline, and will in most cases be less efficient.

For most usual purposes, it certainly will, though if the alternate "static" class/object/method only needs to return a result to one caller at a time (which will always be true as send/receive are synchronous?), the overhead involved in parsing the "caller" argument and setting a forward destination for the returned result is not huge.

But imagine a VERY complex patch that you want to use as an "inline function" in the normal Max way, instantiated a VERY large number of times. Imagine that this also needs to load some resource from disk and manipulate it so each instantiation’s copy of the resource is slightly customized. That’s going to take a LONG time to load all those instances, and possibly use a lot of memory.

I see this as a situation where a single static object providing public utility methods as we have outlined might be very advantageous – not least in avoiding the "why does it take 5 minutes to start up" complaints from users…


March 31, 2007 | 2:57 am

Quote: johnpitcairn wrote on Sat, 31 March 2007 13:44
—————————————————-
> and manipulate it so each instantiation’s copy of the resource is
> slightly customized.

Uh, ignore that bit please, that would likely need to be done in separate instantiations anyway … my point is that I’ve been down this route, where my load times were getting up around 2 minutes on a 1GHz G4 due to a zillion instantiations of an abstraction. Too long.

So I now load the abstraction just once, and send into it providing a unique return address for the result. I hadn’t been thinking of it as a static class with public methods until this thread ;-)


March 31, 2007 | 4:25 am

Well, Im right with you, however I think its a real shame that we
have to work around those sorts of issues though – even relatively
simple abstractions loaded multiple times seem to be an issue, esp
with load times/close times.

Tis a shame.

On Mar 30, 2007, at 10:57 PM, John Pitcairn wrote:

> Uh, ignore that bit please, that would likely need to be done in
> separate instantiations anyway … my point is that I’ve been down
> this route, where my load times were getting up around 2 minutes on
> a 1GHz G4 due to a zillion instantiations of an abstraction. Too long.

v a d e //

http://www.vade.info
abstrakt.vade.info


March 31, 2007 | 2:09 pm

On 31 Mar 2007, at 01:48, John Pitcairn wrote:

> Yes indeed. Send/receive can get a beginner into a lot of trouble…

But then so can a lot of other things in Max, or most any system for
that matter. Designing the system so that beginners are prevented
from making mistakes sounds pretty limiting to me.

Best

L

Lawrence Casserley – lawrence@lcasserley.co.uk
Lawrence Electronic Operations – http://www.lcasserley.co.uk
Colourscape Music Festivals – http://www.colourscape.org.uk


April 1, 2007 | 1:32 pm

Will this approach work if the abstraction contains timing functions
such as metro, line, delay or pipe, or is it limited to work only with
abstractions that provide nothing but instant feedback?

Also, are you able to use this approach for abstractions containing DSP
processing?

Best,
Trond

John Pitcairn wrote:
> Quote: johnpitcairn wrote on Sat, 31 March 2007 13:44
> —————————————————-
>> and manipulate it so each instantiation’s copy of the resource is
>> slightly customized.
>
> Uh, ignore that bit please, that would likely need to be done in separate instantiations anyway … my point is that I’ve been down this route, where my load times were getting up around 2 minutes on a 1GHz G4 due to a zillion instantiations of an abstraction. Too long.
>
> So I now load the abstraction just once, and send into it providing a unique return address for the result. I hadn’t been thinking of it as a static class with public methods until this thread ;-)
>


April 1, 2007 | 3:56 pm

I think the cases we have been discussing mainly focus around patchers
as repositories of data. Using OO methodology to access and organize
that data in such a way that makes it easy an efficient.
As far as DSP goes, I think OO would not help much other than being
able to have classes that encapsulate functionality, which is what you
are probably doing already.

Anthony

—– Original Message —–
From: "Trond Lossius"
To:
Sent: Sunday, April 01, 2007 8:32 AM
Subject: Re: [maxmsp] Re: Re: How to apply oo within Max

> Will this approach work if the abstraction contains timing functions
> such as metro, line, delay or pipe, or is it limited to work only with
> abstractions that provide nothing but instant feedback?
>
> Also, are you able to use this approach for abstractions containing DSP
> processing?
>
> Best,
> Trond
>
>
>
> John Pitcairn wrote:
> > Quote: johnpitcairn wrote on Sat, 31 March 2007 13:44
> > —————————————————-
> >> and manipulate it so each instantiation’s copy of the resource is
> >> slightly customized.
> >
> > Uh, ignore that bit please, that would likely need to be done in
separate instantiations anyway … my point is that I’ve been down this
route, where my load times were getting up around 2 minutes on a 1GHz G4 due
to a zillion instantiations of an abstraction. Too long.
> >
> > So I now load the abstraction just once, and send into it providing a
unique return address for the result. I hadn’t been thinking of it as a
static class with public methods until this thread ;-)
> >


April 1, 2007 | 8:12 pm

Ok, I think I got something nice here, inspired by the recent posts in this thread.

This is a possible way to define an object with its methods and let them communicate according to OO principles.

Objects reference each other by keeping track of each others unique ID’s. The ‘call’ abstraction retrieves the id of the target object and together with the ‘object’ abstraction, which generates a unique id, manages calling methods and delivering its return value.

Have a look at how ‘call’ gets info from its parent object in the updateUI method inside the filterGui object.

Please let me know what you think. Best,
Mattijs

— save as ‘object’

#N comlet id;
#P outlet 27 77 15 0;
#P newex 85 163 64 9109513 prepend send;
#P newex 44 163 39 9109513 forward;
#P newex 44 98 44 9109513 zl ecils 1;
#P newex 59 77 57 9109513 prepend set;
#P newex 44 77 14 9109513 r;
#N comlet return values;
#P inlet 44 143 15 0;
#N comlet method calls;
#P outlet 44 122 15 0;
#P newex 27 50 71 9109513 loadmess $0-id;
#P connect 5 1 7 0;
#P connect 0 0 8 0;
#P connect 0 0 4 0;
#P connect 2 0 6 0;
#P connect 7 0 6 0;
#P connect 5 0 1 0;
#P connect 3 0 5 0;
#P connect 4 0 3 0;

— save as ‘call’

#P message 141 203 14 9109513 0;
#P newex 141 181 57 9109513 prepend set;
#P newex 110 136 43 9109513 sel done;
#P newex 110 157 45 9109513 pv $1-ID;
#P outlet 24 229 15 0;
#P newex 24 206 37 9109513 r $0-ID;
#P newex 23 87 64 9109513 append $0-ID;
#P newex 23 66 54 9109513 prepend $2;
#N comlet arguments;
#P inlet 23 27 15 0;
#P newex 63 115 57 9109513 patcherargs;
#P newex 63 180 74 9109513 sprintf send %s;
#P newex 23 180 39 9109513 forward;
#P connect 10 0 11 0;
#P connect 8 0 1 0;
#P connect 8 0 10 0;
#P connect 9 0 8 0;
#P connect 2 1 9 0;
#P connect 6 0 7 0;
#P connect 5 0 0 0;
#P connect 1 0 0 0;
#P connect 4 0 5 0;
#P connect 3 0 4 0;

— main patch (note: has to be loaded to trigger loadbangs)

#P newex 64 55 54 9109513 pv filter-ID;
#P newex 27 33 101 9109513 loadmess 400. 1.62 1.;
#N vpatcher 324 55 820 306;
#P window setfont "Sans Serif" 9.;
#P comment 245 147 110 9109513 trigger gui update;
#P flonum 193 129 48 9 0 0 0 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P button 193 148 15 0;
#P newex 193 166 99 9109513 call filterGui updateUI;
#N comlet id;
#P outlet 18 46 15 0;
#P newex 156 60 71 9109513 unpack 0. 0. 0.;
#N comlet constructor arguments;
#P inlet 156 42 15 0;
#P newex 104 167 68 9109513 pv filterGui-ID;
#N vpatcher 285 341 702 774;
#P window setfont "Sans Serif" 9.;
#P user filtergraph~ 68 116 256 128 139 9 20. 20000. 0.0625 16. 0 1 1 0 0 1 1;
#X frgb 170 170 170;
#X brgb 209 209 209;
#X rgb2 0 0 0;
#X rgb3 130 130 130;
#X rgb4 0 0 0;
#X rgb5 76 108 172;
#X rgb6 210 74 54;
#X rgb7 255 22 22;
#X linmarkers 5512.5 11025. 16537.5;
#X logmarkers 10. 100. 1000. 10000.;
#X nfilters 1;
#X setfilter 0 1 1 0 0 632. 1. 1.62 0. 0. 0. 0. 0. 0.;
#X done;
#P window linecount 1;
#P newex 266 53 61 9109513 pv parent-ID;
#N comlet constructor arguments;
#P inlet 266 34 15 0;
#N comlet id;
#P outlet 18 39 15 0;
#P newex 35 285 55 9109513 pv this-IDx;
#P newex 35 34 33 9109513 object;
#N vpatcher 715 340 990 560;
#N comlet to filtergraph;
#P outlet 49 120 15 0;
#P window setfont "Sans Serif" 9.;
#P newex 20 69 109 9109513 call parent getParamList;
#N comlet return value;
#P outlet 22 121 15 0;
#P newex 20 48 70 9109513 route updateUI;
#N comlet method calls;
#P inlet 20 31 15 0;
#P connect 0 0 1 0;
#P connect 1 0 3 0;
#P connect 3 0 4 0;
#P pop;
#P newobj 72 34 54 9109513 p updateUI;
#B color 12;
#P window linecount 3;
#P comment 93 285 96 9109513 < == should somehow be seperated from this-ID in parent level;
#P connect 2 0 4 0;
#P connect 1 0 2 0;
#P connect 2 0 3 0;
#P connect 2 1 1 0;
#P connect 1 1 7 5;
#P connect 5 0 6 0;
#P pop 1;
#P newobj 53 167 49 9109513 p filterGui;
#B color 1;
#P newex 53 138 39 9109513 pv gain;
#B color 7;
#P newex 53 116 27 9109513 pv q;
#B color 7;
#P newex 53 94 48 9109513 pv cutoff;
#B color 7;
#P newex 53 65 50 9109513 pv this-ID;
#P newex 35 42 33 9109513 object;
#N vpatcher 15 246 251 469;
#P window setfont "Sans Serif" 9.;
#P newex 22 122 61 9109513 pack 0. 0. 0.;
#P newex 22 76 19 9109513 t b;
#P newex 115 99 27 9109513 pv q;
#P newex 73 99 39 9109513 pv gain;
#P newex 22 99 48 9109513 pv cutoff;
#N comlet return value;
#P outlet 22 143 15 0;
#P newex 22 54 87 9109513 route getParamList;
#N comlet method calls;
#P inlet 22 37 15 0;
#P connect 0 0 1 0;
#P connect 1 0 6 0;
#P connect 6 0 3 0;
#P connect 3 0 7 0;
#P connect 7 0 2 0;
#P connect 4 0 7 1;
#P connect 5 0 7 2;
#P connect 6 0 4 0;
#P connect 6 0 5 0;
#P pop;
#P newobj 72 42 71 9109513 p getParamList;
#B color 12;
#P comment 245 129 110 9109513 change cutoff value and;
#P connect 2 0 11 0;
#P connect 1 0 2 0;
#P fasten 2 0 3 0 40 63 58 63;
#P connect 10 0 4 0;
#P connect 14 0 4 0;
#P connect 10 1 5 0;
#P connect 10 2 6 0;
#P fasten 2 0 7 0 40 164 58 164;
#P connect 2 1 1 0;
#P connect 7 0 8 0;
#P connect 9 0 10 0;
#P connect 13 0 12 0;
#P pop 1;
#P newobj 27 55 35 9109513 p filter;
#B color 1;
#P window linecount 3;
#P user com 132 32 100 9109513 24;
#K set 0 25196 30053 14880 28005 29800 28516 29472 3431 29285 25966 14880 30305 29289 24930 27749 29472 3426 29295 30574 14880 28514 27237 25460 29440;
#K end;
#P connect 2 0 1 0;
#P connect 1 0 3 0;


April 1, 2007 | 8:44 pm

Hm the patch was posted on pc, I just opened the patch on a mac and the patches look crappy. Isn’t this discrimination? Pc users are effectively banned from the communitiy this way. Who’s going to take an ugly-looking patch serious? ;)

Anyways, Cmd+J will resolve most of the uglyness.

Mattijs


April 1, 2007 | 8:55 pm

Hrm. This is definitely interesting Mattijs. Ill have to take a
really close look at this methodology and see how applicable it is in
real world usage. The patch is a little hard to follow even though it
uses so few objects. This is very very interesting stuff, and could
be very useful. Its a shame we have to spend so much time working
around Maxs’ …. inefficient (for lack of a better word) handling of
many abstractions.

On Apr 1, 2007, at 4:12 PM, Mattijs Kneppers wrote:

v a d e //

http://www.vade.info
abstrakt.vade.info


April 1, 2007 | 9:27 pm

Quote: vade wrote on Sun, 01 April 2007 22:55
—————————————————-
> Hrm. This is definitely interesting Mattijs. Ill have to take a
> really close look at this methodology and see how applicable it is in
> real world usage. The patch is a little hard to follow even though it
> uses so few objects. This is very very interesting stuff, and could
> be very useful.

Cool, let me know your findings. I’ll start trying it in real life situations as well.

> Its a shame we have to spend so much time working
> around Maxs’ …. inefficient (for lack of a better word) handling of
> many abstractions.

I totally know what you’re saying. In fact I had to strip a big patch from all send/receive wrapper abstractions I made because the load time got unmanageable. 3 mins on a 2,5 GHz Quad. Debug that :p ..

At the moment I do everything with pattrs (handing in quite some flexibility compared with my abstractions), but I recently figured out that they cause quite some performance loss (as posted in another thread). Hopefully this new idea (which does actual communication with send/receives) can solve the problem.

Best,
Mattijs

>
> On Apr 1, 2007, at 4:12 PM, Mattijs Kneppers wrote:
>
>
> v a d e //
>
> http://www.vade.info
> abstrakt.vade.info
>
>
>
>
>
>
—————————————————-


April 1, 2007 | 10:44 pm

Quote: Trond Lossius wrote on Mon, 02 April 2007 01:32
—————————————————-
> Will this approach work if the abstraction contains timing
> functions such as metro, line, delay or pipe, or is it limited
> to work only with abstractions that provide nothing but
> instant feedback?

Metro might be problematic, unless all you want to do is send some regular result to multiple (registered) listeners, as per my example. Registering/deregistering listeners on the fly shouldn’t be an issue.

For pipe, you’d need to maintain a FIFO list of the caller IDs in order to send the result back to the correct caller, but I don’t see anything technically too troublesome in that, given one input = one output.

Line and delay can’t have multiple inputs processing simultaneously anway (as you can for pipe), so that makes them inherently unsuitable for this approach unless you can guarantee only one caller at a time (which seems unlikely).

> Also, are you able to use this approach for abstractions
> containing DSP processing?

I don’t use DSP at all, so I won’t venture into any speculation here…


April 1, 2007 | 11:22 pm

Quote: vade wrote on Mon, 02 April 2007 08:55
—————————————————-
> The patch is a little hard to follow even though it
> uses so few objects.
—————————————————-

Agreed, I think I see the intent but a few more comments would certainly be helpful. When I have time I’ll try building something using object and call to gain a better understanding of how it’s implemented. It does look like we’re jumping through a lot of hoops…


April 1, 2007 | 11:48 pm

Quote: johnpitcairn wrote on Mon, 02 April 2007 10:44
—————————————————-
> For pipe, you’d need to maintain a FIFO list of the caller IDs
—————————————————-

Second thought: no, you’d just use a separate pipe for the caller ID using the same parameters. Since pipe can remember the delay time as well as the value for each input, you’ll be OK to call the process with a different delay time from a different ID, passing in value, ID, delay, ie:

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 116 106 50 196617 click 2nd;
#P message 116 129 70 196617 4 1006 1000;
#P newex 117 221 70 196617 pipe 0;
#P newex 117 273 76 196617 print returnID;
#P newex 38 273 63 196617 print return;
#P newex 38 181 88 196617 unpack 0 0 0;
#P message 38 129 70 196617 9 1007 5000;
#P newex 38 221 70 196617 pipe 0;
#P comment 38 106 50 196617 click 1st;
#P connect 3 2 1 1;
#P connect 3 2 6 1;
#P connect 6 0 5 0;
#P connect 1 0 4 0;
#P connect 7 0 3 0;
#P connect 3 0 1 0;
#P connect 3 1 6 0;
#P connect 2 0 3 0;
#P window clipboard copycount 9;


April 2, 2007 | 8:41 am

Arne Eigenfeldt schrieb:
> I agree, with a caveat.

I agree even without caveat…

> I store data into value objects for use (as global variables) by other
> patchers/functions. But when I need instantaneous notification, such
> as a bang, I need to use send/receive pairs.

or use a pattr/named_object and a pattrforward in case you need a single
receive somewhere in you patcher hierarchy. If you need it global, there
is nothing wrong with global receives…

> But the problem, in my mind, is not knowing what will happen at the
> other end. A single bang sent "blindly" can inadvertently trigger a
> multitude of actions if I’m not careful.

But that "If you’re not careful" will be true for any language
construction. Its more about how easy it is to be careful – Its much
easier since pattr…

If you use your own name space like within pattr, for example you place
a [pattrmarker MyGloriousPatch] into your main master patch and
consequently name all send/receives like [s MyGloriousPatch.MyGlobal].
You should be on the safe side. You can access local and global
variables at your will, and its pretty unlikely, that a 3rd-party
abstraction will use the same receive names…

Not being forced to be careful, is very helpful for small little
gadgets, as you have to type less. If your patch grows bigger, its just
your own responsibility to stay careful. It might require to rename send
and receives, an easy task with Textwrangler or alike…

To be able to rename elements recursively in a big patch would be great
though – (just dreaming, I am happy with Texwrangler… ;-)

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 2, 2007 | 8:42 am

Anthony Palomba schrieb:
> Although come to think of it, is it really a good idea to have a global
> object that I can call in to from any place? Or would it be more OO
> like to instantiate an object and use inlets to execute functions?

A receive and a pattr are kind of inlets within a subpatcher…

And if your function is burried deep in the patcher hierarchy, cords are
a pain and make the whole thing unreadable/undebugable. If oo forces you
to bad patching I would refuse it…

Come to think of it, is it really a bad idea to have global
functions/variables?

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 2, 2007 | 9:17 am

You’re right. I’ll make a new version with more comments probably tomorrow evening (+1 GMT). I’ll also do it on a mac, that should make a big difference in readability :p

Mattijs

Quote: johnpitcairn wrote on Mon, 02 April 2007 01:22
—————————————————-
> Quote: vade wrote on Mon, 02 April 2007 08:55
> —————————————————-
> > The patch is a little hard to follow even though it
> > uses so few objects.
> —————————————————-
>
> Agreed, I think I see the intent but a few more comments would certainly be helpful. When I have time I’ll try building something using object and call to gain a better understanding of how it’s implemented. It does look like we’re jumping through a lot of hoops…
>
>
—————————————————-


April 2, 2007 | 9:24 am

Quote: Stefan Tiedje wrote on Mon, 02 April 2007 10:41
—————————————————-

> To be able to rename elements recursively in a big patch would be great
> though – (just dreaming, I am happy with Texwrangler… ;-)
>

Absolutely. Refactoring; any eclipse users here? That is so powerful..

Mattijs


April 2, 2007 | 9:29 am

Quote: Stefan Tiedje wrote on Mon, 02 April 2007 20:42
—————————————————-
> Come to think of it, is it really a bad idea to have global
> functions/variables?
—————————————————-

Yes/no/maybe…

Seems to me that in OO-design the idea of a static class vending public methods and constants allows "global" methods/constants without all the dangers of non-OO globals. You never instantiate an instance of the class, just call the class methods or retrieve the constants, and there aren’t any class variables – or maybe that’s just a C++/ObjC procedural concession? Heck, I’m a designer, Computer Science graduates feel free to flame me here…

I’m beginning to think that a very little (like < 20 lines) Java/JavaScript sprinkled over what we're doing might be extremely advantageous - if it weren't for the horrendous per-message overhead between Max and Java/JavaScript.

Durrr … thinking …

PS: Can we stop talking about "functions" and use "methods" instead, as an indication that we’re trying to adhere to OO principles? Then at least we have discrete names for two different things … (OK, I know, JavaScript, function, new, prototype, yaaah).

Uh … is this making sense? I’m on deadline…


April 2, 2007 | 9:52 am

Quote: johnpitcairn wrote on Mon, 02 April 2007 11:29
—————————————————-
> Quote: Stefan Tiedje wrote on Mon, 02 April 2007 20:42
> —————————————————-
> > Come to think of it, is it really a bad idea to have global
> > functions/variables?
> —————————————————-
>
> Yes/no/maybe…

Yes. Except for statics.

>
> Seems to me that in OO-design the idea of a static class vending public methods and constants allows "global" methods/constants without all the dangers of non-OO globals. You never instantiate an instance of the class, just call the class methods or retrieve the constants, and there aren’t any class variables – or maybe that’s just a C++/ObjC procedural concession? Heck, I’m a designer, Computer Science graduates feel free to flame me here…

I think your example is exactly what a static class should be in Max. I definitly like your implementation.

Of course the core of oo lies in the non-static concepts. A static class in max is in fact a collection of global methods that can’t depend on external variables and have a smart return system. We should definitly include the static class in the ‘oo within max’ examples. It’s a typical example of a way of thinking that you don’t run into automatically when working with max, but can have huge advantages, especially in load time and readability.

>
> I’m beginning to think that a very little (like < 20 lines) Java/JavaScript sprinkled over what we're doing might be extremely advantageous - if it weren't for the horrendous per-message overhead between Max and Java/JavaScript.

Yeah, as soon as we have the ideal conceptual way of working with oo in max, perhaps we can remake some stuff in javascript. Or maybe even earlier. I agree though about the max/javascript bridge. Would be another good reason to do some empirical testing.

>
> Durrr … thinking …
>
> PS: Can we stop talking about "functions" and use "methods" instead, as an indication that we’re trying to adhere to OO principles? Then at least we have discrete names for two different things … (OK, I know, JavaScript, function, new, prototype, yaaah).

Agreed. "method" from now on, I promise. :)

Mattijs


April 2, 2007 | 10:53 am

So: I’m thinking about abstractions for "class" (non-static), with objects therein: "var" and "method", with appropriate OO behaviour, within reason. If this works out, the idea is that C++/ObjC/Java concepts are broadly usable (especially ObjC, with its explicit parameter:value arguments), with little conceptual translation.

Also possibly "constructor" and "destructor" as specific loadtime-only subclasses of "method".

Any classes (uh, objects, instantiations of file-abstractions) defined as "static" need to be guaranteed that a single instance per application/runtime will be instantiated. These vend out constants and global methods – a constant is simply a [v] that is set at runtime and cannot be changed. So any object defined with attribute "@static 1" needs to be checked for prior instantiations, and an error message posted if the object name exists. Hmm.

Exceptions to OO-standard: inheritance – has no sensible analogue that I can see in Max, ie you can’t programaticaly (script/js/Java) specify extension and overriding of a class/abstraction without enormous trouble (?) – classes need to be file-based with manual modifications saved as a new file (class). But I don’t see that as a bad thing, especially. Anyone?

Bottom line: this needs to be as easy to use as OO in C++, Java, ObjC, JavaScript, and ot incur huge overhad, or what’s the point?


April 2, 2007 | 10:56 am

What sort of shit is an edit-timeout of 1 minute??? Where did you guys get this forum software?? C’mon…


April 2, 2007 | 11:05 am

Quote: Mattijs wrote on Mon, 02 April 2007 21:52
—————————————————-
> I agree though about the max/javascript bridge. Would be another good reason to do some empirical testing.
—————————————————-

I’ve done it. The translation between JavaScript – or Java, (presumably via JINI?) – and native C Max object in/out is prohibitively expensive for use with realtime-data, whether MIDI or (definitely) audio, unless the JavaScript/Java object does an enormous amount of processing for each event in/out.

JavaScript/Java objects interfaced with native Max are very nice for file i/o, config, preferences, UI or system calls, however…


April 2, 2007 | 11:19 am

Quote: Mattijs wrote on Mon, 02 April 2007 21:52
—————————————————-
> I think your example is exactly what a static class should be in Max. I definitly like your implementation.
—————————————————

Ta. LC Xmu makes a lot of use of this sort of thing, though I wasn’t especially thinking OO as I developed it (don’t look at the processing core, eek!).

To my mind, there’s still a problem in that you can define a "static" class via patcher or instantiated abstraction – the patcher is akin to a class defined "inline" (as per inlined function), which while permissable in C++ etc strikes me as bloody dubious from an OO perspective.

I’m having an internal argument: should ALL patchers be saved to disk, a la .h/.cpp files? Is [p] illegal in the OO context we’re talking about? Or is [p] a static class? In which case, should [p] include a mechanism to prevent more than 1 instantiation (easy enough given a unique name)? Or should [p] be overridden somehow in the search path to prevent its use? Hmm…


April 2, 2007 | 11:50 am

Quote: johnpitcairn wrote on Mon, 02 April 2007 23:19
—————————————————-
> In which case, should [p] include a mechanism to prevent more than 1 instantiation
—————————————————-

Hmmm. Patcher [p] is not a class in any reasonable sense(?). [classname @static 1] should include a mechanism to prevent multiple instantiations (post error message), where classname = abstraction on-disk name. I’d be inclined to override [p] as an abstraction, requiring a unique @name attribute or it self-removes with load failure error?


April 2, 2007 | 12:18 pm

Quote: lists@lowfrequency.or wrote on Fri, 30 March 2007 23:53
—————————————————-
> i find jitter in general a bit more OO, with it’s "@ttributes"
> thatmake figuring out the name of your arguments to an object so
> much easier

The "@" argument syntax can be used in saved Max abstractions and [p] subpatchers, via the [patcherargs] object, unless I’m missing some limitation. Very reminiscent of the excellent Objective-C argument syntax, if I may say so…


April 2, 2007 | 1:23 pm

Just tried this. In a subpatcher like

p thing 440 @one 1

"thing" is interpreted as the first of two regular arguments and not as the
intended name of the subpatcher. Not necessarily a problem, more of a
detail. Potentially quite useful. However, saving it as patcher yields
slightly different results on loading. Only 440 appears as a rehular
argument.

I point this out because, like some other maxers, I often develop an
abstraction as a subpatcher first. When it works, I save it into my own
library of abstractions.

Cheers
Gary Lee Nelson
Oberlin College
http://www.timara.oberlin.edu/GaryLeeNelson

On 4/2/07 8:18 AM, "John Pitcairn" wrote:

>
> Quote: lists@lowfrequency.or wrote on Fri, 30 March 2007 23:53
> —————————————————-
>> i find jitter in general a bit more OO, with it’s "@ttributes"
>> thatmake figuring out the name of your arguments to an object so
>> much easier
>
> The "@" argument syntax can be used in saved Max abstractions and [p]
> subpatchers, via the [patcherargs] object, unless I’m missing some limitation.
> Very reminiscent of the excellent Objective-C argument syntax, if I may say
> so…


April 2, 2007 | 1:45 pm

jln schrieb:
> The main problem I see (at least in my example) is related to
> performance, as the global receive has to keep track of function
> calls orders. So I’m afraid the process can be really slowed down in
> some situations.

Most functions, are independent of other states of a patch, then I just
instantiate another subpatcher as my function with ins/outs locally and
I’m done. Another aproach is the use of a named coll, var or even a
buffer~. If I bang or dump it, it will output only locally. For example,
if I need a function which will output the last ten Midi notes which had
been played, I have a subpatcher, which fills 10 entries of a coll. That
coll would be accessible everywhere, and no "keep track of function call
orders is necessary.
Again, to think in terms of information flow seems to me a much clearer
way of thinking. And there are plenty of ways to pass and/access
information within Max…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 2, 2007 | 2:51 pm

I’ll add jitter matrices to the list of data structures. They are very
useful for implementing multidimensional processes like markov chains.
Limited to numbers however.

On 4/2/07 9:45 AM, "Stefan Tiedje" wrote:

> jln schrieb:
>> The main problem I see (at least in my example) is related to
>> performance, as the global receive has to keep track of function
>> calls orders. So I’m afraid the process can be really slowed down in
>> some situations.
>
> Most functions, are independent of other states of a patch, then I just
> instantiate another subpatcher as my function with ins/outs locally and
> I’m done. Another aproach is the use of a named coll, var or even a
> buffer~. If I bang or dump it, it will output only locally. For example,
> if I need a function which will output the last ten Midi notes which had
> been played, I have a subpatcher, which fills 10 entries of a coll. That
> coll would be accessible everywhere, and no "keep track of function call
> orders is necessary.
> Again, to think in terms of information flow seems to me a much clearer
> way of thinking. And there are plenty of ways to pass and/access
> information within Max…
>
> Stefan

Cheers
Gary Lee Nelson
Oberlin College
http://www.timara.oberlin.edu/GaryLeeNelson


April 2, 2007 | 3:23 pm

I am also using jit.cellblock a lot these days. Perhaps in a future version
of Max perhaps jit.cellblock can be named like coll, table, buffer~ and
jit.matrix.

On 4/2/07 10:51 AM, "Gary Lee Nelson" wrote:

> I’ll add jitter matrices to the list of data structures. They are very
> useful for implementing multidimensional processes like markov chains.
> Limited to numbers however.
>
>
> On 4/2/07 9:45 AM, "Stefan Tiedje" wrote:
>
>> jln schrieb:
>>> The main problem I see (at least in my example) is related to
>>> performance, as the global receive has to keep track of function
>>> calls orders. So I’m afraid the process can be really slowed down in
>>> some situations.
>>
>> Most functions, are independent of other states of a patch, then I just
>> instantiate another subpatcher as my function with ins/outs locally and
>> I’m done. Another aproach is the use of a named coll, var or even a
>> buffer~. If I bang or dump it, it will output only locally. For example,
>> if I need a function which will output the last ten Midi notes which had
>> been played, I have a subpatcher, which fills 10 entries of a coll. That
>> coll would be accessible everywhere, and no "keep track of function call
>> orders is necessary.
>> Again, to think in terms of information flow seems to me a much clearer
>> way of thinking. And there are plenty of ways to pass and/access
>> information within Max…
>>
>> Stefan
>
>
> Cheers
> Gary Lee Nelson
> Oberlin College
> http://www.timara.oberlin.edu/GaryLeeNelson
>
>

Cheers
Gary Lee Nelson
Oberlin College
http://www.timara.oberlin.edu/GaryLeeNelson


April 2, 2007 | 3:48 pm


April 2, 2007 | 4:40 pm


April 2, 2007 | 10:06 pm


April 3, 2007 | 9:59 pm

As promised, the OO example, slightly modified, ‘mac’ified and commented:

http://www.arttech.nl/OO%20example%20Mattijs%20070403.zip

Let me know if something isn’t clear and of course if you have ideas for improvements.

Best,
Mattijs


April 10, 2007 | 7:04 am

Mattijs Kneppers schrieb:
> Hm the patch was posted on pc, I just opened the patch on a mac and
> the patches look crappy. Isn’t this discrimination? Pc users are
> effectively banned from the communitiy this way. Who’s going to take
> an ugly-looking patch serious? ;)

I always thought it is discrimination of the Mac users, they have to
repair all those ugly patches… ;-)

Just make all your object boxes a bit longer… always…

But a comment to your oo method:

On first sight it seems complicated. But there are circumstance where
this way of communicating does make sense. I imagine a UI for a filter
which controls several filters in a mixer. Then you need to
differentiate these. I did this with pattr and forward in the past.

But even if there is from time to time a need for complex communication,
it is not practical to use that for simple communication.

Any standardized methods have to solve the simple problems in a simple
way, and have to simplify the complex stuff. And they should be used
always then… (as patching style). The only project I can see which
would come close to this is still Jamoma. They have a standardized
communication structure. Else wise I would stick to pattr….
Or just subpatchers with inlet for calling the function and outlet for
return. If the function you call is very complex, lets say a database
and you need to avoid several instantiations of it, create a subpatcher
which communicates to the database and use several instantiations of
that calling subpatcher. And as I mentioned before, this could be a
simple coll or v…

Stefan

#P window setfont "Sans Serif" 9.;
#P number 50 248 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P number 50 158 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 4;
#N vpatcher 20 74 391 422;
#P window setfont "Sans Serif" 9.;
#P newex 246 89 46 196617 prepend send;
#P inlet 246 66 15 0;
#P window linecount 1;
#P newex 102 196 70 196617 r 1234-ID;
#P window linecount 0;
#P newex 102 89 97 196617 prepend 1234-ID;
#P newex 102 128 81 196617 forward $1;
#P outlet 102 225 15 0;
#P inlet 102 67 15 0;
#P connect 0 0 3 0;
#P connect 3 0 2 0;
#P fasten 6 0 2 0 251 122 107 122;
#P connect 4 0 1 0;
#P connect 5 0 6 0;
#P pop;
#P newobj 50 188 114 196617 p anotherobject which communicates to the
same central single instance;
#P window linecount 1;
#N vpatcher 20 74 477 433;
#P window setfont "Sans Serif" 9.;
#N vpatcher 30 89 630 489;
#P window setfont "Sans Serif" 9.;
#P newex 50 50 50 196617 * 2.;
#P inlet 50 30 15 0;
#P outlet 50 72 15 0;
#P connect 1 0 2 0;
#P connect 2 0 0 0;
#P pop;
#P newobj 193 183 75 196617 p do something;
#P newex 289 170 50 196617 prepend send;
#P newex 193 224 70 196617 forward;
#P window linecount 1;
#P newex 194 146 57 196617 zl slice 1;
#P window linecount 0;
#P newex 289 147 57 196617 zl slice 1;
#P newex 194 111 89 196617 r $1;
#P connect 2 1 5 0;
#P connect 5 0 3 0;
#P connect 4 0 3 0;
#P connect 0 0 2 0;
#P connect 0 0 1 0;
#P connect 1 0 4 0;
#P pop;
#P newobj 246 109 81 196617 p myGlobject;
#P number 50 116 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P number 50 26 35 9 0 0 0 3 0 0 0 221 221 221 222 222 222 0 0 0;
#P window linecount 3;
#N vpatcher 20 74 391 422;
#P window setfont "Sans Serif" 9.;
#P newex 246 89 46 196617 prepend send;
#P inlet 246 66 15 0;
#P window linecount 1;
#P newex 102 196 70 196617 r $0-ID;
#P window linecount 0;
#P newex 102 89 79 196617 prepend $0-ID;
#P newex 102 128 81 196617 forward $1;
#P outlet 102 225 15 0;
#P inlet 102 67 15 0;
#P connect 0 0 3 0;
#P connect 3 0 2 0;
#P fasten 6 0 2 0 251 122 107 122;
#P connect 4 0 1 0;
#P connect 5 0 6 0;
#P pop;
#P newobj 50 56 114 196617 p myobject which communicates to a central
single instance;
#P connect 5 0 4 0;
#P connect 4 0 6 0;
#P connect 0 0 2 0;
#P connect 1 0 0 0;
#P window clipboard copycount 7;


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 10, 2007 | 7:04 am

vade schrieb:
> The patch is a little hard to follow even though it uses so few
> objects.

That’s why I would suspicious of this as a useful technique. Anything
which is hard to follow (and you are an experienced Max user), is not a
considerable or good solution in my eyes.

> Its a shame we have to spend so much time working around Maxs’ ….
> inefficient (for lack of a better word) handling of many
> abstractions.

It took me also quite a while to find out that it was my own lack and
inefficiency… ;-)
One of the big advantages of Max is its simplicity, if I need other
programming styles, I need to find my own way to do so. Its not so much
working around a lack of Max, its finding your own efficient patching style.

That’s why this discussion is important. It needs a lot of different
views and perspectives to get a picture…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 10, 2007 | 7:04 am

Mattijs Kneppers schrieb:
> At the moment I do everything with pattrs (handing in quite some
> flexibility compared with my abstractions), but I recently figured
> out that they cause quite some performance loss (as posted in another
> thread).

I would not be concerned too much with the performance loss. The
advantages outperform the loss by far. The only efficiency which is
really important is the patching efficiency. Anything you can gain by
"hand optimization" is faster gained by waiting for the next faster
computer generation…

I remember, that I had that problem of very long load times as well, but
this was very long ago. Maybe my general patching style just solved it
without notice…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 10, 2007 | 7:04 am

John Pitcairn schrieb:
> What sort of shit is an edit-timeout of 1 minute??? Where did you
> guys get this forum software?? C’mon…

No timeout with thunderbird ever, I write even in the subway without
connection…. ;-)

Forums are for rare lurkers… ;-)

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 10, 2007 | 7:05 am


April 10, 2007 | 7:05 am

John Pitcairn schrieb:
> So any object defined with attribute "@static 1" needs to be checked
> for prior instantiations, and an error message posted if the object
> name exists. Hmm.

The only place I wanted to have this kind of notification that another
instance is loaded was in my copyright abstractions. I wanted the
copyright notice in the Max window to show up only once, and not with
every instantiation. That technique could be used for this kind of task.
But that would not prevent loading the instance, it would only prevent
printing the message…
And an instance which would kill itself on load was the most solid
method to crash Max… (Memory isn’t too much of an issue nowadays)

But the idea of a "static" instantiation of a class is a very
"oo-centric" way of thinking, there is no need to bother I think. And
the static term was much more used as reference to global variables…

> Exceptions to OO-standard: inheritance – has no sensible analogue
> that I can see in Max, ie you can’t programaticaly (script/js/Java)
> specify extension and overriding of a class/abstraction without
> enormous trouble (?) – classes need to be file-based with manual
> modifications saved as a new file (class). But I don’t see that as a
> bad thing, especially. Anyone?

I have no problem with that. What I usually do, if I need to enhance an
existing abstraction, add some code to interpret new messages. Basically
add a parameter to the route object which is very often placed as first
object in my patches to route messages…

It will almost never break old patches…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 10, 2007 | 11:09 pm

My current thinking:

CLASS

A – an abstraction saved on disk

B – a patcher – in which case it’s only ever a single instance, even if simply duplicated (because then you have two discrete class definitions, not two instantiations).

It would be nice if we could treat patcher/abstraction as (almost) fully interchangeable while developing, but there are obvious problems with the #0 syntax not working in a patcher, and with pvar and pv not being local to a single patcher.

I’d like to define an instantiation of a "class", as either "public" (input accessible from anywhere), or "private" (input only accessible from its parent patcher).

Private is pretty obviously just a regular abstraction/patcher, with regular inlets/outlets. No problem there.

Public would ideally use a receive object bound to a unique name that reflects the patcher heirarchy, ie "L1.L2.L3".

I’m working on a javascript object to handle this, based on a "@pub name" attribute. This javascript object (present in any class) figures out the heirarchy, auto-names the containing class (preventing duplicate names in the same scope) and sets the receive source. If the @pub attribute isn’t there, the receive is replaced with an inlet.

Yes, this is very similar to pattrforward, isn’t it? But Stefan’s comments notwithstanding, I really do want to keep my CPU use to a minimum if I’m a MIDI background app running on an older CPU, and the interesting activity is occurring in some other CPU-intensive app. I need to do some pattrforward tests I guess…

Optional: an @static attribute that would allow a single working instantiation. Subsequent instantiations would load a simpler version that merely communicate with the singleton.

METHOD

You could consider any processing internal to an abstraction or patcher as a method.

Public method – the parent class is responsible for despatching calls to any internal processes that could be considered "public", ie [route method1 method2 ... ]

Private method – processing that can’t be directly accessed from the class inlet (or receive).

[pvar] use is not appropriate, as its behaviour is different in abstraction vs patcher?

VARIABLE

Still thinking about the idea of class variables.

Obvious issues with [pv] in a patcher as opposed to an abstraction.

In general, public class variables should be avoided, with public get/set methods preferred where necessary.

A private static class variable doesn’t look possible?

INHERITANCE

Sure, you can copy an abstraction/patcher and add stuff, but that’s not true inheritance. What happens if the superclass definition changes? The subclass doesn’t know it has a superclass, and won’t inherit the changes.


April 11, 2007 | 3:05 am

Quote: johnpitcairn wrote on Wed, 11 April 2007 11:09
—————————————————-
> Yes, this is very similar to pattrforward, isn’t it? But
> Stefan’s comments notwithstanding, I really do want to keep my
> CPU use to a minimum if I’m a MIDI background app running on
> an older CPU, and the interesting activity is occurring in
> some other CPU-intensive app. I need to do some pattrforward
> tests I guess…

And so I have. Sending to the inlet – ie including a [prepend in0] – of a patcher via pattrforward is about five times slower than sending to a receive object via send. Not an option for realtime data for me, unfortunately.


April 11, 2007 | 8:23 am

Hi johnpitcairn,

I’m interested to see how your implementation will work. I have several comments, but maybe I should wait until you made a prototype. If you could use help, for example with javascript issues, let me know. I work with javascript a lot lately.

The idea of using the position in the hierarchy to compose the unique id that we’ve been discussing, looks promising.

I’m curious as to your thoughts about my latest example. More so if you simply didn’t feel like checking it out because it looked messy; any comments are appreciated.

Cheers,
Mattijs

uote: johnpitcairn wrote on Wed, 11 April 2007 01:09
—————————————————-
> My current thinking:
>
> CLASS
>
> A – an abstraction saved on disk
>
> B – a patcher – in which case it’s only ever a single instance, even if simply duplicated (because then you have two discrete class definitions, not two instantiations).
>
> It would be nice if we could treat patcher/abstraction as (almost) fully interchangeable while developing, but there are obvious problems with the #0 syntax not working in a patcher, and with pvar and pv not being local to a single patcher.
>
> I’d like to define an instantiation of a "class", as either "public" (input accessible from anywhere), or "private" (input only accessible from its parent patcher).
>
> Private is pretty obviously just a regular abstraction/patcher, with regular inlets/outlets. No problem there.
>
> Public would ideally use a receive object bound to a unique name that reflects the patcher heirarchy, ie "L1.L2.L3".
>
> I’m working on a javascript object to handle this, based on a "@pub name" attribute. This javascript object (present in any class) figures out the heirarchy, auto-names the containing class (preventing duplicate names in the same scope) and sets the receive source. If the @pub attribute isn’t there, the receive is replaced with an inlet.
>
> Yes, this is very similar to pattrforward, isn’t it? But Stefan’s comments notwithstanding, I really do want to keep my CPU use to a minimum if I’m a MIDI background app running on an older CPU, and the interesting activity is occurring in some other CPU-intensive app. I need to do some pattrforward tests I guess…
>
> Optional: an @static attribute that would allow a single working instantiation. Subsequent instantiations would load a simpler version that merely communicate with the singleton.
>
>
> METHOD
>
> You could consider any processing internal to an abstraction or patcher as a method.
>
> Public method – the parent class is responsible for despatching calls to any internal processes that could be considered "public", ie [route method1 method2 ... ]
>
> Private method – processing that can’t be directly accessed from the class inlet (or receive).
>
> [pvar] use is not appropriate, as its behaviour is different in abstraction vs patcher?
>
>
> VARIABLE
>
> Still thinking about the idea of class variables.
>
> Obvious issues with [pv] in a patcher as opposed to an abstraction.
>
> In general, public class variables should be avoided, with public get/set methods preferred where necessary.
>
> A private static class variable doesn’t look possible?
>
>
> INHERITANCE
>
> Sure, you can copy an abstraction/patcher and add stuff, but that’s not true inheritance. What happens if the superclass definition changes? The subclass doesn’t know it has a superclass, and won’t inherit the changes.
>
>
—————————————————-


April 12, 2007 | 1:07 am

Quote: Mattijs wrote on Wed, 11 April 2007 20:23
—————————————————-
> I’m curious as to your thoughts about my latest example. More
> so if you simply didn’t feel like checking it out because it
> looked messy; any comments are appreciated.

Checked it out, and it makes sense but it seems too opaque and thus unintuitive to use (to me). Rather than asking an object for its unique id in order to talk to it, I’d prefer to use a more common oo-style scope heirarchy to talk to things:

[p @name L1 [p @name L2 [p @name L3]]]

whereby there are receive objects inside each of those (public) patchers:

[r L1], [r L1.L2] and [r L1.L2.L3]

So you have the local names visible as a patcher argument at each level of the heirarchy, making it easy to construct an appropriate reference.

The javascript I’m working with at the moment does also provide a unique ID (integer) for each instantiation, which could be used if desired.

I’ve not posted anything yet due to lack of time to work on it, and I did want to find out if pattr could be made to do some of the work.


April 12, 2007 | 2:33 am

Quote: johnpitcairn wrote on Wed, 11 April 2007 15:05
—————————————————-
> And so I have. Sending to the inlet – ie including a [prepend
> in0] – of a patcher via pattrforward is about five times slower
> than sending to a receive object via send.

BUT! Sending to a named [route] within the patcher via pattrforward incurs far less penalty than sending to the inlet – only about 20% slower than using a [receive] connected to that [route], and about 10% faster than using [forward].

That I can live with, considering I’ll likely be needing that route and/or forward anyway…


April 12, 2007 | 8:32 am

Quote: johnpitcairn wrote on Thu, 12 April 2007 03:07
—————————————————-
> Quote: Mattijs wrote on Wed, 11 April 2007 20:23
> —————————————————-
> > I’m curious as to your thoughts about my latest example. More
> > so if you simply didn’t feel like checking it out because it
> > looked messy; any comments are appreciated.
>
> Checked it out, and it makes sense but it seems too opaque and thus unintuitive to use (to me).

Ah, thanks for the feedback.

> Rather than asking an object for its unique id in order to talk to it, I’d prefer to use a more common oo-style scope heirarchy to talk to things:
>
> [p @name L1 [p @name L2 [p @name L3]]]
>
> whereby there are receive objects inside each of those (public) patchers:
>
> [r L1], [r L1.L2] and [r L1.L2.L3]
>
> So you have the local names visible as a patcher argument at each level of the heirarchy, making it easy to construct an appropriate reference.

I’d be happy to test and comment your prototypes. I have been working on a similar approach once and I stumbled upon some drawbacks. But I might not understand your idea completely so I’ll wait with that until you made a patch.

In the mean time I’m trying my ideas in practice, to see if I can make a demo application that is built on these oo principles and clearly displays its advantages. If everything works I’ll start using the principles in our (huge) main project patchers.

>
> The javascript I’m working with at the moment does also provide a unique ID (integer) for each instantiation, which could be used if desired.
>
> I’ve not posted anything yet due to lack of time to work on it, and I did want to find out if pattr could be made to do some of the work.

I understand completely. Btw, in my experience, the closer you get to the edge of max, the more timeconsuming this kind of ideas get ;)

Mattijs


April 12, 2007 | 9:16 pm

A few further thoughts:

1 – Do we REALLY need to consider [p] as a class instantiation?

If we limit "class" to saved-to-disk abstractions only, then life becomes a lot simpler – # arguments work, pv and pvar have local scope and can be used as private variable and private method call, respectively.

If p is not a class instantiation, then it’s simply a convenient way of hiding complexity within the same local scope. No equivalent in oo-speak (or is there?), but then, this is Max.

2 – Is pattrforward to named objects in a class really a workable solution for "public" access?

It’s simple and elegant, sure, but objects may be named for other reasons (scripting access, pvar access), and this exposes them as public.

Can a signal be sent via pattrforward?


April 13, 2007 | 1:23 am

John Pitcairn wrote:
> If p is not a class instantiation, then it’s simply a convenient way
> of hiding complexity within the same local scope. No equivalent in
> oo-speak (or is there?), but then, this is Max.

There is an equivalent and it’s broader than OO: [p] == {}

In Max, as an IDE of sorts, we use [p] as collapsible braces.


April 13, 2007 | 1:47 am

Ah yes – though the "collapsibility" is editor-specific.

But another problem arises if p = {} and pattrforward is used for method despatch – pattrforward needs to see the [p] as part of the object heirarchy to access anything therein. So for a structure like:

[abstraction @public L1 [p [abstraction @public L2]]]

I’d want to address stuff in L2 as simply [pattrforward L1::L2], with the p not defining its own scope (consistent with the behaviour or pv and pvar).

But pattrforward addressing would need [pattrforward L1::(pname)::L2], since as far as pattrforward is concerned, p does define its own scope.

Rats.


April 13, 2007 | 5:33 am

Here’s what I arrived at so far: a little js to manage scoping/naming/ids, and pattrforward with unique receives for public method calls with return values.

Class objects (patchers or abstractions) get auto-named according to their @public (name) attribute.

Any named object is exposed to pattrforward as public, so scripting access is a potential problem.

This doesn’t deal with private scoping at all – there are differences using pv and pvar in patchers vs abstractions that make this a tricky prospect, and pvar requires a name, thus it’s not private.

All javascript executes at object instantiation, so there’s no js processing overhead otherwise.

Comments invited…


April 13, 2007 | 9:06 am

no

jb

Am 12.04.2007 um 23:16 schrieb John Pitcairn:

> Can a signal be sent via pattrforward?


April 13, 2007 | 9:23 am

John, that’s nice! It looks like we’re really building towards something! I’m going to have a close look at it this weekend, but for now I already have some quick comments (please forgive me for only mentioning the criticism, not the praise. I really like your implementation in multiple ways).

- generating a unique id could be done more easily with an abstraction getID:

#P outlet 37 51 15 0;
#P newex 37 31 80 196617 loadmess $0-id;
#P connect 0 0 1 0;

- the possibility to have subpatchers as well as abstractions for classes is vital in practice, I am afraid. But I can live with copy-pasting the p.
- why name patchers/classes with @public attribute instead of just name them manually? One important pro would be that max automatically generates a unique name by appending array style [x] if you make a copy of a named object, where x is an increasing number. Very useful, I think, to define arrays of classes, which is definitly what I’m going to do. For now I don’t see an urgent need to distinguish between private and public classes (which I think you are after).
- as you mentioned in the other thread, this system doesn’t allow for unnamed intermediate subpatchers
- public float divide(int, int, symbol): You could leave the symbol out of this description as far as I am concerned, because it is part of the function calling protocol, not of the actual method.
- maybe using a simple abstraction (empty, perhaps, except for a script that sets its object name?) instead of the route for a function call could make a difference in intuitivity
- you didn’t deal with variables yet, only with methods.
- v, pv and pvar: I don’t understand your comment completely. My version: v is not useful because it requires a global name. pvar is not useful because it has only a local scope and there is no way to access it from outside. pv on the other hand, I don’t understand your comment about its scope. As far as I can see it behaves similar in abstractions and subpatchers. There -is- an issue that it resets its peers’ value when instantiated inside an abstraction, but that simply looks like a bug to me, not a conceptual problem. pv could be very useful.
- There is another, more advanced, issue with pv. It can’t be overridden. I am working on a prototype that explains this. I hope to finish it this weekend.

But I’ll give everything a closer look this weekend, perhaps I’m able to make an updated version of your implementation which incorporates some of my comments.

Cheers,
Mattijs

Quote: johnpitcairn wrote on Fri, 13 April 2007 07:33
—————————————————-
> Here’s what I arrived at so far: a little js to manage scoping/naming/ids, and pattrforward with unique receives for public method calls with return values.
>
> Class objects (patchers or abstractions) get auto-named according to their @public (name) attribute.
>
> Any named object is exposed to pattrforward as public, so scripting access is a potential problem.
>
> This doesn’t deal with private scoping at all – there are differences using pv and pvar in patchers vs abstractions that make this a tricky prospect, and pvar requires a name, thus it’s not private.
>
> All javascript executes at object instantiation, so there’s no js processing overhead otherwise.
>
> Comments invited…
—————————————————-


April 13, 2007 | 9:26 am

Quote: Mattijs wrote on Fri, 13 April 2007 11:23
—————————————————-
> – as you mentioned in the other thread, this system doesn’t allow for unnamed intermediate subpatchers

Sorry, I mean in *this* thread.


April 14, 2007 | 6:27 am

John Pitcairn schrieb:
> INHERITANCE
>
> Sure, you can copy an abstraction/patcher and add stuff, but that’s
> not true inheritance. What happens if the superclass definition
> changes? The subclass doesn’t know it has a superclass, and won’t
> inherit the changes.

Inheritance would then be an abstraction around another abstraction,
that would fit your definition.

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#N vpatcher 20 74 620 474;
#P outlet 115 159 15 0;
#P inlet 197 53 15 0;
#P inlet 148 53 15 0;
#P inlet 99 53 15 0;
#P pop;
#P newobj 50 119 61 196617 p new code;
#P outlet 125 183 15 0;
#N vpatcher 20 74 620 474;
#P outlet 94 169 15 0;
#P window setfont "Sans Serif" 9.;
#P newex 93 69 50 196617 route abc;
#P inlet 93 45 15 0;
#P comment 88 111 100 196617 some code in here;
#P connect 1 0 2 0;
#P pop;
#P newobj 125 119 81 196617 p inherited;
#P newex 50 89 87 196617 route a b c;
#P inlet 50 65 15 0;
#P connect 4 0 3 0;
#P connect 1 2 4 2;
#P connect 1 1 4 1;
#P connect 1 0 4 0;
#P connect 2 0 3 0;
#P connect 1 3 2 0;
#P connect 0 0 1 0;
#P window clipboard copycount 5;


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


April 15, 2007 | 1:24 am

Quote: Stefan Tiedje wrote on Sat, 14 April 2007 18:27
—————————————————-
> Inheritance would then be an abstraction around another
> abstraction, that would fit your definition.

OK for method inheritance/overriding, but won’t this run into problems if you want to do something in the derived class using variables defined in the original class? ie:

class original()
{
private p;
}

class new extends original()
{
method getp()
{
return p;
}
}

No way to do this in max-land if the original abstraction provides no way to retrieve the variable?


April 15, 2007 | 2:47 am

Quote: Mattijs wrote on Fri, 13 April 2007 21:23
—————————————————-
> – generating a unique id could be done more easily with an
> abstraction getID:

Yes, the js in my example is left over from some other things I was thinking about. Though it might be useful to have an unique-id generator that is independent of the #0 mechanism (and thus will work in a patcher too).

> – the possibility to have subpatchers as well as abstractions
> for classes is vital in practice, I am afraid. But I can live
> with copy-pasting the p.

It would also be possible to use an "init" message to the patcher inlet, or a name::init public method to re-init the name, but I think simple is better at this stage.

> – why name patchers/classes with @public attribute instead of
> just name them manually? One important pro would be that max
> automatically generates a unique name by appending array style
> [x] if you make a copy of a named object, where x is an
> increasing number. Very useful, I think, to define arrays of
> classes, which is definitly what I’m going to do. For now I
> don’t see an urgent need to distinguish between private and
> public classes (which I think you are after).

I wanted to have a clear visual indication of the name right there in the patch, instead of needing to look it up via the name inspector. The @public attribute is just a reminder that the object is exposed to pattrforward, you could use @name of course (though I wanted a familiar syntax). Using an attribute argument is desirable so that existing patchers/abstractions can be converted to use this. I suspect @name is more likely to conflict with existing attributes than @public…

The general idea is that as few steps as possible are needed to use this, thus the auto-naming. It’s easy to forget to name an object.

Ideally, I’d like to have the script check to see if the object has been successfully named the same as its argument, and if not, re-instantiate with altered argument to reflect the name[x] it would get for a duplicate. Impossible for a patcher (contents would be lost), and probably crash-prone for an abstraction.

> – as you mentioned in the other thread, this system doesn’t
> allow for unnamed intermediate subpatchers

Unless you consider those as essentially "private". An unnamed patcher or abstraction containing "public" objects would atill allow access to those objects from within the local patcher scope or below, but not from anywhere above it. Still thinking about this issue. Maybe pattrmarker can help.

> – maybe using a simple abstraction (empty, perhaps, except for
> a script that sets its object name?) instead of the route for
> a function call could make a difference in intuitivity

Ideally I’d like a named "method" abstraction with two inlets and one outlet. This could be used as a method header, clearly displaying the method name – the outlet would connect to the processing chain, and the result of the processing would connect to inlet 2 for return to the caller.

Unfortunately pattrforward to patcher/abstraction inlets is a lot slower than to a named native object, and in my testing is prone to trouble finding the inlet.

So it would still be desirable to use a named object within that method abstraction, ie [pattrforward L1::divide::in].

I’d prefer just the method name, ie ::divide. Anyway:

oo.method abstraction:
——————-
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 26 57 34 196617 route;
#P objectname in;
#P newex 342 54 64 196617 patcherargs;
#P newex 396 77 70 196617 js oo.name.js;
#N comlet return from processing;
#P inlet 209 56 15 0;
#P newex 209 232 47 196617 forward;
#P newex 111 116 68 196617 prepend send;
#P newex 50 87 71 196617 zl ecils 1;
#N comlet to processing;
#P outlet 50 236 15 0;
#P connect 6 1 5 0;
#P connect 4 0 3 0;
#P connect 2 0 3 0;
#P connect 1 1 2 0;
#P connect 1 0 0 0;
#P connect 7 1 1 0;
#P window clipboard copycount 8;

use like this:
————–
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P newex 762 227 62 196617 print result;
#P message 762 174 37 196617 34 55;
#P newex 762 199 85 196617 oo.call divide::in;
#P newex 760 57 122 196617 oo.method @public divide;
#P objectname divide;
#P newex 760 100 58 196617 / 1.;
#P newex 760 79 58 196617 unpack 0 0;
#P connect 3 0 5 0;
#P connect 4 0 3 0;
#P fasten 1 0 2 0 765 126 752 126 752 50 765 50;
#P connect 2 0 0 0;
#P connect 0 1 1 1;
#P connect 0 0 1 0;
#P window clipboard copycount 6;

> – you didn’t deal with variables yet, only with methods.
> – v, pv and pvar: I don’t understand your comment completely.
> My version: v is not useful because it requires a global name.

Yep, global variables are undesirable.

> pvar is not useful because it has only a local scope and there > is no way to access it from outside.

It would be very useful for private method calls. But it requires the target object to be named, and thus made public to pattrforward, which means the private-ness of the method call is circumvented.

> pv on the other hand, I don’t understand your comment about
> its scope. As far as I can see it behaves similar in
> abstractions and subpatchers.

You’re right, I was evidently confused.

pv in a parent patcher/abstraction is shared by a child patcher/abstraction.

[p [pv test]] is shared by [p [p [pv test]]].

[p [pv test]] is shared by [p [abstraction [pv test]]].

This is not what I want for a private variable, it should be local to the patcher or abstraction only.

> There -is- an issue that it resets its peers’ value when
> instantiated inside an abstraction, but that simply looks like
> a bug to me, not a conceptual problem.

Only if instantiated with a value argument, and that strikes me as correct behaviour given the above. [pv test] instantiated in an abstraction does not reset [pv test 999] already existing in the parent for me.


April 15, 2007 | 8:55 pm

Quote: johnpitcairn wrote on Sun, 15 April 2007 03:24
—————————————————-
> Quote: Stefan Tiedje wrote on Sat, 14 April 2007 18:27
> —————————————————-
> > Inheritance would then be an abstraction around another
> > abstraction, that would fit your definition.
>
> OK for method inheritance/overriding, but won’t this run into problems if you want to do something in the derived class using variables defined in the original class? ie:
>
> class original()
> {
> private p;
> }
>
> class new extends original()
> {
> method getp()
> {
> return p;
> }
> }
>
> No way to do this in max-land if the original abstraction provides no way to retrieve the variable?

You could do this with pv if ‘new’ is a subpatcher inside ‘original’. In fact I do exactly that in the oo example I posted earlier in this thread.

Mattijs


April 15, 2007 | 10:03 pm

Quote: johnpitcairn wrote on Sun, 15 April 2007 04:47
—————————————————-
> Yes, the js in my example is left over from some other things I was thinking about. Though it might be useful to have an unique-id generator that is independent of the #0 mechanism (and thus will work in a patcher too).

This will work in a subpatcher though. The loadmess is in its own abstraction:

Save as ‘getId’:

#P outlet 22 59 15 0;
#P newex 22 36 71 9109513 loadmess $0-id;
#P connect 0 0 1 0;

Save as anything:

#P newex 96 102 26 9109513 print;
#P newex 96 78 31 9109513 getID;
#P connect 0 0 1 0;

>
> > – why name patchers/classes with @public attribute instead of
> > just name them manually? One important pro would be that max
> > automatically generates a unique name by appending array style
> > [x] if you make a copy of a named object, where x is an
> > increasing number. Very useful, I think, to define arrays of
> > classes, which is definitly what I’m going to do. For now I
> > don’t see an urgent need to distinguish between private and
> > public classes (which I think you are after).
>
> I wanted to have a clear visual indication of the name right there in the patch, instead of needing to look it up via the name inspector.

Agreed, a visual indication is a pro.

> Using an attribute argument is desirable so that existing patchers/abstractions can be converted to use this.

I don’t think whether or not to use an attribute in combination with the object name will make a difference there.

> I suspect @name is more likely to conflict with existing attributes than @public…

Yeah, the actual name of the atttribute isn’t crucial, @public would be fine. Still, well, let’s just try this in a practical situation.

>
> It’s easy to forget to name an object.

True. A visual indication is more intuitive.

>
> Ideally, I’d like to have the script check to see if the object has been successfully named the same as its argument, and if not, re-instantiate with altered argument to reflect the name[x] it would get for a duplicate. Impossible for a patcher (contents would be lost), and probably crash-prone for an abstraction.

Hehe, yeah, the point is clear. Some auto-naming mechanism for arrays would be pretty. I’ve been using the array style auto-naming of max for exactly this issue for some time now and I’m pretty content with it. The only real disadvantage is the lack of visual indication.

>
> > – as you mentioned in the other thread, this system doesn’t
> > allow for unnamed intermediate subpatchers
>
> Unless you consider those as essentially "private". An unnamed patcher or abstraction containing "public" objects would atill allow access to those objects from within the local patcher scope or below,

Do you mean by using the parent:: syntax? I see no other alternative. But this would slightly break your path-style call idea, no?

> but not from anywhere above it. Still thinking about this issue. Maybe pattrmarker can help.

Me too, thinking. :)

>
> > – maybe using a simple abstraction (empty, perhaps, except for
> > a script that sets its object name?) instead of the route for
> > a function call could make a difference in intuitivity
>
> Ideally I’d like a named "method" abstraction with two inlets and one outlet. This could be used as a method header, clearly displaying the method name – the outlet would connect to the processing chain, and the result of the processing would connect to inlet 2 for return to the caller.
>
> Unfortunately pattrforward to patcher/abstraction inlets is a lot slower than to a named native object, and in my testing is prone to trouble finding the inlet
>
> So it would still be desirable to use a named object within that method abstraction, ie [pattrforward L1::divide::in].
>
> I’d prefer just the method name, ie ::divide. Anyway:
>
>
> oo.method abstraction:
> ——————-
> #P window setfont "Sans Serif" 9.;
> #P window linecount 1;
> #P newex 26 57 34 196617 route;
> #P objectname in;
> #P newex 342 54 64 196617 patcherargs;
> #P newex 396 77 70 196617 js oo.name.js;
> #N comlet return from processing;
> #P inlet 209 56 15 0;
> #P newex 209 232 47 196617 forward;
> #P newex 111 116 68 196617 prepend send;
> #P newex 50 87 71 196617 zl ecils 1;
> #N comlet to processing;
> #P outlet 50 236 15 0;
> #P connect 6 1 5 0;
> #P connect 4 0 3 0;
> #P connect 2 0 3 0;
> #P connect 1 1 2 0;
> #P connect 1 0 0 0;
> #P connect 7 1 1 0;
> #P window clipboard copycount 8;
>
>
> use like this:
> ————–
> #P window setfont "Sans Serif" 9.;
> #P window linecount 1;
> #P newex 762 227 62 196617 print result;
> #P message 762 174 37 196617 34 55;
> #P newex 762 199 85 196617 oo.call divide::in;
> #P newex 760 57 122 196617 oo.method @public divide;
> #P objectname divide;
> #P newex 760 100 58 196617 / 1.;
> #P newex 760 79 58 196617 unpack 0 0;
> #P connect 3 0 5 0;
> #P connect 4 0 3 0;
> #P fasten 1 0 2 0 765 126 752 126 752 50 765 50;
> #P connect 2 0 0 0;
> #P connect 0 1 1 1;
> #P connect 0 0 1 0;
> #P window clipboard copycount 6;
>

Yep, this looks good! If your only concern is the "::in"; isn’t this easily hidden by always appending "::in" to your call path inside the oo.call object?

> You’re right, I was evidently confused.
>
> pv in a parent patcher/abstraction is shared by a child patcher/abstraction.
>
> [p [pv test]] is shared by [p [p [pv test]]].
>
> [p [pv test]] is shared by [p [abstraction [pv test]]].
>
> This is not what I want for a private variable, it should be local to the patcher or abstraction only.

So you don’t want the variable to be accessible from subclasses, correct? I can understand that. But to me it is rather a cosmetic concern. In practical situations, you’ll need to access private variables of a class inside (unnamed) subpatchers, for example in a method. I think pv is perfect for that.

Mattijs


April 15, 2007 | 10:05 pm

Quote: johnpitcairn wrote on Sun, 15 April 2007 04:47
—————————————————-
> > There -is- an issue that it resets its peers’ value when
> > instantiated inside an abstraction, but that simply looks like
> > a bug to me, not a conceptual problem.
>
> Only if instantiated with a value argument, and that strikes me as correct behaviour given the above. [pv test] instantiated in an abstraction does not reset [pv test 999] already existing in the parent for me.

As far as I can see, the problem is there, also without argument. I definitly call this a bug. Are you sure that you can’t reproduce the error if you follow the steps in in the patch this thread:

http://www.cycling74.com/forums/index.php?t=msg&th=25380&rid=3579&S=bfaaeb3f10c0df961dea06c64beb7a92

?


April 15, 2007 | 11:24 pm

Uh, yeah, confirmed. pv instantiated without a value argument in an abstraction resets the same pv in a parent patcher or abstraction.

If the pv is in a patcher that is re-instantiated by cut/paste, the parent pv is not reset.


April 16, 2007 | 12:01 am

Quote: Mattijs wrote on Mon, 16 April 2007 10:03
—————————————————-
> This will work in a subpatcher though. The loadmess is in its
> own abstraction:

I must confess I didn’t actually try the example. Indeed it is, this will be just fine ;-)

> I don’t think whether or not to use an attribute in
> combination with the object name will make a difference there.

What I mean is, say you have an existing abstraction "munter" that you want to oo-ify using these techniques. We need to use attributes because if we use normal arguments that will mess up existing arguments to munter. And just for safety, a @name attribute is more likely to exist already in somebody’s abstraction than a @public attribute.

So [munter @public munter1] is the equivalent of

public munter1 = new munter() or
public munter munter1()

Which should be fairly faimiliar to C++/Java users.

If the @public isn’t there, the javascript doesn’t auto-name the object and it isn’t exposed to pattrforward.

> Hehe, yeah, the point is clear. Some auto-naming mechanism for > arrays would be pretty.

We could take a look at adding an attribute like @auto X to the script, whereby a js task will bang the patcherargs and re-init every X seconds – this could be useful when running inside a patcher.

I’m still hunting for a reliable way to distinguish whether the object is a patcher or an abstraction – patcher.filename does not return null for a non-saved patcher, it returns the patcher name.

Quote: me:
———-
> > Unless you consider those as essentially "private". An
> > unnamed patcher or abstraction containing "public" objects
> > would atill allow access to those objects from within the
> > local patcher scope or below,

Quote: Mattijs
————–
> Do you mean by using the parent:: syntax? I see no other
> alternative. But this would slightly break your path-style
> call idea, no?

Yes, you’d need to use parent:: inside anything below the patcher, but not from the patcher itself.

> Yep, this looks good! If your only concern is the "::in";
> isn’t this easily hidden by always appending "::in" to your
> call path inside the oo.call object?

Duh. I was stupid yesterday, that will work fine, thanks…

> So you don’t want the variable to be accessible from
> subclasses, correct? I can understand that. But to me it is
> rather a cosmetic concern. In practical situations, you’ll
> need to access private variables of a class inside (unnamed)
> subpatchers, for example in a method. I think pv is perfect
> for that.

To clarify: regardless of the public or non-public status of the containing patcher/abstraction, a true private variable should never be accessible outside the scope of its container. So given a private variable [var]:

[p [var v1] [p [var var1] p [var var1]]]

Those three variables should be totally independent: setting one must not affect the others. Each var1 should only be shared by other var1 instances in the same patcher or abstraction, ie [p [var v1] [var v1]] – not in a parent- or sub-patcher/abstraction.

If you need to get/set a private variable from outside the local scope, that should be done via public get/set methods, not by directly manipulating the variable.


April 16, 2007 | 2:58 am

OK, here’s a possibility for private variables:

If we put aside our distaste for [v], can we use v with a name prepended by a unique ID generated by the patcher? Wrap an abstraction around v that calls the parent patch’s "oo.name.js" object to retrieve a unique ID, then instantiate the v with that unique id + name inside the abstraction.

It’s not REALLY private, but unless you look inside the abstraction to find the name it’s using and deliberately use that in v somewhere else, it behaves like a private variable. Even if you do that, you’ve no guarantee(?) the id will be the same at next runtime. I propose that we use some uncommon symbol before all such names, perhaps "_", ie "_928name".

The only requirement is that the parent patcher/abstraction includes the "oo.name.js" object.

I’ve attached a new .zip that demonstrates this, and incorporates the "method" header abstraction discussed earlier.


April 16, 2007 | 4:46 am

Quote: johnpitcairn wrote on Mon, 16 April 2007 14:58
—————————————————-
> The only requirement is that the parent patcher/abstraction
> includes the "oo.name.js" object.

I’m still brain-impaired – if the parent doesn’t contain oo.name.js, then the search should continue upwards until one is found.

So oo.name.js effectively defines a local namespace, and unnamed patchers or abstractions under that will share the namespace for private variables. This is like using pv, except the scope can be limited without caring about the name used.

I’ll modify the javascript accordingly.

Now I just need a way to make those unnamed patchers (and abstractions?) transparent to pattrforward. This seems unlikely, given that names would need to remain unique across nested subpatchers that share a namespace.

Something close can be achieved by using send/receive instead of pattrforward and named objects, and having oo.name.js set the unique receive source, ie [r L1::L2:name]. This would require the js to fully manage the namespace, including checking for duplicate names across nested patchers sharing a namespace, and unfortunately would also make the use of short local/relative addressing rather more difficult.


April 16, 2007 | 5:01 am

Though the above gets a bit ugly. There’s a point where we have to say "enough", surely?

Maybe unnamed patchers/abstractions have to be considered roughly equivalent to a "private" declaration? Named objects within those would still be accessible to pattrforward from the local scope or below.

This would make any upwardly-greedy oo.v scope not required (though the unnamed parent patcher/abstraction would still need to contain oo.name.js to provide an id).


April 17, 2007 | 9:34 pm

I checked out your new version and this has indeed gotten better. For searching upwards through the patcher hierarchy you could have a look at the overridable pv prototype I recently posted. It does exactly that.

I am currently working on a new version of my example, trying to incorporate many of your ideas, thus trying to work our approaches towards each other.

So I’m still thinking (as I am sure you are ;) about how to work with a path without the problem of unnamed subpatches, without making it ugly. The standard pattr system won’t do, I’m afraid, but maybe something smart with send/receives and unique id’s as you already indicated, perhaps derived from my initial example, could work.

In the mean time I agree to first make this work without dealing with this unnamed subpatcher problem and simply considering that a private declaration.

I’d like to mention that for some reason the .mxt main patch that you include in your zips doesn’t open on a pc. Maybe you could make that plain patch files, like the others?

Thanks,
Mattijs

Quote: johnpitcairn wrote on Mon, 16 April 2007 07:01
—————————————————-
> Though the above gets a bit ugly. There’s a point where we have to say "enough", surely?
>
> Maybe unnamed patchers/abstractions have to be considered roughly equivalent to a "private" declaration? Named objects within those would still be accessible to pattrforward from the local scope or below.
>
> This would make any upwardly-greedy oo.v scope not required (though the unnamed parent patcher/abstraction would still need to contain oo.name.js to provide an id).
>
—————————————————-


April 18, 2007 | 12:30 am

Quote: Mattijs wrote on Wed, 18 April 2007 09:34
—————————————————-
> So I’m still thinking (as I am sure you are ;) about how to
> work with a path without the problem of unnamed subpatches,
> without making it ugly. The standard pattr system won’t do,
> I’m afraid, but maybe something smart with send/receives and
> unique id’s

Yup. Working on it, looks like it’s do-able – essentially, dropping a "scope.js" object into a patcher/abstraction will define that as aa new local scope and handle all naming/scoping requirements, and the arguments to the patcher will likely be optional.

The result should allow patchers (and abstractions) to define a new scope or to inherit the nearest-parent scope according to developer requirements.

I’ll stay clear of pattr and object names entirely I think, so the oo-system is independent of the other object-access and global systems available in Max – which can still be used to break oo encapsulation if desired. Er…

Then if the whole thing is dog-slow at instantiation, I guess we could perhaps look at some custom C/C++ objects to do the same job as the javascripts.

Might need a few more days on this ;-)


April 20, 2007 | 5:16 am

Quote: johnpitcairn wrote on Wed, 18 April 2007 12:30
—————————————————-
> dropping a "scope.js" object into a patcher/abstraction will
> define that as aa new local scope

A modification: the above is certainly possible, but in practice it’s not proving very intuitive, and prevents an abstraction from being used without scope (which I personally think is desirable).

So patchers/abstractions with an @public or @private attribute AND an included scope object will define a new scope, those without one or both will be part of the nearest-parent scope.

I’ve worked out the annoying patcherargs precedence issues I think, so it’s now possible to option-copy or copy/paste an instantiation and have the scoping/naming work immediately without additional effort.

Names are independent of script-names and pattr, name conflicts within a scope are resolved, and can optionally be defined with zero-based indexing, ie for three copied instances:

[p @public L1] [p @public L1] [p @private L1]

the first instance can resolve to either L1 or L1-0, depending on a global setting. Subsequent instances will be L1-1 and L1-2 (etc) in either case. The idea is that L1-0 will make it easier to iterate over like-named objects programatically.

Objects can optionally be automatically script-named if desired (using the same names), to make them accessible to scripting or pattr. If that’s what you really want (warning).

Private variables are working using roughly the same mechanism as outlined earlier. These are ALWAYS private to the scope, ie an oo.v object in a scoped patcher/abstraction will not be shared by its parent patcher (unlike pv).

Setting/getting a private variable from the local scope (only) can simply be done inline, as you would for pv.

I’m now working on an oo.call object that can resolve an address to unique ID, similar to pattrforward but allowing for public/private scoping. Gglobal and relative addressing should be possible.

The only thing you’ll be able to address from oo.call is an oo.method definition header object, unless anyone can make a good case otherwise.

There may need to be a mechanism to handle the situation that occurs when any scoped object has its oo.scope object deleted, making it unscoped – any child objects may need to be notified and re-evaluate their scope. oo.call objects referencing those will then become incorrect, but those will likely need to be found and corrected by hand (yikes)? How should this general situation be handled (or prevented)?

Proposed syntax, reserved names, etc:

All abstractions and unique ids used begin with "oo."

Addressing paths will use "." as a scope separator.

A relative address from the local scope will use "name1.name2.method1" – the method1 method inside the name2 patcher/abstraction inside the name1 patcher/abstraction in the local scope.

Parent-relative addressing will prepend "." for each level upward, ie "..name1.method1" means the method1 method in the name1 object in the parent scope’s parent scope. We don’t need to explicitly specify "parent" I think, it’s a waste of space.

Global (top-down) addresses will begin with ":"


April 20, 2007 | 7:51 pm

Hi again,

I think I have a neat solution for the scope issue with unnamed subpatchers. It’s inspired by the listener/notifier model and the use of coll, earlier in this thread and the idea of a scope.js in subpatchers.

The basic idea is that methods and objects reveal themselves to their parent object. A call propagates through the chain of registered objects until it reaches its destination method.

I also applied some of the conventions you proposed, johnpitcairn.

Have a look and let me know what you think:

http://www.arttech.nl/OO%20example%20Mattijs%20070420.zip

Mattijs


April 22, 2007 | 3:56 am

Quote: Mattijs wrote on Sat, 21 April 2007 07:51
—————————————————-
> The basic idea is that methods and objects reveal themselves
> to their parent object. A call propagates through the chain of
> registered objects until it reaches its destination method.

We’re definitely thinking along similar lines, though we are using different techniques to get there – I’m attempting to work in js as much as possible.

Will you implement public vs private scoping?

I’m not too sure about the use of coll to register objects – a coll lookup for higher-indexed items takes longer, whereas a js lookup stays constant, so at some point (about 400 items?) it’s actually faster to do the lookup in js.

We both have an issue with what happens when a previously unscoped patcher has a scoping object added, or a previously scoped patcher has its scoping object deleted. Any child objects need to be re-scoped to the new parent.

I’ll post an example of where I’m at once I work out a few more kinks.


April 26, 2007 | 11:19 pm

Not getting much time to work onthis at present, but some further thoughts:

A:

Using a unique receive id in methods is not proving ideal. If you define a method [oo.method @public test], define multiple calls to that method, then delete and re-create the method using the same name, it will get a new receive id and all the calls will be wrong.

So I’m looking at using the global call path (:object.object.method) for the method receive, which will at least remain constant if the parent object structure doesn’t change.

Method calls should verify the call path at instantiation, checking that the specified objects exist, and if any object in the call path is private, the method call must be from the same scope as the object. Invalid calls should present some sort of error notification.

I’m also looking at having method calls register their id in the method definition, so if the method call path changes, some sort of action can be taken (perhaps just re-run the verification to print a relevant error message for each newly-invalid call).

B:

If a previously unscoped patcher or abstraction suddenly acquires its own scope – either by adding a scoping object and declaring a public/private attribute, or by adding a scope attribute if the scoping object is already in place – then any (nested) child objects acquire a new parent scope, and any method calls to methods in those objects become invalid.

A similar problem occurs if scoping attributes are removed, or a scoping object is deleted.

Should we be attempting to handle this by notifying and updating all dependent child objects, method receives, and method calls?

This becomes fairly problematic for method calls – to fully update those, the oo.call object needs to be re-instantiated with correct arguments and reconnected.

Or do we just throw an error notification and leave it to the developer to sort it out?


April 27, 2007 | 10:14 am

Quote: johnpitcairn wrote on Sun, 22 April 2007 05:56
—————————————————-
> Quote: Mattijs wrote on Sat, 21 April 2007 07:51
> —————————————————-
> > The basic idea is that methods and objects reveal themselves
> > to their parent object. A call propagates through the chain of
> > registered objects until it reaches its destination method.
>
> We’re definitely thinking along similar lines, though we are using different techniques to get there – I’m attempting to work in js as much as possible.

Yeah, about working as much as possible in js: I have made a quite elaborate scoping/voicing structure in js before. I can post the files if you want. The objects worked fine, but I ran into problems when I used the objects on a large scale (up to 1000 different instantiations). Js started crashing and having load order issues and slowing down significantly.

So now (completely contrary to you ;) I try to avoid js as much as possible. My last example is already in a grey area for me, but I’m afraid there is no alternative to traverse the patcher hierarchy.

On the other hand it is worth a lot to have a working prototype in js which we could then implement in C before using it on a large scale.

>
> Will you implement public vs private scoping?

Please see my reply to your next post for an answer to this question.

>
> I’m not too sure about the use of coll to register objects – a coll lookup for higher-indexed items takes longer, whereas a js lookup stays constant, so at some point (about 400 items?) it’s actually faster to do the lookup in js.

Would that mean there is some quicksort algorithm in the js lookup? I don’t know about that, but I do know that you’re right about coll slowing down with a lot of entries. Inherent to the oo concept I don’t think the amount of members of an object will easily exceed 50, but still.

Anyways, the idea of every object keeping its own list of registered members struck me as the most logical way to implement oo. I’ll try different techniques to optimize speed. For example it should be possible not to search the coll every call but only once during the instantiation of a new method/object.

>
> We both have an issue with what happens when a previously unscoped patcher has a scoping object added, or a previously scoped patcher has its scoping object deleted. Any child objects need to be re-scoped to the new parent.

True, see my next post.

>
> I’ll post an example of where I’m at once I work out a few more kinks.
>
—————————————————-


April 27, 2007 | 10:21 am

Not much time here too, this last week.

With regard to your two points: both are important issues, but I’d be very happy if I could use oo even if they are not taken care of. Even if I have to restart my patch before any new edits work, this will still be a huge upgrade of my current patches in both design and efficiency.

So I’d like to propose to observe some restrictions in a first stage, to make things easier to discuss and test. I was thinking:

- no error messages
- no speed optimizations
- no scope enforcing. Every object is public, every method is public, every variable is private.
- deleting and recreating objects is not properly accounted for.

Let me know what you think.

Mattijs

Quote: johnpitcairn wrote on Fri, 27 April 2007 01:19
—————————————————-
> Not getting much time to work onthis at present, but some further thoughts:
>
>
> A:
>
> Using a unique receive id in methods is not proving ideal. If you define a method [oo.method @public test], define multiple calls to that method, then delete and re-create the method using the same name, it will get a new receive id and all the calls will be wrong.
>
> So I’m looking at using the global call path (:object.object.method) for the method receive, which will at least remain constant if the parent object structure doesn’t change.
>
> Method calls should verify the call path at instantiation, checking that the specified objects exist, and if any object in the call path is private, the method call must be from the same scope as the object. Invalid calls should present some sort of error notification.
>
> I’m also looking at having method calls register their id in the method definition, so if the method call path changes, some sort of action can be taken (perhaps just re-run the verification to print a relevant error message for each newly-invalid call).
>
>
> B:
>
> If a previously unscoped patcher or abstraction suddenly acquires its own scope – either by adding a scoping object and declaring a public/private attribute, or by adding a scope attribute if the scoping object is already in place – then any (nested) child objects acquire a new parent scope, and any method calls to methods in those objects become invalid.
>
> A similar problem occurs if scoping attributes are removed, or a scoping object is deleted.
>
> Should we be attempting to handle this by notifying and updating all dependent child objects, method receives, and method calls?
>
> This becomes fairly problematic for method calls – to fully update those, the oo.call object needs to be re-instantiated with correct arguments and reconnected.
>
> Or do we just throw an error notification and leave it to the developer to sort it out?
>
—————————————————-


April 28, 2007 | 4:50 am

Quote: Mattijs wrote on Fri, 27 April 2007 22:21
—————————————————-
> no error messages

I currently print an error message when defining/making an invalid call (to a non-existent object/method, or to a method that’s private to the caller’s scope).

> no speed optimizations

Yeah, not much point until some real-world use is done. I can certainly see plenty of ways of speeding up my js code if necessary, however.

> no scope enforcing. Every object is public, every method is
> public, every variable is private.

Ah, already done here. I want private objects and methods, and in an all-js setting it’s easy enough to implement when a method call resolves its path. All variables are private.

> deleting and recreating objects is not properly accounted
> for.

Yep, at present I have no safety mechanism implemented, apart from removing a deleted object from the global id array and from its parent scope.


April 28, 2007 | 5:15 am

OK, I think this is mostly behaving itself now. The javascript is all in one file at present, fairly well commented but some things are in need of some tidying up. There are certainly better ways to do a few things that I can see, and some of the array notation is getting a bit out of hand. I’ll probably clean up the internal object structure to more resemble the actual object structure.

I think a good plan might be to aim for a global javascript library, and have much simpler class/method/v/call js objects call to that?

Turn on "debugprint" in the config options to get instantiation info printed.

Gotta go now, back Monday.


April 28, 2007 | 4:37 pm

Cool, I’m looking forward to checking it out asap.

I made a next version of my last example too. Here it is:

http://www.arttech.nl/OO%20example%20Mattijs%20070428.zip

Most import changes are
- coll only used once on init of each member, not on each call
- oo.v added
- a bit less javascript ;)
- clearly defined load sequence

Looks like we’re getting close :)

Cheers,
Mattijs

Quote: johnpitcairn wrote on Sat, 28 April 2007 07:15
—————————————————-
> OK, I think this is mostly behaving itself now. The javascript is all in one file at present, fairly well commented but some things are in need of some tidying up. There are certainly better ways to do a few things that I can see, and some of the array notation is getting a bit out of hand. I’ll probably clean up the internal object structure to more resemble the actual object structure.
>
> I think a good plan might be to aim for a global javascript library, and have much simpler class/method/v/call js objects call to that?
>
> Turn on "debugprint" in the config options to get instantiation info printed.
>
> Gotta go now, back Monday.
—————————————————-


April 29, 2007 | 9:49 pm

Quote: Mattijs wrote on Sun, 29 April 2007 04:37
—————————————————-
> – coll only used once on init of each member, not on each call

Yes, very important.

I’m having thoughts about a method call that can have its destination changed dynamically (an oo equivalent to forward), but this would obviously incur some lookup overhead. Doing the js lookup once for each destination then caching it might be an option, then only the first call to any destination would be slow – though once again, a coll would likely be needed for caching, and that becomes slower for higher entries anyway.

I have a few useful utilities in mind:

Keeping a record of all "bad" method calls, and providing a printout of those, and perhaps a command to locate them.

Similarly, a message to any method definition that will locate all calls to it.

A "print structure" command that can operate from any level. At first this would just be in the Max window, but ultimately it could be in its own window, allowing a click on any object to locate it.

I think you mentioned needing a way to handle "arrays" of objects? What sort of things would you need to do?


April 30, 2007 | 8:44 pm

Ok, I checked out your last version, john. Looks good :)

Some random comments:

I see you also have trouble with the load order, using deferlows etc. By deferring the patcherargs output, you will never know when to start running your program (i.e. after all oo initilization is done, but you don’t know when that is). In my last example, I initialized oo.call with a deferred loadbang. The difference is that loadbangs fire inside-out, which means that a deferred loadbang in top level marks the end of your initialization.

Of course your example was not an attempt at a most-easy-to-understand explanation of the system. But when thinking about that, I’d leave out the separate mention of the scoped abstraction. It’s conceptually equal to subpatcher.

Why allow unnamed but scoped patches? I like the strong visual link. Perhaps just don’t document the option of an unnamed scoped object? ;)

The scope info printout could be a little more elaborate (was hard to figure out without looking at the code). Maybe something like:

name: class1
scope: this patcher (as opposed to ‘self’, which sounds a bit oo-ish, which this doesn’t refer to), or patcher class1
global path: :L1.class1

putting stuff in a library is a good idea. This example already takes a noticeable time to load. But, agreed, no speed optimizations yet.

I never seen a global call such as ":L1.divide" in oo programming before unless a reference to the top class has been passed downward, but it won’t hurt ;)

Let’s mention explicitly that the hierarchy of the path doesn’t refer to classes defined inside classes (like class::class in C), but to classes -instantiated- by other classes (like myClass.myClass in C).

I’m still thinking about a way to pass a reference to an object from one object to another, as in
Math myMath = new Math(graphDrawer);
graphDrawer could be a class with support for a method inside Math that draws a graph to the screen. Although in practice the possibility to access an object’s parent class might be enough.

I will keep working on an as-minimal-as-possible approach with as less js as possible, that will perhaps leave out some second level features such as private vs public scoping and deleting objects. This way I’ll be able to test the concepts in a real life situation asap.

About arrays. You’re right. Look at the patch below. Say I want 64 gridshapes on my screen. They all need to have their own receive to set their parameters. When I change one, I want them all to change. In my example I’d have to copy the one I changed and paste replace the rest with it, then change the index arguments. Btw I don’t necessarily want to do this with abstractions. They make debugging 10 x less efficient.

#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#N vpatcher 244 235 844 635;
#P window setfont "Sans Serif" 9.;
#P newex 130 45 44 196617 zl nth 2;
#P newex 130 26 64 196617 patcherargs;
#P window linecount 1;
#P newex 130 64 155 196617 sprintf set gridshapeParams-%i;
#P window linecount 0;
#P newex 114 64 14 196617 r;
#P newex 114 110 95 196617 jit.gl.gridshape foo;
#P connect 2 0 1 0;
#P connect 3 0 4 0;
#P connect 4 0 2 0;
#P pop;
#P newobj 38 63 76 196617 p drawShape 2;
#N vpatcher 244 235 844 635;
#P window setfont "Sans Serif" 9.;
#P newex 130 45 44 196617 zl nth 2;
#P newex 130 26 64 196617 patcherargs;
#P window linecount 1;
#P newex 130 64 155 196617 sprintf set gridshapeParams-%i;
#P window linecount 0;
#P newex 114 64 14 196617 r;
#P newex 114 110 95 196617 jit.gl.gridshape foo;
#P connect 2 0 1 0;
#P connect 3 0 4 0;
#P connect 4 0 2 0;
#P pop;
#P newobj 38 42 76 196617 p drawShape 1;
#P comment 47 96 32 196617 etc;
#P window clipboard copycount 3;

Mattijs

Quote: johnpitcairn wrote on Sat, 28 April 2007 07:15
—————————————————-
> OK, I think this is mostly behaving itself now. The javascript is all in one file at present, fairly well commented but some things are in need of some tidying up. There are certainly better ways to do a few things that I can see, and some of the array notation is getting a bit out of hand. I’ll probably clean up the internal object structure to more resemble the actual object structure.
>
> I think a good plan might be to aim for a global javascript library, and have much simpler class/method/v/call js objects call to that?
>
> Turn on "debugprint" in the config options to get instantiation info printed.
>
> Gotta go now, back Monday.
—————————————————-


April 30, 2007 | 8:55 pm

Quote: johnpitcairn wrote on Sun, 29 April 2007 23:49
—————————————————-
> Quote: Mattijs wrote on Sun, 29 April 2007 04:37
> —————————————————-
> > – coll only used once on init of each member, not on each call
>
> Yes, very important.
>
> I’m having thoughts about a method call that can have its destination changed dynamically (an oo equivalent to forward),

Good idea. Same holds for object names hehe ;)

> but this would obviously incur some lookup overhead. Doing the js lookup once for each destination then caching it might be an option, then only the first call to any destination would be slow – though once again, a coll would likely be needed for caching, and that becomes slower for higher entries anyway.

Sounds like a lot of work to do this properly..

>
> I have a few useful utilities in mind:
>
> Keeping a record of all "bad" method calls, and providing a printout of those, and perhaps a command to locate them.
>
> Similarly, a message to any method definition that will locate all calls to it.
>
> A "print structure" command that can operate from any level. At first this would just be in the Max window, but ultimately it could be in its own window, allowing a click on any object to locate it.

These utilities can be very useful indeed.

>
> I think you mentioned needing a way to handle "arrays" of objects? What sort of things would you need to do?

Yep, see previous post.

Mattijs


April 30, 2007 | 10:01 pm

Quote: Mattijs wrote on Tue, 01 May 2007 08:44
—————————————————-
> I see you also have trouble with the load order, using
> deferlows etc. By deferring the patcherargs output,

That’s done in oo.call only, so the object structure has initialized from patcherargs before any attempts are made to resolve a call path. The call path could be resolved at first call, but that would mean the first call would be slow.

> never know when to start running your program (i.e. after all
> oo initilization is done, but you don’t know when that is). In
> my last example, I initialized oo.call with a deferred
> loadbang. The difference is that loadbangs fire inside-out,
> which means that a deferred loadbang in top level marks the
> end of your initialization.

Unfortunately for me this might mean the call paths may not be resolvable at load. I do have some other ideas about an "init complete" message at top level however.

> I’d leave out the separate mention of the scoped abstraction.
> It’s conceptually equal to subpatcher.

With slightly different behaviour if using an un-named scoped abstraction – it will get the abstraction name, whereas patcher will get "p".

> Why allow unnamed but scoped patches? I like the strong visual
> link. Perhaps just don’t document the option of an unnamed
> scoped object? ;)

Just an example that it’s possible. I was thinking this might be useful to use a patcher to provide a privately-scoped method body, connected to the method declaration. In that case, we don’t care abot the name.

I like the strong visual link too, but I can see situations where you might not want/need to explicitly name 100 objects, especially if they are scripted into place.

It’s also possible to declare a default @public/@private (name) attribute in the patcherargs object if desired. Even if done for an abstraction, declarations on the object itself would override the default.

> The scope info printout could be a little more elaborate (was
> hard to figure out without looking at the code).

Yes, I’m thinking an expand/collapse on the bpatcher to show more and better info.

> I never seen a global call such as ":L1.divide" in oo
> programming before unless a reference to the top class has
> been passed downward, but it won’t hurt ;)

I was wanting to avoid reserving an explicit name for the top level. And there needs to be a way to indicate that it _is_ a global call path, whereas "top.L1.divide" could also be referring to a path from the current local scope.

> Let’s mention explicitly that the hierarchy of the path
> doesn’t refer to classes defined inside classes (like
> class::class in C), but to classes -instantiated- by other
> classes (like myClass.myClass in C).

Yes, that’s why I chose "." as the separator (it could be made user-definable). Max doesn’t really have a concept of a defined class that isn’t instantiated anywhere but is still "known" at runtime.

> I’m still thinking about a way to pass a reference to an
> object from one object to another, as in
> Math myMath = new Math(graphDrawer);
> graphDrawer could be a class with support for a method inside
> Math that draws a graph to the screen.

So the graphDrawer would be registered inside myMath? And myMath would call something like graphDrawer.draw?

Wouldn’t a simple argument at myMath instantiation be sufficient?

Alternately would a message to a setOutput method in myMath be appropriate?

Store the reference in a variable until you need it?

> I will keep working on an as-minimal-as-possible approach with
> as less js as possible

I suspect that I’ll wind up translating at least some of my js into max objects if/when I optimize.

> About arrays. You’re right. Look at the patch below. Say I
> want 64 gridshapes on my screen. They all need to have their
> own receive to set their parameters. When I change one, I want
> them all to change.

Register their setParameters methods in a notifier class? The notifier would either use a single coll-forward, or actually instantiate & connect one oo.call instance per destination (faster notification, slower instantiation).

In my version I’d want those call paths checked for existence and in-scopeness from the notification scope of course.

Or simply connect them with patchcords and pass the shared parameters from one to the next?

Or instantiate them inside a parent class that has a setParams method that connects via patchcords to each of them?

I see no reason a class instantiation (especially if declared private) shouldn’t be able to have conventional inlets/outlets for this sort of thing?


May 6, 2007 | 8:01 pm

Took me some time to get back to this thread, but here I am ;)

Quote: johnpitcairn wrote on Tue, 01 May 2007 00:01
—————————————————-
> Quote: Mattijs wrote on Tue, 01 May 2007 08:44
> —————————————————-
> > I see you also have trouble with the load order, using
> > deferlows etc. By deferring the patcherargs output,
>
> That’s done in oo.call only, so the object structure has initialized from patcherargs before any attempts are made to resolve a call path.

I don’t think you understand, you could have a look at my latest example, it also relies on patcherargs to initialize the object structure (because of the persisiting problem that the patcher object isn’t initialized on creation of the js object but only after loadbang time.. cycling?). Nonetheless a deferred loadbang will be guaranteed to occur -after- all patcherargs.

> The call path could be resolved at first call, but that would mean the first call would be slow.

Yep, I’ve considered that too. I think it could result in some unintuitive behaviour, so I’d rather not do that.

>
> > never know when to start running your program (i.e. after all
> > oo initilization is done, but you don’t know when that is). In
> > my last example, I initialized oo.call with a deferred
> > loadbang. The difference is that loadbangs fire inside-out,
> > which means that a deferred loadbang in top level marks the
> > end of your initialization.
>
> Unfortunately for me this might mean the call paths may not be resolvable at load. I do have some other ideas about an "init complete" message at top level however.

Have a look at the overridable pv example I posted some time ago. It containts a seperate loading order system, done in js with Globals. I chose not to use it in my oo attempts because I try to depend on js as less as possible for reasons explained earlier.

>
> > I’d leave out the separate mention of the scoped abstraction.
> > It’s conceptually equal to subpatcher.
>
> With slightly different behaviour if using an un-named scoped abstraction – it will get the abstraction name, whereas patcher will get "p".
>
> > Why allow unnamed but scoped patches? I like the strong visual
> > link. Perhaps just don’t document the option of an unnamed
> > scoped object? ;)
>
> Just an example that it’s possible. I was thinking this might be useful to use a patcher to provide a privately-scoped method body, connected to the method declaration. In that case, we don’t care abot the name.
>
> I like the strong visual link too, but I can see situations where you might not want/need to explicitly name 100 objects, especially if they are scripted into place.
>
> It’s also possible to declare a default @public/@private (name) attribute in the patcherargs object if desired. Even if done for an abstraction, declarations on the object itself would override the default.
>
> > The scope info printout could be a little more elaborate (was
> > hard to figure out without looking at the code).
>
> Yes, I’m thinking an expand/collapse on the bpatcher to show more and better info.

kewl

>
> > I never seen a global call such as ":L1.divide" in oo
> > programming before unless a reference to the top class has
> > been passed downward, but it won’t hurt ;)
>
> I was wanting to avoid reserving an explicit name for the top level. And there needs to be a way to indicate that it _is_ a global call path, whereas "top.L1.divide" could also be referring to a path from the current local scope.

Ah, it’s not about the syntax itsself, more about the concept of having a global call possibility. I don’t think there is any such thing in regular oo languages.

>
> > Let’s mention explicitly that the hierarchy of the path
> > doesn’t refer to classes defined inside classes (like
> > class::class in C), but to classes -instantiated- by other
> > classes (like myClass.myClass in C).
>
> Yes, that’s why I chose "." as the separator (it could be made user-definable).

Absolutely, no, I agree, but sometimes I get confused myself about what it is exactly that the path represents, seeing that the instances (subpatchers) are visually ‘inside’ the class that creates them. The C equivalent of writing a class ‘inside’ another class is a different hierarchy than the hierarchy your path represents (what are the official names for these two hierarchies btw?). Also, a term like ‘super class’ doesn’t apply to this path structure. The terms ‘super class’ or ‘sub class’ would fit in the :: syntax in C.

> Max doesn’t really have a concept of a defined class that isn’t instantiated anywhere but is still "known" at runtime.

True. I’ve been thinking about that. I believe there is some kind of equivalent, maybe somewhere in loading order.

>
> > I’m still thinking about a way to pass a reference to an
> > object from one object to another, as in
> > Math myMath = new Math(graphDrawer);
> > graphDrawer could be a class with support for a method inside
> > Math that draws a graph to the screen.
>
> So the graphDrawer would be registered inside myMath? And myMath would call something like graphDrawer.draw?
>
> Wouldn’t a simple argument at myMath instantiation be sufficient?

Um, I don’t follow you here. What is the instantiation? And what would an argument with a reference be like? An Id? I for myself don’t know yet. I was fiddling with id’s that are actually output by objects in one of my earlier examples, but discarded the idea for the moment.

>
> Alternately would a message to a setOutput method in myMath be appropriate?
> Store the reference in a variable until you need it?

I guess that would do. But still we need an idea about how to make a reference to an instance an argument of a method. And in what form it could be stored?

>
> > I will keep working on an as-minimal-as-possible approach with
> > as less js as possible
>
> I suspect that I’ll wind up translating at least some of my js into max objects if/when I optimize.

Guess so. I can imagine that by that time I have some first proofs of concept done with the more limited set of primary features of my approach, in the sense of bigger patches based on the oo system. The new insights that this will probably generate could be included in your externals.

>
> > About arrays. You’re right. Look at the patch below. Say I
> > want 64 gridshapes on my screen. They all need to have their
> > own receive to set their parameters. When I change one, I want
> > them all to change.
>
> Register their setParameters methods in a notifier class? The notifier would either use a single coll-forward, or actually instantiate & connect one oo.call instance per destination (faster notification, slower instantiation).

For now I reverted to the very simple but very workable solution that Stephan Tiedje came up with some time ago. See my next post for that.

>
> In my version I’d want those call paths checked for existence and in-scopeness from the notification scope of course.

Sure :)

>
> Or simply connect them with patchcords and pass the shared parameters from one to the next?
>
> Or instantiate them inside a parent class that has a setParams method that connects via patchcords to each of them?
>
> I see no reason a class instantiation (especially if declared private) shouldn’t be able to have conventional inlets/outlets for this sort of thing?

I’m not sure about getting patch cords involved in this at all. There is a big chance that it constrains the patch structure too much. But of course we’d have to try to know for sure.

See my next post for an updated version of my example.

Mattijs


May 6, 2007 | 8:14 pm

Here is a new version. Apart from small modifications it shows how to deal with arrays of objects now. Also added some code equivalents in comments.

And it has even less objects ;) I dare to challenge people like Stefan Tiedje and Roman Thilenius (sorry for stereotyping ;) to come up with a patch that does the same with less objects. ;))

http://www.arttech.nl/OO%20example%20Mattijs%20070506.zip

All comments and additions are welcome, as always.

Cheers,
Mattijs


May 7, 2007 | 2:21 am

Haven’t had a chance to look at your latest (I’m not at my Max machine right now), but I have over the past few days been rewriting what I’ve done so far without using any javascript.

The only requirement to do so is that every patcher/class in a heirarchy must contain the oo.object abstraction (but does not need to define a scope, which is still done via attributes). The oo.object initially uses pattrforward parent:: to discover its immediate parent. This requirement could easily be removed with a very little javascript of course.

In response to the object-array management thing, I’m also looking at storing multiple declared named instances in such a way that you can call the same method in all those instances using a single method call (as well as calling a single instance only using instance-number syntax).

This could also extend to calling via multiple same-named class instantiations in the middle of a call path (ie call L1.L2.L3.method, where there are multiple L2s instantiated in L1), but that might be best left as an option.


May 7, 2007 | 9:27 am

Quote: johnpitcairn wrote on Mon, 07 May 2007 04:21
—————————————————-
> Haven’t had a chance to look at your latest (I’m not at my Max machine right now), but I have over the past few days been rewriting what I’ve done so far without using any javascript.

.. cool! I’m curious what you’ve made.

Pity eh? Javascript is really not up to a task like this.. dear list, let’s keep in mind from now on that ‘but you can always do it in javascript’ is not a valid reply per se.

>
> The only requirement to do so is that every patcher/class in a heirarchy must contain the oo.object abstraction (but does not need to define a scope, which is still done via attributes). The oo.object initially uses pattrforward parent:: to discover its immediate parent. This requirement could easily be removed with a very little javascript of course.
>
> In response to the object-array management thing, I’m also looking at storing multiple declared named instances in such a way that you can call the same method in all those instances using a single method call (as well as calling a single instance only using instance-number syntax).
>
> This could also extend to calling via multiple same-named class instantiations in the middle of a call path (ie call L1.L2.L3.method, where there are multiple L2s instantiated in L1), but that might be best left as an option.
>
—————————————————-


May 7, 2007 | 11:42 pm

Quote: Mattijs wrote on Mon, 07 May 2007 08:14
—————————————————-
> Here is a new version. Apart from small modifications it shows
> how to deal with arrays of objects now. Also added some code
> equivalents in comments.

Nice. Looks very usable, with limitations as you’ve noted elsewhere (everything public, etc).

I’m still a little uncomfortable about using the script-name functionality to handle naming for "arrays" of identical objects. As far as possible, I’d like the oo-system to steer clear of hijacking existing functionality (script-names, pattr) to ensure maximum drop-in compatibility with existing apps.

I like the array notation in call paths, however, I’ll switch to that…


May 8, 2007 | 5:49 am

Mattijs Kneppers schrieb:
> Here is a new version. Apart from small modifications it shows how to
> deal with arrays of objects now. Also added some code equivalents in
> comments.
>
> And it has even less objects ;) I dare to challenge people like
> Stefan Tiedje and Roman Thilenius (sorry for stereotyping ;) to come
> up with a patch that does the same with less objects. ;))

I don’t know if my patch would do the same, but I’d just throw in
pattrmarker, pattrs and patrrforwards and skip all of your oo stuff… ;-)
To be honest I lost interest to follow the thread in detail, because I
don’t see the necessity. If you would supply a real world example which
would only be possible with your oo methods or at least show a "simpler
to understand" way of doing things I am all ears again. At the moment it
looks for me like a "why easy if you can have it complicated" method…

I know its aimed at bigger projects…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


May 8, 2007 | 8:37 am

Quote: Stefan Tiedje wrote on Tue, 08 May 2007 07:49
—————————————————-
> Mattijs Kneppers schrieb:
> > Here is a new version. Apart from small modifications it shows how to
> > deal with arrays of objects now. Also added some code equivalents in
> > comments.
> >
> > And it has even less objects ;) I dare to challenge people like
> > Stefan Tiedje and Roman Thilenius (sorry for stereotyping ;) to come
> > up with a patch that does the same with less objects. ;))
>
> I don’t know if my patch would do the same, but I’d just throw in
> pattrmarker, pattrs and patrrforwards and skip all of your oo stuff… ;-)
> To be honest I lost interest to follow the thread in detail, because I
> don’t see the necessity. If you would supply a real world example which
> would only be possible with your oo methods or at least show a "simpler
> to understand" way of doing things I am all ears again. At the moment it
> looks for me like a "why easy if you can have it complicated" method…

Ah, that’s right on the mark. I think we’re quite close to implementing the oo objects in a real world bigger patch, which will probably explain a lot. IF it works, of course.

>
> I know its aimed at bigger projects…
>
> Stefan
>
> —
> Stefan Tiedje————x——-
> –_____———–|————–
> –(_|_ —-|—–|—–()——-
> — _|_)—-|—–()————–
> ———-()——–www.ccmix.com
>
>
>
—————————————————-


May 8, 2007 | 8:03 pm

Here’s a little speed test. It roughly indicates that the oo system (based on receives) is approximately 6x as fast as the pattr system.

http://www.arttech.nl/speed%20test.zip

I also noticed that the load time of the oo system is much bigger (not completely unexpected of course). I’m curious whether porting the js files to C would make a big difference there.

Mattijs


May 8, 2007 | 10:32 pm

Quote: Mattijs wrote on Wed, 09 May 2007 08:03
—————————————————-
> Here’s a little speed test. It roughly indicates that the oo
> system (based on receives) is approximately 6x as fast as the
> pattr system.

pattrforward sending directly to a named int, float, or route might be rather faster than binding via a pattr object.

> I also noticed that the load time of the oo system is much bigger
> (not completely unexpected of course). I’m curious whether
> porting the js files to C would make a big difference there.

Er, yeah, not even C. Preliminary testing with the non-js version I’m working on has 100 simple objects as per your example loading in about 1.5 seconds on my 1GHz powerbook (old, eh?) compared to about 12 seconds for your js version (tested using a timer on that deferred loadbang).


May 9, 2007 | 4:19 am

Quote: johnpitcairn wrote on Wed, 09 May 2007 10:32
—————————————————-
> Er, yeah, not even C. Preliminary testing with the non-js version I’m working on has 100 simple objects as per your example loading in about 1.5 seconds on my 1GHz powerbook (old, eh?) compared to about 12 seconds for your js version (tested using a timer on that deferred loadbang).
—————————————————-

Actually, that’s 150ms for the object-discovery and name registration etc, waaay faster than js.

This is, however, offset considerably by the seriously larger number of max objects needed inside oo.object, ie the patch with 100 methods is taking about 6 seconds to instantiate all the (non-js) oo.objects, then the object-discovery and registration takes 150ms. Overall, about half the load time of your js version.

Some optimisation could certainly be done to reduce the number of objects, comments, segmented cables, etc, but yes, coding oo.object as a single C object should radically improve upon that.


May 9, 2007 | 10:19 am

Am 09.05.2007 um 00:32 schrieb John Pitcairn:
> —————————————————-
>> Here’s a little speed test. It roughly indicates that the oo
>> system (based on receives) is approximately 6x as fast as the
>> pattr system.
>
> pattrforward sending directly to a named int, float, or route might
> be rather faster than binding via a pattr object.

This will almost certainly be the case.

jb


May 9, 2007 | 2:51 pm

I’m a bit late to this thread, as I haven’t been actively reading the list/forums for a while now… This thread did catach my attention though.

The comment I would like to address is this:
> Agreed, JAMOMA is about standaridizing a Max api.
> OO is about the the structuring and organizatrion of thought.

While Jamoma does try to standardize certain ways of doing things in Max, the reason it does this is to serve structural and organizational goals. In fact, structural principles are the most important aspect of Jamoma.

The entire implementation of Jamoma is conceived as an MVC framework ( http://en.wikipedia.org/wiki/Model-view-controller ) found frequently in object-oriented design (Apple’s Cocoa and Ruby-on-Rails are two prominent examples).

As a bit of a thesaurus on how OO terms can be appropriated to Jamoma modules:

* Class = module
* Pubic variable = parameter
* Public method = message
* Private members are anything not exposed with the above
* etc.

Module inheritance is something that Jamoma’s core development team began to discuss at a workshop in Albi, France this past Spring. This is where a module can inherit from another module. There isn’t an implementation of it yet, but it is under discussion — this is clearly an OO-inspired case.

Of course, given that what OO means can spark ‘religious’ reactions in people, I’m sure that people will disagree — but the point is that OO considerations have weighed heaviliy throughout the entire development of Jamoma, and that continues.

Hopefully this is helpful somehow!
Tim


May 10, 2007 | 7:18 am

That’s true, using pattrforward is much faster than pattr.

About loading times: by implementing the search for an object with getnamed instead of a while loop that scans the patcher names, the load time decreased from 12 to 1 second(s)!

Does this mean that the javascript implementation itself is slow, not just the js-max bridge? Unless the bridge is crossed with every property request..?

Would it be possible to add a method in to patcher, getpatcher(name) for example, that returns the first abstraction with the given name (not varname)?

Anyway, the updated speed tests are here:

http://www.arttech.nl/speed%20test%20070509.zip

Still thinking about a way to set the name of the oo.object abstraction with javascript before patcherargs fires..

Also looking into the SDK for ways to traverse patcher hierarchy and such. So far I only wrote externals for data management and some dsp, didn’t spend much time interfacing with max. If someone happens to have an example that does stuff similar to the javascripts in these oo examples and you’re willing to share.. that would be great.

Mattijs

Quote: Jeremy Bernstein wrote on Wed, 09 May 2007 12:19
—————————————————-
>
> Am 09.05.2007 um 00:32 schrieb John Pitcairn:
> > —————————————————-
> >> Here’s a little speed test. It roughly indicates that the oo
> >> system (based on receives) is approximately 6x as fast as the
> >> pattr system.
> >
> > pattrforward sending directly to a named int, float, or route might
> > be rather faster than binding via a pattr object.
>
> This will almost certainly be the case.
>
> jb
>
—————————————————-


May 10, 2007 | 7:25 am

Hi Tim,

So funny that everyone keeps referring to a religous aspect of oo programming and I really don’t have a clue what that is about. Can someone send me a link or something that illustrates that idea?

Thanks,
Mattijs

> Of course, given that what OO means can spark ‘religious’ reactions in people, I’m sure that people will disagree — but the point is that OO considerations have weighed heaviliy throughout the entire development of Jamoma, and that continues.
>
> Hopefully this is helpful somehow!
> Tim
>
—————————————————-


May 10, 2007 | 9:12 am

Timothy Place schrieb:
> I’m a bit late to this thread, as I haven’t been actively reading the
> list/forums for a while now… This thread did catach my attention
> though.

I followed this thread on/off, and just out of my intuition, I’d advise
Mattjis and John to really look at Jamoma deeper, because I believe what
you have been talking and testing about recently is all there, but in an
advanced state. It would be great if these discussions would be
incorporated into Jamoma instead of creating something very similar
aside of it…

just my 2 cents…

Stefan


Stefan Tiedje————x——-
–_____———–|————–
–(_|_ —-|—–|—–()——-
– _|_)—-|—–()————–
———-()——–www.ccmix.com


Viewing 150 posts - 1 through 150 (of 202 total)