Hacker News new | past | comments | ask | show | jobs | submit login
Is Python strongly typed? (stackoverflow.com)
38 points by avinassh on Sept 26, 2015 | hide | past | web | favorite | 37 comments

Strong typing (absence of implicit conversions) is a spectrum, with some aspects being more important than others.

1) Do you allow 1 + 1.5? Most languages say yes, even very disciplined ones like Haskell. Very few languages say no, like Ocaml.

2) Do you allow "hello" + 1? Some languages say yes, like Java. Some languages say no, like Python. It doesn't seem very important either way.

3) Do you allow implicit conversion between pointers and integers? Most languages say no. Very few languages say yes, like C or assembly.

When people ask "is Python strongly typed?", they usually mean either "is Python statically typed?" (no, because a TV with a single color is not a color TV) or "is Python memory-safe?" (yes, unless you make a special effort to break it). Beyond these two questions, there's very little to learn from the fact that Python happens to disallow "hello" + 1.

> 1) Do you allow 1 + 1.5? Most languages say yes, even very disciplined ones like Haskell.

That's not really because of an implicit conversion. Integral literals are typed as `Num a` and floating literals as `Fractional a`, since `+ :: Num a => a -> a -> a` both operands must be of the same type, so `1` becomes a `Fractional a :: a` and voilà, the expression is correctly typed as `Fractional a :: a`.

Force `1` to a concrete integral type and you'll get a type error because there is no `Fractional Int` instance which would satisfy `(+)`:

    Prelude> (1 :: Int) + 1.5

        No instance for (Fractional Int)
          arising from the literal `1.5'
        Possible fix: add an instance declaration for (Fractional Int)
        In the second argument of `(+)', namely `1.5'
        In the expression: (1 :: Int) + 1.5
        In an equation for `it': it = (1 :: Int) + 1.5

Yeah, I know that the literal 1 has type Num a => a. Actually I suspect that's a bit of a flaw in Haskell. All the interesting things we can do with 1 as a literal (like adding it to 1.5) are also things we could do with the length of a one-element list, but in Haskell these two 1's are not interchangeable. Also, defaulting rules seem to be a wart that's necessary only because of overloaded literals. Maybe the literal 1 could have type Integer, and 1 + 1.5 could work through some other kind of typeclass magic?

The intended question is: is python statically typed? Strictly speaking, it depends on what you call a type. If you think of all possible values (integers, strings etc.) as being of a single type, then python is statically typed. However, most people wouldn't think of the values that way.


https://en.wikipedia.org/wiki/Lambda_calculus#Typed_lambda_c... ``From a certain point of view, typed lambda calculi can be seen as refinements of the untyped lambda calculus but from another point of view, they can also be considered the more fundamental theory and untyped lambda calculus a special case with only one type.''

Where should I start reading to understand lambda calculus?

> The intended question is: is python statically typed?

Erlang isn't statically typed, yet you can't do what the OP shows.

Aren't you begging the question?

No. I'm pointing out an inconsistency in GP's interpretation.

Unless I'm missing something, it's only an inconsistency if you assume Erlang is not statically typed, which is why I said you seem to be begging the question. Erlang (and indeed any dynamic language) could be viewed as statically typed in the not-particularly-useful way amelius was describing.

Nothing controversial (or particularly noteworthy) here.

It might be for some as it's a common misconception that Python does not have strong typing.

The "misconception" probably comes from "strong typing" being less an objective concept and more an attempt to weaselly state language preferences.

I don't think that's true. What I don't want is my program to blow up at runtime because given some input a function doesn't give me the expected type of output (e.g. maybe I've missed a condition and my function drops out the bottom). OCaml will tell me about this at compile time.

I don't think it is so much about it being 'subjective' or 'weaselly'. It is more about type systems sitting on various continuum dimensions rather than having binary descriptions.

There are marked differences between where different dynamically typed languages can sit on the strong vs weak dimension. Python and Ruby are closer to the strong end while PHP and Javascript are closer to the weak end. It is a useful real world distinction.

eg PHP and Javascript will happily coerce different types (eg strings and ints) together while Python and Ruby will raise type errors.

Well strong vs weak typing is both orthoganal to and predates most of the discussion of static vs dynamic typing. You have to deal with conversions no matter what.

> Well strong vs weak typing is orthoganal to the discussion of static vs dynamic typing.

"strong vs weak" can't be orthogonal to anything because it's meaningless and nonsensical. That's like saying NaN is lower than 5.

> Well strong vs weak typing is predates most of the discussion of static vs dynamic typing.

[citation required]

I'm not sure what there is to be confused about.

"weak" types mean they may elide into other types implicitly. "strong" types mean that the value will always be interpreted as one (set of) type(s). (really just one type, but that type may be a subtype, so it gets confusing.)

Even on HN? That was news to me.

Maybe the names are poor.

Strong/Weak typing refers to Conversion Typing. Or Type Malleability. It is about the implicit conversions or transitions between types.

Static/Dynamic refers to Variable Typing (or Identifier Typing). It refers to the type of an expression.

The problem is that many use Strong/Static and Weak/Dynamic as synonyms. Dynamically typed languages happen to often be weakly typed and statically typed languages happen to often be strongly typed. This is why you get people debating whether Python is "strong or dynamic" although that's a false dichotomy.

I recommend this article going into good depth on how Python's name and binding model functions:


In both (classic) Python and JavaScript, there is no static typing and you can change the type of existing objects, access all their fields, and add/remove methods and field any time.

The only languages with "weaker" typing are languages with no concept of types at all.

Strong/weak typing generally refers to types being implicitly converted. It's a almost completely orthogonal concept from static/dynamic typing. For instance C has several implicit integer width conversions. Javascript, PHP and Ruby are often used as examples for weak typing.

I'd argue that C++ is weaker than Java, although both have the concept of types. If you cast from one class to another, C++ will do it without hesitation. Java will do a runtime check and throw a ClassCastException if it fails.

C++ has both checked casts and unsafe casts.

Python 2 was broken when Unicode strings were allowed weak conversion from/to regular strings.

So Java is "broken" because it performs "weak conversion" (whatever the hell that means) between integers and floats, or anything and strings? And Scala would be even more "broken" because developers can define "weak conversion"?

In the reply below "str" and "unicode" refer to the python types of those names, not to generic "string" and "unicode".

No, in this case it was broken because things suddenly started working in weird ways, because type conversions between str and unicode were taking place when you weren't expecting it. So it's "broken practically" and not "broken philosophically". You could call X.encode('utf-8') expecting to get the utf-8 byte representation of a string, only to be told "character \xf8 at position whatever cannot be handled by ASCII decoder", because X is a str containing weird bytes and not an unicode, so when you ask to have it encoded, it is first silently decoded to unicode using the default encoding - ASCII in this case. You could do X + Y and get the same error because one of them happens to be an unicode, but the other is a str which python tries to convert to unicode.

Your comment has very limited relation to the GP in that the issue you outline is not the implicit conversion itself but the fact that said implicit conversion may fault and it is nigh impossible to know where that could happen until it does.

For the record I would agree, but I'm guessing it made sense in the context surrounding the introduction of "proper" unicode objects in Python 2 considering all the issues which cropped up after the Python 3 split and the issue of correctly dispatching APIs between str and unicode.

Furthermore some of the APIs are decidedly idiotic: `unicode` can take a string and an encoding, one could expect that if an encoding is provided it'll try to decode str inputs but let unicode go through unmolested, and thus could be a convenient way to ensure a possibly-str input is converted to unicode. After all, forced conversion is already available using e.g. `str(obj).decode(encoding)`.


    >>> unicode(u"straße", 'utf-8')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: decoding Unicode is not supported

I do think that implicit conversions are generally more pain than they are worth. Generally, my understanding of them stops with numeric conversions, and even there you can get bitten by e.g. precision loss if you accidentally use the wrong literal.

I'd say yes. The whole weak conformance stuff is terrible, not well-designed, and (in Scala) only exists for "Java compatibility" (the worst reason one can think of).

Things which silently throw away precision, change values and semantics in dangerous ways should never happen automatically.

One way to think about strong typing is that type matters when performing operations on a variable. If the type is not as expected, a language that complains is strongly typed (python/java) and one that isn't is weakly typed (javascript)

Dynamically typed languages(python) are those which allow the type of a variable to change at runtime whereas statically typed languages(java) do not allow this once a variable is declared

no implicit type conversion is just one of several strongly typed properties. type checking & safety weigh more to label a language as a strongly typed one.

In a strongly typed language, you wouldn't be able to interpret 'bob' as a number without an explicit coercion. That's as I understand it, but I also understand that terms like "strongly typed" are not well-defined.

Python is strongly typed with one type

This article about CL but it's applicable to Python as well:


Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact