5 ms·
When I did most of my work in Python, typehints weren't a thing. I still feel like static typechecking is less useful in Python since its datamodel is overally
by bayesian_horse 4y ago
When I did most of my work in Python, typehints weren't a thing. I still feel like static typechecking is less useful in Python since its datamodel is overally less of a hot mess compared to Javascript for example.
And Python modules/frameworks can be a lot more "typed" than you'd expect. Django models, forms etc offer more runtime validation than typesystems can easily achieve. Yes, at runtime. But between not having a build process and in general being more readable and concise, I feel like Python lets you run into the runtime error long before you get the same thing done "error free" in C#. Not that C# doesn't have runtime errors...
- phailhaus 4y ago> its datamodel is overally less of a hot mess compared to Javascript for example. I don't understand this, what do you mean? TypeScript is such a success partly because everything is an object in Javascript. There's no need to distinguish between classes and "dicts", as you have to with Python. Another example: Python functions have args and kwargs, which make typing significantly more complex (as the article points out, Callable doesn't even support kwargs). Javascript doesn't, so typing functions is trivial. Part of the point of static typechecking is documentation that can be verified by tooling. If you have no types in your codebase, and you decide to change something from a dict to a class, good luck! You're going to have to manually trace all the data flows through your entire application to figure out what's affected.
- pdonis 4y ago> everything is an object in Javascript Everything is an object in Python too. > There's no need to distinguish between classes and "dicts", as you have to with Python. "dict" in Python (or at least Python 3, but Python 2 is EOL now so Python 3 is the only active Python there is) is a class. You can even subclass it, which if you want a customized dict for some reason in your particular application is often the best way to do it. Or you can subclass MutableMapping, which dict itself is a subclass of, and which is what is supposed to be used for isinstance checks now that Python has established abstract base classes for all of its standard "built-in type" interfaces.
- phailhaus 4y ago> Everything is an object in Python too. Ah yes, true. JavaScript goes one step further though, and has no distinction between get-item accesses and attribute accesses. This makes TypeScript's data model much simpler to manage. Is it even possible to implement your own `MutableMapping` or `dataclasses` equivalent type in Python? I know the latter requires custom plugins.
- pdonis 4y ago> JavaScript goes one step further though, and has no distinction between get-item accesses and attribute accesses. Can you explain a bit more about what you mean here? > Is it even possible to implement your own `MutableMapping` or `dataclasses` equivalent type in Python? Of course. With dataclasses that's what Python itself does; that's a pure Python module: https://github.com/python/cpython/blob/3.11/Lib/dataclasses.py https://github.com/python/cpython/blob/3.11/Lib/dataclasses.... For MutableMapping, Python currently implements it as a C class for speed, but you could implement the same functionality in pure Python. That's what earlier versions of the collections.abc module did. > I know the latter requires custom plugins. I don't know what you mean here. See the pure Python module that Python itself provides above.
- phailhaus 4y agoThere is no difference between `object["hello"]` and `object.hello`. So in Typescript, all you need is `interface`, that's it. Everything (except primitives) is just an `interface` with keys or index signatures. > Of course. With dataclasses that's what Python itself does; that's a pure Python module: Sorry, I meant that you can't create an equivalent class that typechecks the same way. For example, when you define a dataclass with fields, mypy and pyright are capable of inferring what args and kwargs the constructor supports. But that's because it was implemented as a special case. For example, see the mypy docs [1]. If you just alias `dataclasses`, you lose type support! Pydantic is a library with similar semantics, and the only way to get typechecking support is to install the pydantic plugin for the typechecker you use. The language simply can't express it. [1] https://mypy.readthedocs.io/en/stable/additional_features.html#caveats-known-issues https://mypy.readthedocs.io/en/stable/additional_features.ht...
- KyeRussell 4y agoOP is not saying that type checking is useful. They’re saying that it’s not as useful.
- phailhaus 4y agoWhat about Python's data model makes typechecking less useful? You still need to know how data flows through your application. You can either document it in your types, or require your engineers to hold all that information in their heads/recapitulate it every time they want to refactor code. That has nothing to do with the language's data model.
- ReflectedImage 4y ago[flagged]
- phailhaus 4y agoCitation heavily, heavily needed. Dynamic typing means that none of your code can be statically checked, which means that correctness relies on the exhaustiveness on your tests. It should be obvious that this would allow you to introduce more bugs, not fewer. Every program involves passing around data. When you need to change that data in a dynamic untyped language, you have no option but to manually test your whole system to make sure that you nailed all the spots. Compare that to a language like TypeScript. If I need to refactor my code, I update the type and the static typechecker immediately tells me all the spots I need to fix. I don't have to hunt for them, I don't have to run it 100x trying to hit every edge case. And JavaScript is still dynamic, it doesn't stop me from writing concise code. This isn't theoretical. I literally just worked on changing something from a dict to an object in Python, and it was a pain. Thankfully most spots were documented with type hints, but even then I ran into many runtime errors that could have been caught statically.
- ReflectedImage 4y ago[flagged]
- codexb 4y ago> Python functions have args and kwargs, which make typing significantly more complex Not really. It's only complex when they're used with poor design decisions. There are plenty of languages that allow you to do things that aren't a good idea. Python is no exception. Type hinting just makes those shortcomings more readily apparent. > Callable doesn't even support kwargs PEP 544 and Protocols have existed for 5 years, and they support keyword only type hinting for callables.
- phailhaus 4y agoI'm talking more about really simple patterns that Python's type system just can't support. Take kwargs. They've existed forever. A really common and not-stupid pattern is to write a subclass such that you only specify some arguments you care about, and then take *kwargs to pass on to the super constructor. Can't type this. You have to exhaustively enumerate those kwargs and pass them in manually, or else you lose type hinting for your subclass.
- codexb 4y agoYes, that exact scenario is supported with TypedDict. And while that is a simple pattern, it's not a good pattern, and quickly becomes unmaintainable in a program of any size. Using *kwargs because of Too-many-arguments and so you can violate the Liskov substitution principle isn't good programming. Just because it can be done doesn't mean we should start bastardizing typing to make it easier.
- phailhaus 4y ago> Yes, that exact scenario is supported with TypedDict. I don't think so. I just threw together a simple example that doesn't work: from typing import TypedDict class A(TypedDict): name: str age: int def myfunc(**kwargs: A): print(kwargs) myfunc() No errors with mypy. In fact, kwargs is inferred as `dict[str, A]`, which is unbelievable given that Python explicitly supports `**kwargs` as a way to represent a grab-bag of keyword arguments. > And while that is a simple pattern, it's not a good pattern, and quickly becomes unmaintainable in a program of any size It's not though, if you had a proper type system. For example, you could do this trivially in Typescript and it would automatically infer the types of the rest of the kwargs. That means that your type information is preserved, making it possible to keep using your subclass without losing information about the total set of arguments it supports. The advantage is that you can add/remove arguments to your base class without having to hunt down every subclass, and you're guaranteed to be correct (and it would error otherwise!).
- bayesian_horse 4y agoWith hot mess I mean things like undefined vs null, various surprising comparisons, truthiness, lack of a primitive integer type...