Eric V. Smith <e...@trueblade.com> added the comment:

Here's where I am on what methods are added under which circumstances. 
Hopefully these tables don't get mangled.

The more I think about what to do with hash and raising exceptions, the more I 
think that the right answer is to not raise any exceptions, and just follow the 
rule of "don't overwrite an attribute that the user specified". The uses of 
hash=True or hash=None are so specialized that users can be expected to 
understand the implications. The interaction among hash=, eq=, and frozen= are 
sufficiently complicated (see the last table below) that we don't need to add 
any more rules.

There are only 2 places below where exceptions are raised:

1. frozen=True and the user supplied __setattr__ or __delattr__. These methods 
are crucial for frozen-ness, so we must be able to add them.

2. order=True and the user supplied at least one of __lt__, __le__, __ge__, or 
__gt__. This is at Nick's request (see msg310464 in this issue). I'm not so 
sure about this one: if the user wants to explicitly ask that these methods be 
added (by specifying order=True, which is not the default), and they also 
specify some of the ordering function, then why not let them, and have 
dataclass add the missing ones as we normally would? But I'm not heavily 
invested in the outcome, as I don't see any reason to write such code, anyway. 
The only reason I'd suggest leaving it out is to avoid having to explain it in 
the documentation.

I have this all coded up and ready to create a PR, modulo a few more tests. 
I'll get it committed before Beta 1. Hopefully these tables answers the 
questions about the new proposal.

# Conditions for adding methods:
# added = method is added
#       = no action: method is not added
# raise = TypeError is raised
# None  = attribute is set to None

# __init__
#
#   +--- init= parameter
#   |
#   v    |   yes   |   no    |  <--- class has __init__?
# -------+---------+---------+
#  False |         |         |
# -------+---------+---------+
#  True  |         | added   |  <- the default
# -------+---------+---------+

# __repr__
#
#   +--- repr= parameter
#   |
#   v    |   yes   |   no    |  <--- class has __repr__?
# -------+---------+---------+
#  False |         |         |
# -------+---------+---------+
#  True  |         | added   |  <- the default
# -------+---------+---------+

# __setattr__
# __delattr__
#
#   +--- frozen= parameter
#   |
#   v    |   yes   |   no    |  <--- class has __setattr__ or __delattr__?
# -------+---------+---------+
#  False |         |         |  <- the default
# -------+---------+---------+
#  True  | raise * | added   |
# -------+---------+---------+
#
# * Raise because not adding these methods
#    would break the "frozen-ness" of the class.

# __eq__
#
#   +--- eq= parameter
#   |
#   v    |   yes   |   no    |  <--- class has __eq__?
# -------+---------+---------+
#  False |         |         |
# -------+---------+---------+
#  True  |         | added   |  <- the default
# -------+---------+---------+

# __lt__
# __le__
# __gt__
# __ge__
#
#   +--- order= parameter
#   |
#   v    |   yes   |   no    |  <--- class has any comparison method?
# -------+---------+---------+
#  False |         |         |  <- the default
# -------+---------+---------+
#  True  | raise * | added   |
# -------+---------+---------+
#
# * Raise because to allow this case would interfere with using
#    functools.total_ordering.

# __hash__

#   +------------------- hash= parameter
#   |       +----------- eq= parameter
#   |       |       +--- frozen= parameter
#   |       |       |
#   v    |  v    |  v    |  yes  |  no   |  <--- class has __hash__?
# -------+-------+-------+-------+-------+
#  False | False | False |       |       |
# -------+-------+-------+-------+-------+
#  False | False | True  |       |       |
# -------+-------+-------+-------+-------+
#  False | True  | False |       |       |
# -------+-------+-------+-------+-------+
#  False | True  | True  |       |       |
# -------+-------+-------+-------+-------+
#  True  | False | False |       | added | Has no __eq__, but hashable
# -------+-------+-------+-------+-------+
#  True  | False | True  |       | added | Has no __eq__, but hashable
# -------+-------+-------+-------+-------+
#  True  | True  | False |       | added | Not frozen, but hashable
# -------+-------+-------+-------+-------+
#  True  | True  | True  |       | added | Frozen, so hashable
# -------+-------+-------+-------+-------+
#  None  | False | False |       |       | No __eq__, use the base class 
__hash__
# -------+-------+-------+-------+-------+
#  None  | False | True  |       |       | No __eq__, use the base class 
__hash__
# -------+-------+-------+-------+-------+
#  None  | True  | False |       | None  | <-- the default, not hashable
# -------+-------+-------+-------+-------+
#  None  | True  | True  |       | added | Frozen, so hashable
# -------+-------+-------+-------+-------+
#
# For boxes that are blank, __hash__ is untouched and therefore
#  inherited from the base class.  If the base is object, then
#  id-based hashing is used.
# Note that a class may have already __hash__=None if it specified an
#  __eq__ method in the class body (not one that was created by
#  dataclass).

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<https://bugs.python.org/issue32513>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to