Why most people use boolean flags instead of catching the MPlug ?

102 views
Skip to first unread message

justin hidair

unread,
Mar 17, 2018, 12:24:10 AM3/17/18
to Python Programming for Autodesk Maya


There's this good'ol workflow most apply when they want to know exactly what plug is getting changed
 so that you can make more efficient decision/computation, this typically involve the use of MPxNode::setDependentsDirty(..) ,

the thing is why setup just boolean flags with it ? instead of assigning the passed MPlug of MPxNode::setDependentsDirty(const MPlug& plug,..) to a member variable of the node class ?
(you can verify and compare to your attribute with MPlug::attribute() == myattribute )

this offer more versatility and when dealing with compound/arrays attribute it is way less redundant than the jumpToElement mouse and cat game, so why ?
As a matter of fact I tested this approach and see no problem with it ..

Marcus Ottosson

unread,
Mar 17, 2018, 8:01:01 AM3/17/18
to python_in...@googlegroups.com
My question to you is, who is most people? Maybe if you share an example we could more easily spot why the decision to use a boolean was made for that particular case.

If I had to guess, then I'd think it's the same reason as to why it is ill advised to store a reference to an MObject; they aren't built to last. That is to say, storing an MObject, changing the Maya scenegraph, and later accessing the MObject could yield unexpected results, and in some cases even lead to crash, because the memory it points to is no longer what you think it is.

However if you know that there is no chance of the scenegraph to change for the duration of you storing this member variable, then I would think you should be fine. That is why I'm asking for examples, because odds are the examples you've have been unable to guarantee such conditions.

justin hidair

unread,
Mar 17, 2018, 10:03:16 AM3/17/18
to python_in...@googlegroups.com

 

/*in the boolean flag case :

lets say aDistance and aAmount are both child of a compound in an array of compound*/

MStatus myclass::setDependentsDirty(const MPlug &plug, MPlugArray &affect)

{

                mayastream << "dirtying. .." << "\n";

 

        if(plug.isChild() && plug.attribute() == aDistance )

        {

                e_distance_change= true ;

                /*get index to target this attribute specifically will be

                useful with MArrayDataHandle*/

                m_element_idx = plug.parent().logicalIndex();

        }

        else

        if(plug.isChild() && plug.attribute() == aAmount )

        {

               

                e_amount_change= true ;

                /*get index to target this attribute specifically will be

               useful with MArrayDataHandle*/

                m_element_idx = plug.parent().logicalIndex();

        }

 

    return MPxNode::setDependentsDirty(plug , affect );

   

}

MStatus myclass::compute(...)

{

    //typical moves:

    cmp_array = datablock.inputArrayValue(aArray);

    if( e_distance_change == true )

    {

    /*    perform targeted calculations

            use cmp_array.jumpToElement(m_element_idx)*/

    }

    else

    if(e_amount_change == true )

    {

        /*perform targeted calculations

            use cmp_array.jumpToElement(m_element_idx)*/

 

    }

//...

}

 

/*in the use Plug case :

lets say aDistance and aAmount are both child of a compound in an array of compound*/

MStatus myclass::setDependentsDirty(const MPlug &plug, MPlugArray &affect)

{

                mayastream << "dirtying. .." << "\n";

 

        m_dirty_plug = plug;    

                /*just one line and we can use the plug however we want

                the benefit is we also have all the methods of MPlug

                like .isConnected and so on , aslong as the method stay ) const

                we can use it in compute without a problem...

                we can use this to get index in array :

                m_dirty_plug.parent().logicalIndex();

                now to compute() ... */

 

    return MPxNode::setDependentsDirty(plug , affect );

   

}

MStatus myclass::compute(...)

{

    //things I never saw:

    cmp_array = datablock.inputArrayValue(aArray);

    if(m_dirty_plug.isChild() && m_dirty_plug.attribute() == aDistance ) 

    {

        /*perform targeted calculations

        use all the cool const methods of MPlug

        use cmp_array.jumpToElement(m_dirty_plug.parent().logicalIndex())*/

    }

    else

    if(m_dirty_plug.isChild() && m_dirty_plug.attribute() == aAmount)

    {

        /*perform targeted calculations

        use all the cool const methods of MPlug

        use cmp_array.jumpToElement(m_dirty_plug.parent().logicalIndex())*/

 

    }

    /*...

    optionnaly at the end you can if you want reset  m_dirty_plug with

    m_dirty_plug.setMObject(MObject::kNullObj) but it's not really required because it

    will be reassigned ... it allow to use .isNull() in particular cases tho

    lot of things you can do with just a plug instead of 4 boolean flags, it's also

    way easier to maintain*/

}

 

 

Sent from Mail for Windows 10

--
You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/python_inside_maya/CAFRtmOB9pPUBGsHk8_1Q53E4TTm42evbqtBrou6nLEXJmPH%3Dcg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

 

Marcus Ottosson

unread,
Mar 17, 2018, 12:14:43 PM3/17/18
to python_in...@googlegroups.com
Thanks, I think that's much clearer.

In this case, one immediate advantage of using a bool is performance. Querying a boolean is simply faster than calling a function.

If performance wasn't an issue, then I would likely still opt for a boolean as a means of communicating what it is being used for. You could argue that you should always pass the full APIs of objects around, to maximise your ability to take full advantage of them wherever they are being intercepted. In my experience this leads to brittle and stale code. Consider for example if you made a change to your code whereby you were no longer using `MPlug` to retrieve plug dirtiness. What if there was a faster method? In that case, you will either have to (1) instantiate a dedicated `MPlug` simply to pass it along (slow), (2) build your own `MPlug` replica that mirror the interface of the original `MPlug` such that any method using the member still works (slower), or (3) refactor anything that uses that member variable to use the new return value (painful, maybe). If instead all you passed was a boolean, then the odds are greater that you'd be able to use the new method, and still pass a boolean. Subsequent methods could remain untouched (and blissfully unaware of your improvement).

justin hidair

unread,
Mar 17, 2018, 12:39:54 PM3/17/18
to python_in...@googlegroups.com

Hmm , the little overhead of the MPlug way is really negligible / small if we talk about using it in C++, however for Python I don’t know so … I mean it brings so much advantages … I would’ve though that maybe there was a dark profound issue with doing it , I guess it’s all good as long as you use it in a low-level language and you don’t use it to set/get values of course …

 

Sent from Mail for Windows 10

 

From: Marcus Ottosson
Sent: Saturday, March 17, 2018 4:14 PM
To: python_in...@googlegroups.com
Subject: Re: [Maya-Python] Why most people use boolean flags insteadofcatching the MPlug ?

 

Thanks, I think that's much clearer.

In this case, one immediate advantage of using a bool is performance. Querying a boolean is simply faster than calling a function.

If performance wasn't an issue, then I would likely still opt for a boolean as a means of communicating what it is being used for. You could argue that you should always pass the full APIs of objects around, to maximise your ability to take full advantage of them wherever they are being intercepted. In my experience this leads to brittle and stale code. Consider for example if you made a change to your code whereby you were no longer using `MPlug` to retrieve plug dirtiness. What if there was a faster method? In that case, you will either have to (1) instantiate a dedicated `MPlug` simply to pass it along (slow), (2) build your own `MPlug` replica that mirror the interface of the original `MPlug` such that any method using the member still works (slower), or (3) refactor anything that uses that member variable to use the new return value (painful, maybe). If instead all you passed was a boolean, then the odds are greater that you'd be able to use the new method, and still pass a boolean. Subsequent methods could remain untouched (and blissfully unaware of your improvement).

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Mar 17, 2018, 1:14:56 PM3/17/18
to python_in...@googlegroups.com

I would’ve though that maybe there was a dark profound issue with doing it

In order of profoundness, from my limited understanding of MPlug (which may be wrong!) you should prefer boolean values over instances of objects due to:

  1. Memory access violation
  2. Performance
  3. Communication

I only found one reference to why holding onto MObject is not ok, which may or may not apply to MPlug.

If I was you, I would just give it a go (and report back here with how it went) :)

justin hidair

unread,
Mar 17, 2018, 1:54:18 PM3/17/18
to python_in...@googlegroups.com

I gotchu fam , here in the documentation it says :

 

A networked plug cannot be explicitly created. They are created when a connection is established for some attribute of the node. Since the allocation of networked plugs is managed exclusively by Maya, a plugin should never reference a networked plug after changes are made to the DG. Instead, use a non-networked version of the plug, or get a new reference to the networked plug.

 

BUT , here’s the catch :

MPlug & operator=

(

const MPlug

other

)

Assignment operator.

Copies one plug to another.

Networked plugs are not allowed to be duplicated so if the RHS is a networked plug then a non-networked version is returned.

And turns out that the plug of MPxNode::setDependentsDirty(const MPlug&, ...) is networked.

Therefor when I use operator= I get a non-networked plug , so there’s no risks 😊

So I’m tempted to conclude that most people use Boolean flags instead of using the plug ,

because “ it has always been done that way”

 

Sent from Mail for Windows 10

 

From: Marcus Ottosson
Sent: Saturday, March 17, 2018 5:14 PM
To: python_in...@googlegroups.com
Subject: Re: [Maya-Python] Why most people use boolean flags insteadofcatchingthe MPlug ?

 

I would’ve though that maybe there was a dark profound issue with doing it

In order of profoundness, from my limited understanding of MPlug (which may be wrong!) you should prefer boolean values over instances of objects due to:

1.       Memory access violation

2.       Performance

3.       Communication

I only found one reference to why holding onto MObject is not ok, which may or may not apply to MPlug.

·         https://forum.highend3d.com/t/using-mobjects-as-pointers-to-other-objects/39887/3

If I was you, I would just give it a go (and report back here with how it went) :)

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Marcus Ottosson

unread,
Mar 17, 2018, 2:17:28 PM3/17/18
to python_in...@googlegroups.com

because “ it has always been done that way”

Not to argue (though you make it very tempting to do so!), but even if this were true then even it has its merits, as it invokes the POLA and turns into convention. It means the reader of your code won’t have to think twice when coming across your boolean, which they would otherwise have to do if you chose to do it differently. ;)

justin hidair

unread,
Mar 17, 2018, 2:22:26 PM3/17/18
to python_in...@googlegroups.com

This is a fair point  😉 , fortunately in my case I’m the only one to see/modify the code

 

Sent from Mail for Windows 10

 

From: Marcus Ottosson
Sent: Saturday, March 17, 2018 6:17 PM
To: python_in...@googlegroups.com
Subject: Re: [Maya-Python] Why most people use boolean flagsinsteadofcatchingthe MPlug ?

 

because “ it has always been done that way”

Not to argue (though you make it very tempting to do so!), but even if this were true then even it has its merits, as it invokes the POLA and turns into convention. It means the reader of your code won’t have to think twice when coming across your boolean, which they would otherwise have to do if you chose to do it differently. ;)

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Rob Engle

unread,
Mar 17, 2018, 3:40:44 PM3/17/18
to Python Programming for Autodesk Maya
My question is slightly off topic to this thread but motivated by the posted code sample...

I was under the impression that setDependentsDirty can be called any number of times with different arguments before compute is called (if ever). This would mean that storage of m_element_index (or caching of any information from setDependentsDirty) would need to store more than just the one call.  This could be solved by making m_element_index an array of cached values and compute handling all of them.  Is this right?

Rob

justin hidair

unread,
Mar 17, 2018, 3:59:32 PM3/17/18
to python_in...@googlegroups.com

Correct . However it is expensive(for a dev) to do it that way when you know you can just use one unsigned int that get assigned in every call of setdepdirty()  , and it goes also with the fact that you only have to worry about one attribute change at a time , and it is not necessary to store every indices like that , the use of MArrayDataHandle::jumpToArrayElement() with MArrayDataHandle::elementIndex() is a recommended combo to iterate over the array of compounds/element even in the documentation , and you will need to call MDataBlock::inputArrayValue() once you are in compute anyway so … this m_element_index thing is just here so I know what element is tingling so that I don’t have to do expensive complete calculations, it’s lazy evaluation if you want

 

 

Sent from Mail for Windows 10

 

From: Rob Engle
Sent: Saturday, March 17, 2018 7:40 PM
To: Python Programming for Autodesk Maya
Subject: Re: [Maya-Python] Why most people use boolean flags insteadofcatching the MPlug ?

 

My question is slightly off topic to this thread but motivated by the posted code sample...

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Rob Engle

unread,
Mar 17, 2018, 5:55:01 PM3/17/18
to python_in...@googlegroups.com
Perhaps I am not being clear.  setDependentsDirty could be called a bunch of times, with different plugs (distance and amount) and different indices before compute is ever called.  That would mean the code in compute would only have cached the results of the last call.

I understand the dependency graph evaluation to be: Step 1: propagate dirty flags from changed attribute(s) to all dependent destinations.  One attribute change can cause numerous downstream attributes (possibly through different array indices) to dirty. Step 2: determine which, and compute now-dirty attributes needed to be evaluated (some attributes may have been dirtied but don't affect drawing or any open attribute editors, for example). This implies that, if you are caching info from calls to setDependentsDirty, you need to cache all the calls, not just the last one.

In other words, I think "you only need to worry about one attribute change at a time" is incorrect.  You only need to worry about one attribute computation at a time but, if you are storing information from setDependentsDirty, you can't just cache the last call.  What happens in your code if BOTH distance and amount changed? What if they are coming from different indices?

What am I missing here?

thanks,
Rob

justin hidair

unread,
Mar 17, 2018, 6:08:41 PM3/17/18
to python_in...@googlegroups.com

Lol I love these conversations , YES you are right this is something I didn’t mentioned but In my real compute() I have something to verify that it is the first compute ( it’s some truly used cached data not a collection of indices) , if it is , I simply do a complete computation it’s a bit like this :

 

if( myvector.size() == 0 )

{

                //complete compute() , everything counts

}

else

if( myplug ==…)

{

                //update cache , targeted compute

}

else( …)

 

this mechanism implies a lot of things so beware , for example if an output attribute is disconnected and you have cached data , you need to override MPxNode::connectionBroken(const MPlug&,…) to clear your cache , and set its size back to zero while you are at it …

 

like this :

        else

        if (plug.attribute(MRTERR()) == a_output)

        {

            reset_cache();

        }

 

 

Sent from Mail for Windows 10

 

From: Rob Engle
Sent: Saturday, March 17, 2018 9:55 PM
To: python_in...@googlegroups.com
Subject: Re: [Maya-Python] Why most people use boolean flags insteadofcatchingthe MPlug ?

 

Perhaps I am not being clear.  setDependentsDirty could be called a bunch of times, with different plugs (distance and amount) and different indices before compute is ever called.  That would mean the code in compute would only have cached the results of the last call.

--

You received this message because you are subscribed to the Google Groups "Python Programming for Autodesk Maya" group.
To unsubscribe from this group and stop receiving emails from it, send an email to python_inside_m...@googlegroups.com.

Reply all
Reply to author
Forward
0 new messages