Python is DOOMED! Again!

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jan 31 06:56:43 EST 2015


random832 at fastmail.us wrote:

> On Thu, Jan 29, 2015, at 10:56, Steven D'Aprano wrote:
>> Bar language, on the other hand, tries extremely hard to ensure that
>> every
>> type is automatically able to be coerced into every other type. The
>> coercion might not do what you expect, but it will do *something*:
> 
> See, this is where the concept falls apart. Many people will define a
> dynamically-typed language as weakly-typed *only if* the result of the
> automatic type coercion is unexpected/distasteful/fattening, 

Oh, the curse of the discontinuous mind! :-)

https://richarddawkins.net/2013/01/the-tyranny-of-the-discontinuous-mind-christmas-2011/

A concept doesn't fall apart just because a few people are unable to use it
correctly. We may not be able to distinguish the exact moment when a child
becomes an adult (except, of course, by picking some arbitrary culturally
sanctioned age) but the concepts of child and adult are meaningful. And so
it is with strong and weak typing: people of good faith may nevertheless
disagree where the dividing line should be draw, or even whether a dividing
line is meaningful, but the concept of typing strength remains meaningful.


> even if it 
> is well-defined and predictable according to the rules of the language.
> Which makes it a matter of personal taste.


Some degree of weakness in a type system is not necessarily bad. Even the
strongest of languages usually allow a few exceptions, such as numeric
coercions. I've never come across a language that has pointers which
insists on having a separate Nil pointer for ever pointer type: the
compiler will allow Nil to be used for any pointer type. Anything else
would be impractical.

Unfortunately, weakly typed languages get a bad reputation because so few of
them have well-defined rules that can be derived without having to learn a
bunch of arbitrary rules. Consider Javascript. What happens when you add
two arrays?

js> [1, 2, 3] + [4]
1,2,34

If it makes no sense to you, consider this:

js> typeof([1, 2, 3] + [4])
string

If it still makes no sense to you, you're not alone.

How about an array and an object?

js> [] + {}  //empty array plus empty object
[object Object]
js> {} + [] //empty object plus empty array
0

What if you add two empty objects?

js> {} + {}
NaN

More here:

https://www.destroyallsoftware.com/talks/wat


>> Bar will never give you a TypeError. I think we can agree that Bar is a
>> *very weakly typed* language.
> 
> Statically typed lanugages by definition can never give you a TypeError

They can't give you a *runtime* TypeError, but the compiler can give you a
compile-time type error. (Sorry for the misleading use of "TypeError" as in
the Python exception, I was thinking more broadly than just runtime
exceptions.)


> - there are no runtime conversions that can succeed or fail based on the
> type of the arguments. What makes a statically typed language strong or
> weak? Are statically typed languages always weak?

Statically typed languages tend to be strong. The point of doing static type
analysis is to prohibit ill-defined operations at compile-time, rather than
have the compiler mindlessly (say) write a 16-byte struct where a 2-byte
int is expected. But I don't think that it is necessarily the case that
statically-typed languages *must* be strongly typed, or dynamically-typed
languages weak.


>> There are degrees of strength, and I think that Python comes closer to
>> the
>> Foo end than the Bar end. There are few automatic coercions, and most of
>> those are in the numeric tower according to the usual mathematical rules.
> 
> Why is converting an int to a float when passed to a math function
> better than converting any object to a string when passed to a string
> function?

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.

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>'

but doing so *implicitly* gains us nothing except the saving of a few
keystrokes, while risking serious bugs. Forcing all arbitrary objects to
support string operations would be pointless and confusing. What could this
possibly mean?

server.replace('7', 'FOO')


We shouldn't insist that server objects support string methods, since that
would preempt them using methods of the same name for their own purposes,
and would needlessly clutter their API. We shouldn't want server objects to
automatically coerce into a string (why a string? why not a list or a dict
or a float?) because there is no real benefit to doing so. It can only
cause confusion.


-- 
Steven




More information about the Python-list mailing list