Python is DOOMED! Again!

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jan 31 22:16:09 EST 2015


Chris Angelico wrote:

> On Sat, Jan 31, 2015 at 10:56 PM, Steven D'Aprano
> <steve+comp.lang.python at pearwood.info> wrote:
>> Both ints and floats are models of the same abstract thing, namely
>> "number". Ideally, from a mathematically standpoint, there should be no
>> difference between 23 and 23.0. Automatic coercions allow us to get a
>> little closer to that ideal.
> 
> So far, I'm mostly with you. (Though if your float type is not a
> perfect superset of your integer type - as in Python - then the
> default "up-cast" from int to float, while disallowing a corresponding
> implicit "down-cast", seems flawed. But in concept, yes, automatic
> coercion allows us to treat 23 and 23.0 as the same.)

In principle, we might have a real-number type that is a perfect superset of
ints, and we might even have int versions of NAN and INF. But down-casting
real-to-integer is ambiguous, due to the need to handle any fractional
parts:

- raise an exception if the fractional part is non-zero
- truncate (round towards zero)
- round down towards -infinity
- round up toward +infinity
- round to nearest, ties to odd numbers
- round to nearest, ties to even numbers
- round to nearest, ties split randomly
- something else

One might semi-arbitrarily pick one (say, truncation) as the default when
you cast using int(x) but you need to support at least the most common
rounding modes, perhaps as separate functions.


>> Arbitrary objects, on the other hand, are rarely related to strings.
>> Given that we need to be able to display arbitrary objects to the human
>> programmer, if only for debugging, we need to be able to *explicitly*
>> convert into a string:
>>
>>
>> py> import nntplib
>> py> SERVER = "news.gmane.org"
>> py> server = nntplib.NNTP(SERVER)
>> py> str(server)
>> '<nntplib.NNTP instance at 0xb7bc76ec>'
> 
> Here, though, I'm not so sure. Why should you be able to *type-cast*
> anything to string? Python has another, and perfectly serviceable,
> function for converting arbitrary objects into strings, and that's
> repr().

Which *also* converts to a string. (Note I didn't say *cast* to a string. I
cannot imagine any meaningful definition of what casting a NNTP server
object to a str might be.)


> It would make perfect sense for a language to make this 
> distinction much more stark:
> 
> 1) str() attempts to convert something into a string. It can do this
> automatically in the case of "string-like" objects (eg buffers, maybe
> some magical things that come from databases), and can convert others
> with help (eg bytes->string using an encoding parameter), but anything
> else will raise an error.
> 
> 2) repr() guarantees to convert anything into a string. It does this
> in a relatively arbitrary fashion; you can write a helper method for
> your class to make this more useful to the human.
> 
> #2 is how Python's repr already functions, so explicitly converting
> arbitrary objects into strings is covered. The idea that we can str()
> them as well isn't necessarily part of a sane typing system.
> 
> (Note that I'm not saying that Python got it wrong, here; just that
> taking the alternate choice would also be not-wrong.)

I agree with all of that. And for what it is worth, a class can refuse to
convert to str while still supporting repr:

py> class K(object):
...     def __str__(self): raise TypeError
...     def __repr__(self): return "Stuff and things. Mostly stuff."
...
py> k = K()
py> str(k)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 2, in __str__
TypeError
py> repr(k)
'Stuff and things. Mostly stuff.'


But by default, Python will fallback on __repr__ if __str__ doesn't exist,
or __str__ if __repr__ doesn't exist, or both. Or something. (I always
forget what the rules are exactly.)


>> but doing so *implicitly* gains us nothing except the saving of a few
>> keystrokes, while risking serious bugs.
> 
> Complete and automatic casting to string, I would agree. However, I
> would suggest that there are a few *binary operations* which could be
> more convenient if they allowed some non-strings. For instance, Pike
> allows addition of strings and integers: "1" + 2 == "12", where Python
> requires "1" + str(2) for the same operation. (But Pike does *not*
> allow just any object there. Only a few, like numbers, can be quietly
> cast on being added to strings.)

I'm surprised you're not into Perl, with an attitude like that. A sick,
disgusting, despicably perverted attitude. *wink*

But seriously, I can see some uses there, but frankly why bother to make an
exception for ints when you require all other types to have an explicit
coercion?

The problem with string/int automatic coercions is that there are lots of
answers but none of them are obviously the right answer:

"1" + 1 --> "11" or 2?

"1a" + 1 --> 2 like Perl does, or "1a1" like Javascript does?

Do you strip out all non-numeric characters, or truncate at the first
non-numeric character?

Should you perhaps be a little more flexible and allow common mistypings
like O for 0 and l for 1? How about whitespace?



-- 
Steven




More information about the Python-list mailing list