I propose a style guide when we create a sentinel.
Common standard python sentinels like 'True', 'False', 'None' follow this style
-
Naming Conventions: The requirement for sentinel names to be in title case and have descriptive names is clear and aligns with Python's naming conventions. This ensures that sentinel names are meaningful and self-explanatory. Example: Undefined, Missing.
-
Avoiding Conflicts: The guideline to avoid overriding standard Python sentinels like None, True, and False is crucial to prevent confusion and unexpected behavior. It's important to emphasize that sentinels should not interfere with the behavior of built-in constants.
-
Usage of Sentinels: The suggestion to use sentinels only when None cannot be used as a sentinel value is reasonable. It encourages developers to leverage the existing None sentinel when it fits the purpose as this is normal python standard.
-
Complexity of Sentinels: The recommendation to keep sentinels simple and not create complex classes or subclasses aligns with the principle of keeping code straightforward and understandable.
-
Consistency: Sentinels created must be consistent throughout the entire project. The created Sentinels must have the same meaning wherever it is used. The guideline to maintain consistency in the meaning of sentinels throughout a project is essential for code clarity and predictability.
-
Sentinel Comparison Order: Sentinels cannot be compared with each other. Use Enums instead.
-
Explicit Boolean Evaluation: Provide Boolean evaluation explicitly rather than setting it to be True by default as this avoids confusion.
Example:
Undefined = Sentinel('<undefined>')
# Let's say a function can return `Undefined `
value = foo()
if value:
print(f"Value received is {value}")
else:
raise ValueError("Value wan't available")
Here you can see that, it makes more sense that Undefined was False rather than it being True by default. If a sentinel must be True or False depends on the context of the sentinel.
Example: Undefined should be evaluated to False and Success can be evaluated to True, while EOF doesn't necessarily mean True or False and thus can have an "Invalid State" or it is "ambiguous".
So, I propose that we should pass in explicitly if a Sentinel is truthy or not, using the truthy argument. The truthy argument can be True, False or None (default). If truthy is None, then we should raise a ValueError. This makes sentinels more explicit and can force the users to give meaning to a sentinel and enforces them to use is operator to evaluate.
Example:
Undefined = Sentinel('<undefined>', truthy=False)
Success= Sentinel('<successful>', truthy=True)
EOF= Sentinel('<undefined>')
value = Undefined
if value:
print("value is defined.")
value = Success
if value:
print("Function ran successfully")
value = EOF
# This results in a ValueError
# bool(value)
This makes the behavior of sentinels more explicit and avoids any ambiguity.
Can we discuss this and possibly add it into PEP 661 Proposal?
I propose a style guide when we create a
sentinel.Common standard python sentinels like 'True', 'False', 'None' follow this style
Naming Conventions: The requirement for sentinel names to be in title case and have descriptive names is clear and aligns with Python's naming conventions. This ensures that sentinel names are meaningful and self-explanatory. Example:
Undefined,Missing.Avoiding Conflicts: The guideline to avoid overriding standard Python sentinels like None, True, and False is crucial to prevent confusion and unexpected behavior. It's important to emphasize that sentinels should not interfere with the behavior of built-in constants.
Usage of Sentinels: The suggestion to use sentinels only when None cannot be used as a sentinel value is reasonable. It encourages developers to leverage the existing
Nonesentinel when it fits the purpose as this is normal python standard.Complexity of Sentinels: The recommendation to keep sentinels simple and not create complex classes or subclasses aligns with the principle of keeping code straightforward and understandable.
Consistency: Sentinels created must be consistent throughout the entire project. The created Sentinels must have the same meaning wherever it is used. The guideline to maintain consistency in the meaning of sentinels throughout a project is essential for code clarity and predictability.
Sentinel Comparison Order: Sentinels cannot be compared with each other. Use
Enumsinstead.Explicit Boolean Evaluation: Provide Boolean evaluation explicitly rather than setting it to be
Trueby default as this avoids confusion.Example:
Here you can see that, it makes more sense that Undefined was
Falserather than it beingTrueby default. If a sentinel must beTrueorFalsedepends on the context of the sentinel.Example:
Undefinedshould be evaluated toFalseandSuccesscan be evaluated toTrue, whileEOFdoesn't necessarily meanTrueorFalseand thus can have an "Invalid State" or it is "ambiguous".So, I propose that we should pass in explicitly if a Sentinel is truthy or not, using the
truthyargument. Thetruthyargument can beTrue,FalseorNone(default). IftruthyisNone, then we should raise aValueError. This makes sentinels more explicit and can force the users to give meaning to a sentinel and enforces them to useisoperator to evaluate.Example:
This makes the behavior of sentinels more explicit and avoids any ambiguity.
Can we discuss this and possibly add it into PEP 661 Proposal?