Hacker News new | past | comments | ask | show | jobs | submit login

It seems that your point boils down to "Python enforces types at runtime if you define 'enforce types at runtime' not to include 'enforcing that data you declare to be of a certain type actually is of that type'".

Am I the only one baffled by this way of thinking?




Python does and always has enforced types at runtime. This is called duck-typing. If you're not familiar with the concept of strong+dynamic, it is easy to see how this could be confusing. This may help. https://stackoverflow.com/questions/2351190/static-dynamic-v...

Static type annotations by definition are not enforced at runtime. This has been true of every language that has ever used static typing, including C, C++, Java, Rust, Typescript... you name it, statically typed languages only enforce their static typing at compile/analysis time.

Yes, it is possible to annotate types in Python incorrectly. It's possible to do this in all other languages that allow type-unsafe behavior (whether natively or via reflection, etc). This may be less common in some languages than in others, but it is fundamentally possible in the vast majority of languages that perform static typing, because those types are fundamentally enforced at analysis time, not runtime.

The author of the article seems to be unfamiliar with these distinctions, and maybe you are too. It's fair to complain that these distinctions are confusing and make things harder for programmers. Nevertheless, very few languages have ever been designed with a type system that acts exactly the same at analysis time and runtime. It's a very difficult problem, partly because these are all abstractions from the perspective of the underlying computer, which only understands boolean logic and integer/floating point math, and has virtually no other notion of types in any formal sense.

Type systems are a complex topic, and as someone who has been paying attention to them for a while, it's frustrating to see uninformed discussion of them show up on Hacker News. That said, it's perfectly understandable that people are confused by these distinctions, and rest assured there's a lot of effort going into developing better languages that suffer _less_ from these issues.

For the everyday working programmer, however, there are currently lots of tradeoffs to be made, and Python's approach to static+dynamic typing is actually pretty usable, all things considered, which is why the community overall has embraced the new static typing despite its blemishes.


Duck typing is really enforcement of interfaces, not types themselves. Everyone who has passed a string into a Python method expecting a list of strings has run into this. It works, but did you really want to process a character at a time?

Also, some languages like Java do actually enforce types at runtime. If you've ever called a Java method dynamically with the wrong types, you'd know. You can run into ClassCastException, or worse (ClassNotFoundException if you have the wrong classloader.) This is a runtime error.


> Duck typing is really enforcement of interfaces, not types themselves

A type system is just a set of rules that must be followed. The rules can be as weird or as simple as you want. Just because <int> + <string> is allowed doesn't mean it's not enforcing types.

Not really a criticism, just trying to push to expand your idea of what a type system is.


> Yes, it is possible to annotate types in Python incorrectly. It's possible to do this in all other languages that allow type-unsafe behavior (whether natively or via reflection, etc). This may be less common in some languages than in others, but it is fundamentally possible in the vast majority of languages that perform static typing, because those types are fundamentally enforced at analysis time, not runtime.

It is pretty damn hard to make this mistake in languages that enforce static typing. I mean, you would have to go out of your way to do so. In Python, however, it is trivial to write the wrong type signature or to modify the body of a function so that it no longer matches the signature.

"Fundamentally possible but terribly unlikely, as opposed to the Python way of doing it" would be a more accurate description.


I think your (and the article's) argument could be summarized as "static type annotations without automated enforcement by actually running a type checker considered harmful".

Since this argument is not meaningfully different from "comments that are lies considered harmful", it seems fair to expect reasonable people to dismiss it as uninteresting.


It is meaningfully different because, as the article says, comments are known to not be machine verified and thus to potentially be wrong. With type hints, they’re usually verified, but not always, so you’re more likely to trust them and get a nasty surprise when they turn out to be wrong.

However, there are other aspects to the article’s argument, such as the fact that it’s easy to end up with type annotations going silently unenforced even if you do run the checker.


> it seems fair to expect reasonable people to dismiss it as uninteresting.

Do you think that's a fair treatment of someone who disagrees with you but has been respectful of your opinion so far?

I realize proglang debates are flamewar territory. But I have been very careful to state I find Python type hints puzzling and less useful than they should be. It is obviously an interesting opinion shared by many others, not just me or the article's author.

As a fan of statically typed languages, I do indeed find some Python programmers engage in a form of Stockholm's syndrome. It usually takes the form of the assertion "I never found a bug that was a type error". Have you or anyone you know ever said this?

In my mind, the opposite statement of the one you attribute to me would be "wishful thinking and a positive attitude is enough to catch mistakes, it's not necessary to have help from automated tooling". In this day and age, I cannot disagree more.


I'm very confused by your response. Where did I suggest that I don't like type systems or think automated tooling is not useful?

It's precisely because I do like and use them that I find Python's static type hints to be extremely useful for large Python codebases.

What I hear you saying is "Python does not offer these things". What I hope you hear me saying is "Python does, in fact, offer these things".


Well, you did frame the discussion as:

> I think your (and the article's) argument could be summarized as "static type annotations without automated enforcement by actually running a type checker considered harmful"

It illustrates your mindset, in my opinion. I think type annotations without checking them (or without a satisfying implementation of said type checking) are mostly pointless.

You also left out the part where I remarked on the dismissive tone of your reply.


No, you're not the only one. All of these gymnastics to justify the behavior of the string-declared-int baffle me.

Is it "legally" baffling, i.e., do I understand why this behaves in the way it does purely mechanically, and do I understand the arguments the gymnasts are making? Yes.

But from an idiomatic, colloquial, linguistic, syntactic, programming-historical, or programming-cultural standpoint? Baffled.

Even calling it gradual typing is baffling. It's just adding metadata-that-doesn't-look-like-metadata that sophisticated programs that aren't part of the Python bytecode compiler can use. The definition I know is the same one from Wikipedia:

> Gradual typing is a type system in which some variables and expressions may be given types and the correctness of the typing is checked at compile time [...]

This is definitely not what Python is doing.


> This is definitely not what Python is doing.

Maybe not by default but there is tooling that makes it work that way — that’s exactly how the python build system works at my company. I don’t know the details but when I “build” python code (creating bytecode pyc files) it produces compiler errors and fails to build if I e.g. try to pass an int to an f(x: str). This has usefully caught bugs before I ran some expensive/time-consuming scripts.

I guess you could say this doesn’t count as it’s a separate program doing the type checking but IMO there’s not a clear distinction between that and e.g. having a first type checking pass in the “same” compiler program.


I don't know the latest but PEP 484 writes:

> While these [type] annotations are available at runtime through the usual __annotations__ attribute, no type checking happens at runtime. Instead, the proposal assumes the existence of a separate off-line type checker which users can run over their source code voluntarily.


Right, it’s definitely still a voluntary feature. What I meant is if you opt in and make it part of your project’s standard build procedure for python code, you effectively get the behavior and benefits of “compile-time type checking” (to the extent that you actually use type annotations in your code).


>> Gradual typing is a type system in which some variables and expressions may be given types and the correctness of the typing is checked at compile time [...] > This is definitely not what Python is doing.

When I read "compile time", I mentally replace it with "before runtime". There isn't a real compilation step in Python, so it's reasonable to accept static code analysis as part of "compile time" in that definition.

The point is that type annotations will let a static analysis tool make sure that the program is correctly typed. This can be enabled easily in most of the modern IDEs and editors. You could just decide to block the code's deployment in CI/CD if the type checker raises issues, for example.


This is how all or most statically-typed languages work, too. The typing is purely a compile-time construct.

E.g. this kind of code: https://play.rust-lang.org/?version=stable&mode=debug&editio...

typically works fine (or worse, works fine in debug mode and causes unpredictable UB-related bugs in release mode).

std::mem::transmute here is a no-op at runtime; all it does is subvert the static type checker.

The difference between statically-typed languages and things like Python with type hints is _not_ that the former has any runtime type checking; it’s that subverting the (static!) type system is more difficult and requires more obvious ceremony, and that static type checking is required whereas with Python it’s optional.

If you hacked rustc to disable static typechecking you would get a similar experience to Python with type hints but without any mypy-like tools. (Of course, this would be hard to do in practice, because Rust, like most statically-typed languages, uses types not just for typechecking but also for code generation and method dispatch.)




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

Search: