pattrhub shortcomings and a nice crash

Diemo Schwarz's icon

I'm somehow underwhelmed by the pattr snakepit of objects. For all its bloat and complexity, it doesn't go to 100%, and can crash.... read on.

In the control patch below, I'm trying to refer, via [pattrhub ::testui], to a remote top-level UI patcher that contains a [pattrmarker testui].

param mapping test UI.maxpat
Max Patch
remote patch testui

param mapping test control.maxpat
Max Patch
control patch

  1. I'd expect pattrhub to also send me changes made to parameters in the remote patch, like pattrstorage can do with @outputmode, but that works only in the remote patch, DUH!

  2. When the remote patch is not open *before*, pattrhub ignores its arg (and you need to resend the "patcher") message, so no loadbang will do, but one needs to devise a send/receive logic where the remote patch says "I'm here now". I'd expect pattrhub to be notified that the pattrmarker is created (by loading the remote patch or creating it), and connect automatically.

  3. Once connected, after closing the remote UI patch, pattrhub crashes when trying to change a remote param:

Thread 0 Crashed:: CrBrowserMain  Dispatch queue: com.apple.main-thread
0   com.cycling74.Max                 0x00000001018528c6 object_attr_get + 38
1   com.cycling74.Max                 0x00000001018993a3 object_attr_getvalueof_imp + 99
2   com.cycling74.Max                 0x0000000101853627 object_attr_getobj + 55
3   com.cycling74.pattrhub            0x0000000126dd97c2 pattrhub_resolve_object_impl + 146
4   com.cycling74.pattrhub            0x0000000126dd7ab2 pattrhub_anything + 194
5   com.cycling74.Max                 0x000000010187e8e3 typedmess_fun + 371
6   com.cycling74.Max                 0x0000000101869bb2 outlet_anything + 1426
7   com.cycling74.Max                 0x000000010187e8e3 typedmess_fun + 371
8   com.cycling74.Max                 0x0000000101848f9a aeval + 2314
9   com.cycling74.Max                 0x000000010184863e atombuf_eval + 142
10  com.cycling74.message             0x0000000107741a17 jmessage_atombuf_eval + 567
11  com.cycling74.message             0x000000010773f68f jmessage_int + 175
12  com.cycling74.Max                 0x000000010187c878 outlet_int + 1560
13  com.cycling74.number              0x00000001276dc029 jnumber_mousedragdelta + 409
Diemo Schwarz's icon

For the record: I got the additional tip to look at the patcher inspector for the parent and the child's "global patcher name" attribute. the pattrmarker sets the parent's one and then refuses to set the child to the same name when encapsulating.

Jeremy's icon

Thanks, looks like you've found some bugs and oversights, which we'll take a look at. In particular, I think we can improve the automatic registration/unregistration in pattrhub, which probably haven't been significantly updated since the objects were originally added to Max. Obviously, crashes aren't ideal, so keep an eye open for improvements.

As for the global patcher name issue (which tip I gave you on Facebook), I think we can improve how pattrmarker handles name conflicts (looks like it just fails at the moment). I need to think about your expectation that encapsulation of a pattrmarker object moves the global patcher name. We could certainly provide some ways for pattrmarker to inform you when the wish-name doesn't match the real-name, but I don't know if moving the object should automove the name.

Here's why: the pattrmarker object modifies a patcher attribute; if you delete the pattrmarker object entirely, the global patcher name is retained, and in fact, you never even need a pattrmarker object in order to award this name to a patcher, you can just type it in the inspector. This has roots in the evolution of pattrmarker from a 3rd party object/feature to a core object/feature, and that's just how it is. But I don't know if it's appropriate for an encapsulation to change attributes in the parent patcher. On the other hand, the presence of a pattrmarker is a fairly good indication that you're explicitly assigning that attribute using the pattrmarker object mechanism, so it's worth thinking through.

Diemo Schwarz's icon

> As for the global patcher name issue (which tip I gave you on Facebook),

thanks indeed, you understood my question and situation better than myself!


> I think we can improve how pattrmarker handles name conflicts (looks like it just fails
> at the moment). I need to think about your expectation that encapsulation of a
> pattrmarker object moves the global patcher name. We could certainly provide
> some ways for pattrmarker to inform you when the wish-name doesn't match the
> real-name, but I don't know if moving the object should automove the name.

Yes, a warning would already be helpful (but could be missed when it is output only when encapsulating... don't know if that name mismatch state could be warned about at each patch load.)

> Here's why: the pattrmarker object modifies a patcher attribute; if you delete
> the pattrmarker object entirely, the global patcher name is retained, and in
> fact, you never even need a pattrmarker object in order to award this name to a
> patcher, you can just type it in the inspector. This has roots in the evolution
> of pattrmarker from a 3rd party object/feature to a core object/feature, and
> that's just how it is. But I don't know if it's appropriate for an encapsulation
> to change attributes in the parent patcher. On the other hand, the presence of a
> pattrmarker is a fairly good indication that you're explicitly assigning that
> attribute using the pattrmarker object mechanism, so it's worth thinking through.

If that's an option, I'd definitely be for making the "global patcher name" attr editable, and make pattrmarker optional. It would make for one less member in that unwieldy zoo of pattr* objects (one less moment of head scratching "what is this good for? do I really need to remember this object?").

While we're rethinking this for simplification options, couldn't the patcher name be defined by the scripting name? That's one thing everyone is already used to, and easy to reach via CMD-'.

Thanks a lot for caring!...
                                ...Diemo

Diemo Schwarz's icon

Another crash when setting from OSC, investigating...

Thread 0 Crashed:: CrBrowserMain Dispatch queue: com.apple.main-thread
0 com.cycling74.Max     0x00000001063b48c6 object_attr_get + 38
1 com.cycling74.Max     0x00000001063fb3a3 object_attr_getvalueof_imp + 99
2 com.cycling74.Max     0x00000001063b5627 object_attr_getobj + 55
3 com.cycling74.pattrhub     0x000000011737d7c2 pattrhub_resolve_object_impl + 146
4 com.cycling74.pattrhub     0x000000011737bab2 pattrhub_anything + 194
5 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
6 com.cycling74.Max     0x00000001063cbbb2 outlet_anything + 1426
7 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
8 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
9 com.cycling74.Max     0x00000001063cbbb2 outlet_anything + 1426
10 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
11 com.cycling74.Max     0x00000001063aaf9a aeval + 2314
12 com.cycling74.Max     0x00000001063aa63e atombuf_eval + 142
13 com.cycling74.message     0x000000012b4cba17 jmessage_atombuf_eval + 567
14 com.cycling74.Max     0x00000001063dfb06 outlet_list + 1398
15 com.cycling74.Max     0x00000001063df1b2 outlet_float + 1458
16 com.cycling74.scale     0x000000012bae55f8 scale_float + 856
17 com.cycling74.Max     0x00000001063df3a3 outlet_float + 1955
18 com.cycling74.Max     0x00000001063ddd79 outlet_bang + 1385
19 com.cycling74.Max     0x00000001063ddd79 outlet_bang + 1385
20 com.cycling74.Max     0x00000001063ddd79 outlet_bang + 1385
21 com.cycling74.Max     0x00000001063ddf50 outlet_bang + 1856
22 com.cycling74.Max     0x00000001064db736 trigger_iterate + 86
23 com.cycling74.Max     0x00000001064db5f5 trigger_anything + 37
24 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
25 com.cycling74.Max     0x00000001063cbbb2 outlet_anything + 1426
26 com.cycling74.Max     0x00000001063e08e3 typedmess_fun + 371
27 com.cycling74.Max     0x00000001063cbbb2 outlet_anything + 1426
28 com.cycling74.udpreceive     0x000000012a60229a osc_parse_osc_packet + 1866
29 com.cycling74.udpreceive     0x000000012a601a30 udprecv_clock_tick + 80

Jeremy's icon

Diemo, this is the same crash as above, don't go to any extra effort to isolate it.

Jeremy's icon

If that's an option, I'd definitely be for making the "global patcher name" attr editable, and make pattrmarker optional. It would make for one less member in that unwieldy zoo of pattr* objects (one less moment of head scratching "what is this good for? do I really need to remember this object?").

This is already the case -- the global patcher name attribute is always available to be set, even without a pattrmarker object. The reason it's not synonymous with the patcher's scripting name is that every patcher in a pattr hierarchy has a name for navigation purposes, but you don't generally want those patchers to be available as "pattrmarked" top-level nodes. Also, pattr/scripting names are patcher-local, while pattrmarker names are global.

I'm still thinking about the name-moves-with-pattrmarker-object expectation, but I'm not 100% convinced. In some ways, it's a question of what is easier to document. In any case, the name collision issue needs to be sorted for people using pattrmarker/global patcher name inside of abstractions/poly~/etc.

I've fixed the pattrhub registration issues, though (and thus the crash), and that fix will eventually make it into an updated Max. But I can't say when at this moment...

Jeremy's icon

@Diemo, my mistake, looks like there's a bug in the way the attribute is presented to the inspector so that the field isn't editable if a pattrmarker object is instantiated anywhere. Clearly not ideal.

vichug's icon

i guess it' not editable because if you were to change it manually, the next patcher restart would trigger the instantiation of pattrmarker and hence re-change the patcher's scripting name ?

Jeremy's icon

@vichug yeah, that's correct. the next version will still be uneditable, but only if a pattrmarker is in the patcher in question. If there's no pattrmarker providing the name, that field will be editable.

Diemo Schwarz's icon

Hi Jeremy, thanks for the clarification of patcher name/scripting name. It makes complete sense.

What do you think about the expectation that pattrhub also output param changes in the remote patch (with an appropriate @outputmode), and thus make it an actual bidirectional hub, not just a control object? That would allow to completely take over (i.e. link to a hw controller) an existing (sub)patch, without having to instrument it by pattrstorage and send objects.

Jeremy's icon

@diemo sounds reasonable to me, but no promises. pattrhub was originally a fairly primitive object which was largely ignored when pattr, pattrstorage and friends became more complicated (since no one seemed to use it very much). I'm definitely open to making it more useful, and most of the infrastructure is available to do so.

Diemo Schwarz's icon

Hi again, another occasional pvar crash when closing a patch, don't know if it's related (and thanks for the hopeful response to the pattrhub suggestion, BTW):

Thread 0 Crashed:: CrBrowserMain  Dispatch queue: com.apple.main-thread
0   com.cycling74.Max                 0x000000010601c115 pvar_free + 213
1   com.cycling74.Max                 0x0000000105f803ce freeobject + 190
2   com.cycling74.Max                 0x0000000105ef296a jnewobj_free + 26
3   com.cycling74.Max                 0x0000000105f803ce freeobject + 190
4   com.cycling74.Max                 0x0000000105f7725b object_free + 27
5   com.cycling74.Max                 0x00000001060418ef jpatcher_free + 319
6   com.cycling74.Max                 0x0000000105f803ce freeobject + 190
7   com.cycling74.Max                 0x0000000105f7725b object_free + 27
8   com.cycling74.Max                 0x0000000105f736e0 object_method_imp + 352
9   com.cycling74.Max                 0x0000000105cc7fcc jwind_close + 1052
10  com.cycling74.Max                 0x0000000105f87794 object_method_typed + 148
11  com.cycling74.Max                 0x0000000105eec54f jmenuitem_process + 559
12  com.cycling74.Max                 0x0000000105eec2fd jmenu_process + 141
13  com.cycling74.Max                 0x0000000105e17f4b interface_process + 11
14  com.cycling74.Max                 0x000000010636ebec juce::JuceMainMenuHandler::invokeDirectly(int, int) + 60
15  com.cycling74.Max                 0x000000010636eb54 juce::MessageManager::AsyncCallInvoker<juce::JuceMainMenuHandler::invoke(juce::PopupMenu::Item const&, int) const::'lambda'()>::messageCallback() + 52
16  com.cycling74.Max                 0x000000010624b36d juce::MessageQueue::runLoopSourceCallback(void*) + 269
17  com.apple.CoreFoundation          0x00007fff32adad17 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
18  com.apple.CoreFoundation          0x00007fff32adacbd __CFRunLoopDoSource0 + 108
19  com.apple.CoreFoundation          0x00007fff32abe67b __CFRunLoopDoSources0 + 195
20  com.apple.CoreFoundation          0x00007fff32abdc45 __CFRunLoopRun + 1189
21  com.apple.CoreFoundation          0x00007fff32abd54e CFRunLoopRunSpecific + 455
22  com.apple.HIToolbox               0x00007fff31d1c1ab RunCurrentEventLoopInMode + 292
23  com.apple.HIToolbox               0x00007fff31d1bee5 ReceiveNextEventCommon + 603
24  com.apple.HIToolbox               0x00007fff31d1bc76 _BlockUntilNextEventMatchingListInModeWithFilter + 64
25  com.apple.AppKit                  0x00007fff300b377d _DPSNextEvent + 1135
26  com.apple.AppKit                  0x00007fff300b246b -[NSApplication(NSEvent) _nextEventMatchingEventMask:untilDate:inMode:dequeue:] + 1361
27  com.apple.AppKit                  0x00007fff300ac588 -[NSApplication run] + 699
28  org.cef.framework                 0x000000010fab43bc base::mac::CxxPersonalityRoutine(int, _Unwind_Action, unsigned long long, _Unwind_Exception*, _Unwind_Context*) + 4764
29  org.cef.framework                 0x000000010fab31d3 base::mac::CxxPersonalityRoutine(int, _Unwind_Action, unsigned long long, _Unwind_Exception*, _Unwind_Context*) + 179
30  org.cef.framework                 0x000000010fa723bd uhash_compareUnicodeString_69 + 754989
31  org.cef.framework                 0x000000010fa3e3fd uhash_compareUnicodeString_69 + 542061
32  org.cef.framework                 0x000000010f722d3b __gxx_personality_v0 + 401403
33  com.cycling74.Max                 0x0000000105dceb82 MaxCefEventLoopHandler::runMessageLoop() + 18