7 ms·
Static types. Python is strongly typed, although possibly not as much as we might hope. This fails: "cat" + 1 with a type error, but it happens at runtim
by michaelochurch 12y ago
Static types.
Python is strongly typed, although possibly not as much as we might hope. This fails:
"cat" + 1
with a type error, but it happens at runtime. (Oddly enough, Scala permits it.) Python's type system isn't very expressive-- for example, you have "list" and "dict" types but not "list of int"-- and since you can branch without type congruence (because Python's "if" is a statement, not an expression) you can lose static knowledge pretty quickly, but Python does block type errors. It just does so at runtime, which means that the problem may be hard to reproduce and the error/failure distance can be high.
I agree with most of what's said in the OP. I just want to push back against the use of "strong" and "static" typing as if they were interchangeable. I'm in the same boat-- generally an advocate for compile-time static typing-- but to conflate static/dynamic with strong/weak is to misrepresent the issue, and unfair to the dynamically-typed languages. All of the modern dynlangs (e.g. Python, Ruby, Clojure) enforce type safety. They just do it at runtime, whereas Haskell, Scala and Ocaml do it at compile time.
- xwowsersx 12y agoYou're right. I wasn't precise and conflated those issues. Thank you.
- michaelochurch 12y agoYou are far from the first. Many, many years ago, I made a more embarrassing mistake. I insisted in a job interview that OCaml was dynamically typed because it didn't require explicit typing. (To my naive eye, it "looked" like a dynlang). When I realized that I was interviewing with an expert, I backed off and admitted that I was wrong, not entirely sure why but not about to argue with someone who knew the language in depth. (And, of course, I was wrong.) I still got the job. I'd actually argue that strong vs. weak is a continuum and somewhat subjective. One of my gripes with Scala is that the type system (as used in the field) isn't strong enough. It will implicitly auto-promote types in ways you might not want (i.e. List[Int] :+ String = List[Any]). It can be a strong type system, but the quality of programmers has a huge influence on your experience with Scala. If you have bad programmers who do things the Enterprise Java Way, you can quickly end up with compile-speed issues. But that's another rant. Scala's great for mid-sized projects or when the developers are strong.
- xwowsersx 12y agoHehe, fun story. Totally agree with you about Scala. I'm hoping to do all future development in Haskell.
- jimbokun 12y ago"It will implicitly auto-promote types in ways you might not want (i.e. List[Int] :+ String = List[Any])." Wow, that seems to totally miss the point of using types to help you catch errors.
- kod 12y agoNo, because if you then try to call an Int-specific method on an item from that List[Any], you will still get a compile time error.
- HolyHaddock 12y agoSilently inferring List[Any] is like a null reference. The error that you get told about is in a different place to where the problem that you need to fix is. In this case, the static type system could have been more helpful. There have been attempts to fix this - WartRemover specifically has a Wart for any uses of Any for example.
- kod 12y agoNo, a compile time error is nothing at all like a runtime null pointer exception. Given that the language supports subtype polymorphism, this is exactly how the type inference should work. Any is the narrowest available supertype. If you don't like it, there's a pretty simple fix: add an explicit type ascription, which you should be doing for the return values of any methods anyway.
- dllthomas 12y agoIt's like a null reference in that both increase the distance between the error and the report of failure, and both have a way of working correctly. The distinction between compile time failure and runtime failure is an important one, but not the only thing going on.
- mikeash 12y agoI agree, it would be good to tighten up the terminology. "Weak typing" should be reserved for stuff where the underlying bits can get reinterpreted at will, e.g.: printf("%d", 42.0); Strong typing means the type of each chunk of memory is known and can't be arbitrarily changed, and then static/dynamic refers to how much type information is present at compile time. Might be a losing battle, though. Strong/weak has been overloaded in this way for a long time.
- masklinn 12y ago> "Weak typing" should be reserved for stuff where the underlying bits can get reinterpreted at will, e.g.: > printf("%d", 42.0); which does not demonstrate your point and is valid Python: >>> "%d" % 42.0 '42' also the more odd >>> "%.2f" % True '1.00' and who could forget >>> "foo" * 3 'foofoofoo' edit: forget about this, for some reason I'd forgotten what the example would output…
- dllthomas 12y agoI think it was meant to be C, where it would often (although not always - very much implementation defined) wind up interpreting the bits of the float as if they represented an integer.
- mikeash 12y agoThat's a C example, where it demonstrates my point perfectly. Python doesn't even have a printf function, where did you get the idea it was supposed to be Python?
- dllthomas 12y agoIf someone is saying something bad about a language and it has something to do with types being weak, they must be saying it about Python?
- masklinn 12y ago> That's a C example, where it demonstrates my point perfectly. Yeah I kinda forgot about the result. > Python doesn't even have a printf function, where did you get the idea it was supposed to be Python? Nowhere? I never assumed your example was python, I was showing something irrelevant.
- icebraining 12y agoPython's type system isn't very expressive-- for example, you have "list" and "dict" types but not "list of int" Sure you can. >> from array import array >> a = array('i') >> a.append(3) >> a array('i', [3]) >> a.append('Hello') TypeError: an integer is required The default "list" type just happens to be an heterogeneous list.
- bunderbunder 12y agoAll of the modern dynlangs (e.g. Python, Ruby, Clojure) enforce type safety. Well, a lot of them. Some are weakly typed, and IMO weak typing is genuinely damaging whereas I'll concede some room for the static/dynamic debate. Example: What's "1" + 1? Answer: In JavaScript, it's "11". In PHP, it's 2. Meaning it's possible that it could mean two different things in the same file.
- dllthomas 12y ago"Meaning it's possible that it could mean two different things in the same file." If you're spanning languages, that's not unusual. I have Haskell code with C in quasiquotes. What's x /= 2?
- dragonwriter 12y agoThat's not a weak typing artifact, its an artifact of the fact that different languages use operators with the same name but with different semantics. (And the fact that you can have PHP and JS, which are different languages, in the same file.) You could have the same issue with languages with indisputably strong, static typing with different semantics if there was a way of embedding them in the same file.
- bunderbunder 12y agoLanguage that value strong type-safety guarantees won't respond to a request for "1" + 1 by quietly coercing one value to the other's type and moving along as if nothing strange happened. They'll generate a type mismatch error because adding an integer to a text string is undefined operation.
- dragonwriter 12y agoPerhaps (though, discarding the emotional language of "quietly" and "as if nothing strange happened", there's all kinds of things in strong, statically-typed languages that aren't much different structurally from that, though if they did it would usually be by way of an operator working on a typeclass which included a total, rather than partial, conversion function to support the operation, so that the semantics of addition of string and whatever numeric type it was supported with would be well defined for all strings, rather than being only defined for particular strings; then again, its not like Haskell doesn't have functions that crash on values of an appropriate type but unsuppored specific values, so maybe not), but, in any case, f a b (or f(a,b) or (f a b) or a op b, depending on the syntax of the languages involved and the kind of function/operator at issue) having two different meanings in two different languages (specifically, two that can be included in the same file), which was what was complained about that example, isn't something that only occurs with that example, and it certainly can occur in strong statically-typed languages without even considering hypothetical constructs.
- pekk 12y agoWhat would it help, in Python, to have 'list of int'?
- _yosefk 12y agoA more compact representation is one advantage - that's why numpy has array of int.
- codygman 12y agoYou don't have to validate all objects inside of that list are an int or handle cases via duck typing, exceptions, etc. As _yosefk said, the interpreter can assume a more compact representation.