This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author eric.smith
Recipients eric.smith, gvanrossum, larry, levkivskyi, ncoghlan
Date 2018-01-26.13:24:50
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1516973090.23.0.467229070634.issue32513@psf.upfronthosting.co.za>
In-reply-to
Content
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).
History
Date User Action Args
2018-01-26 13:24:50eric.smithsetrecipients: + eric.smith, gvanrossum, ncoghlan, larry, levkivskyi
2018-01-26 13:24:50eric.smithsetmessageid: <1516973090.23.0.467229070634.issue32513@psf.upfronthosting.co.za>
2018-01-26 13:24:50eric.smithlinkissue32513 messages
2018-01-26 13:24:50eric.smithcreate