Chris Angelico wrote: > On Sat, Jan 31, 2015 at 10:56 PM, Steven D'Aprano > <steve+comp.lang.pyt...@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 -- https://mail.python.org/mailman/listinfo/python-list