[Python-Dev] Symmetry arguments for API expansion

Gregory P. Smith greg at krypto.org
Mon Mar 12 13:33:00 EDT 2018


On Mon, Mar 12, 2018 at 9:51 AM Raymond Hettinger <
raymond.hettinger at gmail.com> wrote:

> There is a feature request and patch to propagate the float.is_integer()
> API through rest of the numeric types ( https://bugs.python.org/issue26680
> ).
>
> While I don't think it is a good idea, the OP has been persistent and
> wants his patch to go forward.
>
> It may be worthwhile to discuss on this list to help resolve this
> particular request and to address the more general, recurring design
> questions. Once a feature with a marginally valid use case is added to an
> API, it is common for us to get downstream requests to propagate that API
> to other places where it makes less sense but does restore a sense of
> symmetry or consistency.  In cases where an abstract base class is
> involved, acceptance of the request is usually automatic (i.e. range() and
> tuple() objects growing index() and count() methods).  However, when our
> hand hasn't been forced, there is still an opportunity to decline.  That
> said, proponents of symmetry requests tend to feel strongly about it and
> tend to never fully accept such a request being declined (it leaves them
> with a sense that Python is disordered and unbalanced).
>
>
> Raymond
>
>
> ---- My thoughts on the feature request -----
>
> What is the proposal?
> * Add an is_integer() method to int(), Decimal(), Fraction(), and Real().
> Modify Rational() to provide a default implementation.
>
> Starting point: Do we need this?
> * We already have a simple, traditional, portable, and readable way to
> make the test:  int(x) == x
>

Mark Dickerson left a comment on the bug pointing out that such a test is
not great as it can lead to an excessive amount of computation to create
the int from some numeric types such as Decimal when all that is desired is
something the type itself may be able to answer without that.


> * In the context of ints, the test x.is_integer() always returns True.
> This isn't very useful.
> * Aside from the OP, this behavior has never been requested in Python's 27
> year history.
>
> Does it cost us anything?
> * Yes, adding a method to the numeric tower makes it a requirement for
> every class that ever has or ever will register or inherit from the tower
> ABCs.
> * Adding methods to a core object such as int() increases the cognitive
> load for everyday users who look at dir(), call help(), or read the main
> docs.
> * It conflicts with a design goal for the decimal module to not invent new
> functionality beyond the spec unless essential for integration with the
> rest of the language.  The reasons included portability with other
> implementations and not trying to guess what the committee would have
> decided in the face of tricky questions such as whether
> Decimal('1.000001').is_integer()
> should return True when the context precision is only three decimal places
> (i.e. whether context precision and rounding traps should be applied before
> the test and whether context flags should change after the test).
>
> Shouldn't everything in a concrete class also be in an ABC and all its
> subclasses?
> * In general, the answer is no.  The ABCs are intended to span only basic
> functionality.  For example, GvR intentionally omitted update() from the
> Set() ABC because the need was fulfilled by __ior__().
>
> But int() already has real, imag, numerator, and denominator, why is this
> different?
> * Those attributes are central to the functioning of the numeric tower.
> * In contrast, the is_integer() method is a peripheral and incidental
> concept.
>
> What does "API Parsimony" mean?
> * Avoidance of feature creep.
> * Preference for only one obvious way to do things.
> * Practicality (not craving things you don't really need) beats purity
> (symmetry and foolish consistency).
> * YAGNI suggests holding off in the absence of clear need.
> * Recognition that smaller APIs are generally better for users.
>
> Are there problems with symmetry/consistency arguments?
> * The need for guard rails on an overpass doesn't imply the same need on a
> underpass even though both are in the category of grade changing byways.
> * "In for a penny, in for a pound" isn't a principle of good design;
> rather, it is a slippery slope whereby the acceptance of a questionable
> feature in one place seems to compel later decisions to propagate the
> feature to other places where the cost / benefit trade-offs are less
> favorable.
>
> Should float.as_integer() have ever been added in the first place?
> * Likely, it should have been a math module function like isclose() and
> isinf() so that it would not have been type specific.
> * However, that ship has sailed; instead, the question is whether we now
> have to double down and have to dispatch other ships as well.
> * There is some question as to whether it is even a good idea to be
> testing the results of floating point calculations for exact values. It may
> be useful for testing inputs, but is likely a trap for people using it
> other contexts.
>

I don't think that ship has sailed.

We could still add a math.is_integer or math.is_integral_value function
(I'll let others bikeshed the name) and have it understand all stdlib
numeric types.  For non-stdlib types it could fall back to looking for an
.is_integer() method on the type as a protocol before just raising a
TypeError.

-gps


> Have we ever had problems with just accepting requests solely based on
> symmetry?
> * Yes.  The str.startswith() and str.endswith() methods were given
> optional start/end arguments to be consistent with str.index(), not because
> there were known use cases where code was made better with the new
> feature.   This ended up conflicting with a later feature request that did
> have valid use cases (supporting multiple test prefixes/suffixes).  As a
> result, we ended-up with an awkward and error-prone API that requires
> double parenthesis for the valid use case:  url.endswith(('.html', '.css')).
> _______________________________________________
> Python-Dev mailing list
> Python-Dev at python.org
> https://mail.python.org/mailman/listinfo/python-dev
> Unsubscribe:
> https://mail.python.org/mailman/options/python-dev/greg%40krypto.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180312/4fa6f217/attachment.html>


More information about the Python-Dev mailing list