@passerby: Don’t see why, a Boolean is value type and is supposed to be either true or false

@zhalktis: I sometimes resort to a similar pattern in maxscript; using ‘undefined’ in cases where a boolean value couldn’t be determined. Complicates code somewhat since then you end up testing for it all over the place, or everything explodes. (Not sure if Python silently accepting None as Falsey by accident would be any better)

For such cases, raising exceptions would probably make more sense in a reasonable language, but mxs exception handling leaves a lot to be desired. Could be an option in Python, though.

Unless you mean treating None as a ‘valid’ value. That sounds “too surprising”.

@jeff_hanna: Don’t fall in to the anti-pattern of the Tri-State Boolean!
Especially in Python where None can be used in non-equality checks.

@passerby: in most languages if you wanted that you should use a enum
offers type safety that way too
in python i would likely just compare against ints i gave names
if its for exceptions reasons, like return null if it fails, i would personally just raise a exception

If you’re going to do something like this, you’d probably want to use a third default value that won’t reasonably passed in by the user

@covinator: I agree with passerby on this - enums! Err on the side of explicitness. Avoid inference with design.

@bob.w: Though yes, uses enums. if you’re on py3.4+ they are in the standard library. otherwise pip install enum34enum.IntEnum is great, you can treat it like an int but it actually has a nice readable repr so debugging isn’t half as dumb.

@alanweider: Looks like our code base is going to include both pyqt4 and pyqt5. We use a base class to define all our tools both inside and out of DCC apps. Would setting a class variable to nudge the use of one library or another depending on context make the most sense to ensure the correct libraries are loaded in this base class?

@bob.w: Yeah, None is very much the goto sentinel value. Where it gets squishy is when its a valid value and not just a standin for do the default.

@theodox:if XXX is True is usually regarded as an antipattern in Python, so that people can write custom truth functions for different kinds of objects

@bob.w: Also, be careful, as in Py2, True = False is completely valid.
So at that point thing is True could be horribly wrong

@alanweider: oh gosh that’s right

@bob.w: A real monster would do True, False = False, True

@ldunham1: Thanks for the replies, you’ve all covered cases for and against, although the general consensus errs towards enums. This is something I’m considering, although my hesitation is the addition of specific enum classes in various places and decreasing comfortability of use for mid-level developers.
Casing point would be using knowledge of existing instances where this happens (i think of some Mel commands - the existence of a flag may result in behaviour derived from its Boolean value).
Whilst not necessarily the best way to handle it I’ve fallen into traps of too many enums.
You guys are monsters for even considering such a thing…

@ldunham1: Making it a pain in the ass for other Devs to comfortably use them when needed if pretty much everything else relies on standard types.
I’m also talking about use in a core set of common DCC utilities
So they’re used alot

@passerby: I feel checking if a bool is none is more confusing then extra enum types

@bob.w: So the enum library actually lets you use other types as a mixin. You can have a StrEnum, or an IntEnum. I make a bunch of enums based on our C-bindings and they get passed through just fine as an IntEnum

@ldunham1: Cheers, although I think I typically omit the object inheritance to lighten the class
For Enum types I’ll use for non-boolean types.

@theodox: You can also just put the constants into a module, and import the module:

# constants mod
RED = 'red'
BLUE = 'blue'

then

import constants
if something == constants.RED:
...

@ldunham1: So then, my issue is related to using a common type of Enum to replace the behaviour whilst being clear about what it should do. Specifically refering to the use of the True/False/None
Although actually, thinking about providing an anti-example may have given me an answer
Enum.Yes/No/Ignore
Or a variation of such.

@theodox: it’s a convention, a lot depends on what kind of use patterns you expect

@passerby: I know anyone familiar with a statically typed Lang will never expect a bool to be None since it’s a value type and not a ref or pointer

@bob.w:

class Test(enum.Enum):
TRUE = True
FALSE = False
INVALD = None
...

@ldunham1: Yeah, thats the principle argument against atm. Its not standard/expected or generally, very clear@bob.w - yeah, thats what im thinking
Example:

@bob.w: Then the function expects a Test type, or you know a better name

@theodox: I would make the named constants into strings, however; otherwise debugging the code will be as unclear as the original example was

@bob.w: So the enum library I linked earlier, actually gives a nice repr, with both the name of the flag, and the value

@bob.w: Completely compatible, just wasn’t introduced until after the feature freeze went in
So the backport is pip installable at least.
And because it can represent an int or a str or whatever, it can be pretty easy to replace magic constants, or to act as a more readable wrapper for some C-exposed enum.
I use it a LOT for that last one. As we’ve got a lot of C-code that expects some enum, and we have to throw ints over the wall.

@bob.w: and debugging is pretty crappy when you go hey whats thing.flag and get back 0.

@ldunham1: This is all great. Really appreciate the help/advice. Although it probably seemed like a nonsense question, its from relatively good intentions. Just trying to make sure various levels of devs (maya backgrounds) feel comfortable with implementations and systems, without feeling like things are more hassle than they need to be.

@theodox: It’s also worth stepping back and considering if the api design is making too many assumptions – it’s much easier to test and maintain code if the number of expectations in each individual function is lowerIn the face of ambiguity, refuse the temptation to guess, as the man says

@bob.w: Also: special cases aren't special enough to break the rules

@ldunham1: Very fair points something I believe I should spend a little more time considering

@bob.w: I’m so bad at considering both those. At least when I’m in ‘lets put out the fire mode’

@ldunham1: Yeah, that was an option I considered also, but there are a few more args to consider and I was wary or bloating the number of arts.
That being said, I think you guys were right anyway
Got so caught up in this idea of generality and ease of use that I missed some pretty important things
Explicit is better than implicit especially

@bob.w: Also, sometimes it makes sense to just have 2-3 functions. get_all_attributes(node), get_default_attributes(node), get_custom_attributes(node)
No flags, no magic values.

@theodox: I was in the middle of typing out an example based on ls()
bob wins

@ldunham1: But I guess I presumed a very refined subset was an ideal middle ground of Devs used that level of accessibility.
Not arguing my original point anymore, just clarifying my initial thinking that made me question in the first place
But yeah, I think I will probably want to refine a couple of the functions to match up with the rest now.
Pulling away from my comfortable zone of Maya API and just being more explicit

@bob.w: So one thing that could work as well, is you have a _ private function with a bunch of silly flags, mostly because you don’t want to duplicate code all over the place. But the public API, that is a group of more refined functions that you don’t have to think about when using.

@ldunham1: Especially when using the same API in max, mobu and fbx
I will take a look!

@theodox: oh – if you’re outside of maya it’s maya only
but the general idea would be pretty easy to copy to different platforms
the hard part for that kind of problem set it is mapping between similar-but-different concepts in different environments; the thing that makes FBX so icky

@ldunham1: The API was written for Maya Devs to easily use max, mobu and fbx. The ls behaviour was a bit of a pain, but we’ll worth the payoff when then same API works in each application
Yes, been there.
But now a very large chunk of the common operations are done and working as expected, it’s now about refining into something more.

@bob.w: Sounds wonderful, and hideously complicated.

@ldunham1: Haha, definitely complicated at points, but big emphasis on usability and convenience for Devs. I’ve also made sacrifices with optimisation in favour or transparency or simplicity for some of the more problematic methods.
Some core functionality coverage for querying data, but then the rest of it falls under - I typically want to do this operation/pattern regardless of app (copying/validating skinning, baking animation, constraining, exporting etc)
So provide a layer of common behaviour through common API
Will definitely admit it’s not perfect, or perhaps even the best approach. As expected, sometime it just won’t work as you want / need. So they get special consideration and perhaps exposed common at a higher level

@theodox: I’d imagine you’ll run into nasty stuff like different naming and hierarchy behavior for objects and so on
scary

@ldunham1: For that, we pick a single naming convention that can work for all and stick with it. Each DCC implementation can choose to handle exceptions however it needs to in order to complete the task given to it
Sometimes it really doesn’t work, but they seem to be specific cases in which we can just provide a DCC specific functions to deal with it, and add the layer of abstraction.
So far things seem solvable and it’s been pretty nice to use. We do have a design to approach situations where we cannot get around it, but as I mentioned, for most of the common operations we perform - real general, workflow stuff, it’s working as expected
Phew, damn I sound defensive!
I posted a few times asking if anyone has done something like this on a similar scale, I don’t remember hearing too much back. I may end up seeing it biting me on the ass at some point!

@ldunham1: Haha after Mike’s talk regarding plugin based development (forward facing rigs), it felt like a natural thing to do.
I started it a few years ago, most of it has been personal time, up until it started to be used in production

@bob.w: The most terrifying point in any libraries life. When someone else starts to use it.

@ldunham1: Haha, that’s been some.of the more exciting times! I LOVE code reviews and feedback
Some of the biggest improvements in this project and my own personal development have come from them. Sometimes I’m too damn eager

@theodox: This sounds like a project that screams “unit test me”… in multiple environments…