[HN Gopher] Python developers are embracing type hints
___________________________________________________________________
Python developers are embracing type hints
Author : ocamoss
Score : 290 points
Date : 2025-09-24 11:23 UTC (4 days ago)
(HTM) web link (pyrefly.org)
(TXT) w3m dump (pyrefly.org)
| LoganDark wrote:
| I think I've always used Python type hints, but that was
| partially because early versions of Discord.py relied on them
| (maybe it still does). But it was also because I like to be able
| to mentally verify my code's correctness before running it, and
| waiting for runtime errors is comparatively a huge waste of time
| (in my opinion).
| secondcoming wrote:
| I recently had to debug someone else's Python code and trying to
| figure out what variables are was a massive headache, especially
| coming from C++.
| skydhash wrote:
| I do not program that much in python, but I believe the general
| accepted wisdom in dynamic languages was explicit name and load
| of documentations (as comments and docstrings).
| imron wrote:
| Absolutely the general accepted wisdom in line with best
| practices - that are often ignored
| maleldil wrote:
| > explicit name and load of documentations (as comments and
| docstrings).
|
| Which can be out of date are often missing. Might as well use
| type-hints that can be statically checked.
| skydhash wrote:
| If the name of a function and its docstring is out of date,
| then what you have is a bad culture for coding. It's up
| there with god classes in OOP.
| Akronymus wrote:
| Even c++ feels clunky in terms of types to me. Though that's
| probably down to me preferring a more complete type system like
| haskell has
| rcfox wrote:
| In Python, every variable is either defined or imported in the
| file in which it's used, so you always know where to find it.
| (Assuming you don't do `from foo import *`, which is frowned
| upon.)
|
| In C++, a variable might be defined in a header or in a parent
| class somewhere else, and there's no indication of where it
| came from.
| maleldil wrote:
| How does this help when trying to determine the parameters a
| function takes? You have to either hope that the name is
| descriptive enough or that the function is well-documented.
| Failing that, you need to read the code to find out.
| kstenerud wrote:
| CMD-click shows you.
| lacker wrote:
| Type hints are much easier to use nowadays than they were a few
| years ago, because the agentic tools like Claude Code are very
| good at converting an existing codebase to using type hints.
| OutOfHere wrote:
| The flip side of it is that Claude Code will have a very bad
| time in a code base with grossly unsatisfiable or conflicting
| types (where a type checker would fail the project). A human
| should always first ensure that the types are broadly correct,
| with or without the assistance of code tools.
| Waterluvian wrote:
| I can empathize with the code tools. Sometimes I'll read
| Python code and have no idea at first glance if these are
| type bugs or _creative_ coding by the dev. Python is
| incredibly flexible. Though I think most of the time you
| really shouldn't be using the flexibility.
| imron wrote:
| I enforce strong types on all Python code I'm responsible for -
| and make sure others don't play fast and loose with dict[str,
| Any] when they could use a well defined type.
|
| Doing otherwise is just asking for prod incidents.
| scuff3d wrote:
| I worked on a project that did this. Drove me absolutely nuts.
| It's like having all the worst parts of a dynamic language and
| a static language with none of the benefits.
|
| I'd much rather just work in a statically typed language from
| the start.
| lrobinovitch wrote:
| What exactly drove you nuts? The python ecosystem is very
| broad and useful, so it might be suitable for the application
| (if not, reasonable that you'd be frustrated). With strict
| mypy/pyright settings and an internal type-everything
| culture, Python feels statically typed IME.
| scuff3d wrote:
| It's not even close compared to working with Java or Go or
| any language built with static typing in mind.
|
| To be clear, I'm not opposed to type hints. I use them
| everywhere, especially in function signatures. But the
| primary advantage to Python is speed (or at least perceived
| speed but that's a separate conversation). It is so popular
| specifically because you don't have to worry about type
| checking and can just move. Which is one of the many
| reasons it's great for prototypes and fucking terrible in
| production. You turn on strict type checking in a linter
| and all that goes away.
|
| Worse, Python was not built with this workflow in mind. So
| with strict typing on, when types start to get complicated,
| you have to jump through all kinds of weird hoops to make
| the checker happy. When I'm writing code just to make a
| linter shut up something is seriously wrong.
|
| Trying to ad typing to a dynamic language in my opinion is
| almost always a bad idea. Either do what Typescript did and
| write a language that compiles down to the dynamic one, or
| just leave it dynamic.
|
| And if you want types just use a typed language. In a
| production setting, working with multiple developers, I
| would take literally almost any statically typed language
| over Python.
| Spivak wrote:
| But TypeScript erases (its) types at runtime, exactly
| like Python. Python is Python's TypeScript. Whether you
| want TS or JS-like semantics is entirely dependent on
| whether you use a type checker and whether you consider
| its errors a build breaker.
| ehutch79 wrote:
| Not it doesn't. It doesn't throw errors, but they're
| still introspectable in python, unlike typescript
| scuff3d wrote:
| I'm not sure what you're trying to say here. If you mean
| Python's type annotations are erased at runtime... Okay?
| It still has runtime type information. It's not "erasure"
| as that term applies to Java for example. And Typescript
| compiles down to JavaScript, so obviously it's runtime
| behavior is going to be the same as JavaScript.
|
| In my view it's always a mistake to try and tac static
| typing on top of a dynamic one. I think TS's approach is
| better than Python's, but still not nearly as good as
| just using a statically typed language.
| ngrilly wrote:
| The fact that the types are reflected at runtime is what
| makes FastAPI/Pydantic possible, letting us use Python
| types to define data models used for serialization,
| validation, and generating. In TypeScript, we have to use
| something like Zod, instead of "normal" TypeScript types,
| because the types are not reflected at runtime.
| scuff3d wrote:
| I think a couple of things have to be untangled here.
|
| The problem we are talking about in both Python and TS
| comes from the fact that they are (or compile down to)
| dynamic languages. These aren't issues in statically
| typed languages... because the code just won't compile it
| it's wrong and you don't have to worry about getting data
| from an untyped library.
|
| I don't know a lot about Zod, but I believe the problem
| you are referring to is more about JavaScript then TS.
| JavaScript does a LOT of funky stuff at runtime, Python
| thank God actually enforces some sane type rules at
| runtime.
|
| My point was not about how these two function at runtime.
| My point was that if you want to tac static typing onto a
| dynamic language, Typescripts approach is the better one,
| but even if can't fix the underlying issues with JS.
|
| You could take a similar approach in Python. We could
| make a language called Tython, that is statically typed
| and then compiles down to Python. You eliminate an entire
| class of bugs at compile time, get a far more reliable
| experience then the current weirdness with gradual typing
| and linters, and you still get Pythons runtime type
| information to deal with things like interopt with
| existing Python code.
| AlienRobot wrote:
| Typescript requires a compiler to produce valid
| Javascript. Python 3 shoved types into Python 3 without
| breaking backwards compatibility I think.
|
| You would never have typing.TYPE_CHECKING to check if
| type checking is being done in TypeScript, for example,
| because type hints can't break Javascript code, something
| that can happen in Python when you have cyclic imports
| just to add types.
| throwaway81523 wrote:
| I would say mypy is better than nothing but it still misses
| things sometimes, and makes some signatures difficult or
| impossible to write. I use it anyway, but patched-on static
| typing (Erlang, Clojure, and Racket also have it) seems
| like a compromise from the get-go. I'd rather have the type
| system designed into the language.
| IshKebab wrote:
| Mypy is trash but Pyright is very good.
| chpatrick wrote:
| I went from mypy to pyright to basedpyright and just
| started checking out pyrefly (the OP), and it's very
| promising. It's written in Rust so it's very efficient.
| imron wrote:
| I too would much rather work in a statically typed language,
| but sometimes you have to work with what you've got.
|
| These systems are part of the core banking platform for a
| bank so I'd rather some initial developer friction over
| runtime incidents.
|
| And I say initial friction because although developers are
| sometimes resistant to it initially, I've yet to meet one who
| doesn't come to appreciate the benefits over the course of
| working on our system.
|
| Different projects have different requirements, so YMMV but
| for the ones I'm working on type hints are an essential part
| of ensuring system reliability.
| scuff3d wrote:
| I'm not opposed to type hints, I use them everywhere. It's
| specially the strict linting.
|
| But it's a fair point. If you truly have no option it's
| better then absolutely nothing. I really wish people would
| stop writing mission critical production code in Python.
| Syntaf wrote:
| I feel like it's more often a result of suffering from
| success that leads to these situations, rather than a
| lack of foresight to begin with.
|
| For example I work on a python codebase shared by 300+
| engineers for a popular unicorn. Typing is an extremely
| important part of enforcing our contracts between teams
| within the same repository. For better or for worse,
| python will likely remain the primary language of the
| company stack.
|
| Should the founder have chosen a better language during
| their pre-revenue days? Maybe, but at the same time I
| think the founder chose wisely -- they just needed
| something that was _quick_ (Django) and capable of
| slapping features / ecosystem packages on top of to get
| the job done.
|
| For every successful company built on a shaky dynamic
| language, there's probably x10 more companies that failed
| on top of a perfect and scalable stack using static
| languages.
| pydry wrote:
| A statically typed language doesnt prevent developers from
| using the equivalent of dict[str, Any].
| yxhuvud wrote:
| Well, some do. Let's not pretend all static type systems
| are the same.
| budro wrote:
| Type hints seem fantastic for when you're in maintenance mode
| and want to add sanity back to a system via automated
| tooling.
|
| However for new projects I find that I'd much rather pick
| technologies that start me off with a sanity floor which is
| higher than Python's sanity ceiling. At this point I don't
| want to touch a dynamically typed language ever again.
| minikomi wrote:
| Always fun to inherit a data-scientist derrived chunk of
| pytjon code for which every type hint is 'takes a dataframe'
| and 'returns a dataframe'..
| Waterluvian wrote:
| Typescript turned me into a believer but my gosh do python
| typings feel clumsy and quickly busy up files. I get why, and
| it's not exactly realistic, but I wish a lot of it didn't require
| an import.
|
| Whatever the solution is, it doesn't include giving up on Python
| typings.
| mrln wrote:
| With the newest Python versions, most of the time I don't need
| typing imports!
| letmeinhere wrote:
| Yeah post 3.10 you don't need Union, Optional, List, Duct,
| Tuple. Any still necessary when you want to be permissive,
| and I'm still hoping for an Unknown someday...
| maleldil wrote:
| > hoping for an Unknown someday
|
| Wouldn't that just be `object` in Python?
| Narushia wrote:
| That's what I use it for. If you type something as
| `object`, static type checkers can just narrow down the
| exact typing later.
| lexicality wrote:
| No, because the type checker should prevent you
| interacting with `Unknown` until you tie it down, but
| `object` is technically a valid type
| rgovostes wrote:
| I am glad they improved this but I still like Optional[],
| and to a lesser extent, Union[]. It's much more readable to
| have Optional[str] compared to str | None.
| Narushia wrote:
| I disagree with `Optional`. It can cause confusion in
| function signatures, since an argument typed as
| "optional" might still be _required_ if there is no
| default value. Basically I think the name is bad, it
| should be `Nullable` or something.
|
| I believe Python's own documentation also recommends the
| shorthand syntax over `Union`. Linters like Pylint and
| Ruff also warn if you use the imported `Union`/`Optional`
| types. The latter even auto-fixes it for you by switching
| to the shorthand syntax.
| __MatrixMan__ wrote:
| > List, Duct, Tuple...
|
| I'm aware this is just a typo but since a lot of the Python
| I write is in connection with Airflow I'm now in search of
| a way to embrace duct typing.
| quotemstr wrote:
| Type hints in dynamic languages are great, but I wish they came
| with deeper integration into the language runtime for validation
| and for optimizer setup.
|
| If I have a function that takes an int, and I write down the
| requirement, why should a JIT have to learn independently of what
| I wrote down that the input is an int?
|
| I get that it's this way because of how these languages evolved,
| but it doesn't have to _stay_ this way.
| dmurray wrote:
| That was the original intent of mypy, to allow a subset of
| Python to be interpreted by a JIT or transpiled to a compiled,
| statically typed language.
|
| The type hints proved to be useful on their own so the project
| moved past what was useful for that purpose, but a new JIT
| (such as the one the upcoming CPython 3.14 lays the groundwork
| for) could certainly use them.
| donatj wrote:
| Typings have pretty cleanly been getting added to PHP over the
| last decade. I'm kind of surprised Python's are so bolted on by
| comparison
| morkalork wrote:
| They do remove an entire class of avoidable errors in code bases
| of course people will embrace it.
| LordDragonfang wrote:
| The biggest reason I use typehints is that VSCode's intellisense
| relies on them - and I know I've missed one when typing a dot
| doesn't give me the method I'm expecting.
| circadian wrote:
| I really love Python for it's expedience, but type hints still
| feel like they don't belong in the language. They don't seem to
| come with the benefits of optimisation that you get with static
| typed languages. As someone who uses C and Julia (and wishes they
| had time for Rust), introducing solid typing yields better end
| results at a minimum, or is a requirement at the other end of the
| scale.
|
| The extra typing clarification in python makes the code harder to
| read. I liked python because it was easy to do something quickly
| and without that cognitive overhead. Type hints, and they feel
| like they're just hints, don't yield enough of a benefit for me
| to really embrace them yet.
|
| Perhaps that's just because I don't use advanced features of
| IDEs. But then I am getting old :P
|
| EDIT: also, this massively depends on what you're doing with the
| language! I don't have huge customer workloads to consider any
| longer..!
| imron wrote:
| > I don't use advanced features of IDEs
|
| I use vanilla vim (no plugins) for my editor, and still
| consider type hints essential.
| zahlman wrote:
| > They don't seem to come with the benefits of optimisation
| that you get with static typed languages
|
| They don't. And cannot, for compatibility reasons. Aside from
| setting some dunders on certain objects (which are entirely
| irrelevant unless you're doing some crazy metaprogramming
| thing), type annotations have no effect on the code at runtime.
| The Python runtime will happily bytecode-compile and execute
| code with incorrect type annotations, and a type-checking tool
| really can't do anything to prevent that.
| afiori wrote:
| Now that python has a jit it could use them (not saying it
| should) for speculative compilation
|
| My understanding is that currently python can collect type
| data in test runs and use it to inform the jit during
| following executions
| zahlman wrote:
| > Now that python has a jit it could use them (not saying
| it should) for speculative compilation
|
| I'd forgotten about that. Now that you mention it, my
| understanding is that this is actually the plan.
| xdfgh1112 wrote:
| They catch bugs. And you don't have to use them; even if
| they're only provided by libraries, there is a benefit to
| users.
| stellalo wrote:
| > The extra typing clarification in python makes the code
| harder to read
|
| It's funny, because for me is quite the opposite: I find myself
| reading Python more easily when there are type annotations.
|
| One caveat might be: for that to happen, I need to know that
| type checking is also in place, or else my brain dismissed
| annotations in that they could just be noise.
|
| I guess this is why in Julia or Rust or C you have this
| stronger feeling that types are looking after you.
| circadian wrote:
| I think the face they fundamentally don't look after you is
| where my resistance comes from. Will try and evaluate some
| newer code that uses them and see how I get on a bit more :)
| Ekaros wrote:
| Remembering project where type hints would have been helpful to
| grok the code I do now mostly like them. They are useful when
| you come back after days or weeks and try to remember what does
| this function produce and what does this one actually take in.
|
| And Python always was rather strongly typed, so you anyway had
| to consider the types. Now you get notes. Which often do help.
| IshKebab wrote:
| > The extra typing clarification in python makes the code
| harder to read.
|
| It depends what you mean by "read". If you literally mean
| you're doing a weird Python poetry night then sure they're sort
| of "extra stuff" that gets in the way of your reading of `fib`.
|
| But most people think of "reading code" and reading _and
| understanding_ code, and in that case they definitely make it
| easier.
| tdeck wrote:
| 'Twas brillig: Adjective and the slithy toves: Noun
| Did gyre: Verb and gimble: Verb in the wabe: Noun
| Izkata wrote:
| As someone who has read code as easily as English for decades
| (which is apparently rare, if my co-workers are any
| indication), too many type annotations clutter it up and make
| it a lot harder to read. And this is after having used
| Typescript a lot in the past year and liking that system - it
| works well because so much can be inferred.
| IshKebab wrote:
| Python also has type inference. I don't think it really has
| more type annotation "noise" than Typescript does.
| mcdeltat wrote:
| Interesting that for you typing makes the code harder to read.
| What context do you use Python for? And who is writing it?
|
| In my experience I have seen far too much Python code like
|
| `def func(data, _args, *kwargs)`
|
| with no documentation and I have no clue wtf it's doing. Now I
| am basically all in on type hints (except cases where it's
| impossible like pandas)._
| bgwalter wrote:
| Because they follow any corporate initiative that gives them
| something to do, even if the type hints are the most unreadable
| and hackish form of typing in existence.
| scuff3d wrote:
| Or you could just use a statically typed language and get a much
| better experience.
| fnord77 wrote:
| A entire class of bugs, wiped out by a thing called a
| "compiler". Gigahours of downtime and bug fixing globally
| prevented by a modest extra step up front. Great stuff.
| scuff3d wrote:
| I had someone say to me they preferred strict type checking
| in a Python linter over a statically typed language because
| they "don't like a build step"...
|
| Dudes it's literally just worse compilation with extra steps.
| __MatrixMan__ wrote:
| I'm in favor of partitioning the set of reasons it can fail
| to compile into separate checks with separate tools. Taming
| the zoo of tooling is extra work, but smaller more focused
| tools are easier to work with once you understand their
| relationship to their neighbors.
|
| There's a world of difference between:
|
| > I've been using a different type checker and I like it,
| you should try it
|
| And
|
| > I'd like to switch our project to a different compiler
|
| The former makes for more nimble ecosystem.
| scuff3d wrote:
| Yes, if you are stuck with Python something is certainly
| better than nothing. But we shouldn't be writing large
| production apps in it in the first place.
| __MatrixMan__ wrote:
| Should we be writing large apps at all?
| scuff3d wrote:
| I don't know how to respond to this. Yes, large software
| projects do in fact exist...
| ashu1461 wrote:
| Sometimes that is not an option, consider the bias which python
| gets due to all the LLM libraries being python first.
| krzat wrote:
| Yeah, I thought lack of typing in python was intentional to
| support this another paradigm of programming for geniuses who
| don't need hand holding.
|
| Turns out they just didn't know any better?
| scuff3d wrote:
| How would a static type system have anything to do with
| handholding?
| chpatrick wrote:
| Would you? Why?
|
| Python has a great experience for a bunch of tasks and with
| typing you get the developer experience and reliability as
| well.
| pansa2 wrote:
| > _Why?_
|
| Python's 3 traditional weak spots, which almost all
| statically-typed languages do better: performance,
| parallelism and deployment.
| chpatrick wrote:
| None of those things are to do with typing. Python is slow
| because it's interpreted, bad at parallelism because of the
| GIL (which is going away), and bad at deployment because of
| the messy ecosystem and build tools (although it's pretty
| good with Nix). Conversely other languages aren't good at
| those because of static typing.
|
| It is a great choice though for many problems where
| performance isn't critical (or you can hand the hard work
| off to a non-Python library like Numpy or Torch). Typing
| just makes it even better.
| scuff3d wrote:
| No you don't. You get the illusion of static types without
| the actual upsides.
|
| For any even medium sized project or anything where you work
| with other developers a statically typed language is always
| going to be better. We slapped a bunch of crap on Python to
| make it tolerable, but nothing more.
| chpatrick wrote:
| I disagree and I've been using Haskell professionally for
| ten years so I know what I'm talking about when it comes to
| types. Typed Python isn't perfect but it's totally workable
| with medium sized projects and gives you access to a great
| ecosystem.
| throwaway81523 wrote:
| Oh datatype hints. I ignored the headline on first scan, thinking
| it was about font metrics.
| simonw wrote:
| The thing that finally got me on board with optional type hints
| in Python was realizing that they're mainly valuable as
| documentation.
|
| But it's _really valuable_ documentation! Knowing what types are
| expected and returned just by looking at a function signature is
| super useful.
| lysace wrote:
| Decent argument in principle. It still sucks for non-obvious
| types though:
|
| https://old.reddit.com/r/Python/comments/10zdidm/why_type_hi...
|
| Edit: Yes, one can sometimes go with Any, depending on the
| linter setup, but that's missing the point, isn't it?
| mjr00 wrote:
| As the top comment says, if you don't know or want to define
| the type just use Any. That's what it's there for.
|
| That entire Reddit post is a clueless expert beginner rant
| about something they don't really understand, unfortunate
| that it's survived as long as it has or that anyone is taking
| it as any sort of authoritative argument just because it's
| long.
| pdonis wrote:
| _> if you don 't know or want to define the type_
|
| That's not the issue the reddit post is raising. The reddit
| post is pointing out that what a "type" is is not as simple
| as it looks. Particularly in a language like Python where
| user-defined types proliferate, and can add dunder methods
| that affect statements that involve built-in operations.
| "Just use Any" doesn't solve any of those problems.
|
| _> just use Any._
|
| All the above said: not putting a type in at all is even
| easier than using Any, and is semantically equivalent.
| mjr00 wrote:
| The Reddit post falls under the case of "don't know" the
| type. If you want to allow users to pass in any objects,
| try to add and fail at runtime... that's exactly what Any
| is for.
|
| But the entire post is built upon the premise that
| accepting all types is good API design. Which it isn't,
| at all.
| zahlman wrote:
| > But the entire post is built upon the premise that
| accepting all types is good API design. Which it isn't,
| at all.
|
| Was Tim Peters also wrong way back in the day when he
| counseled Guido van Rossum to allow floats to be added to
| integers without a cast, like other popular languages?
| mjr00 wrote:
| How is `float | int` anywhere close to equivalent to
| `Any`?
| MrJohz wrote:
| How is "responds to the `__add__` method" anywhere close
| to equivalent to `Any`?
| mjr00 wrote:
| If your implication is that "implementing __add__ means
| you can use the + operator", you are incorrect. This is a
| common Python beginner mistake, but it isn't really a
| Python type checking issue, this is complexity with
| Python built-ins and how they interact with magic
| methods.
|
| My suggestion -- don't rely on magic methods.
| jampekka wrote:
| > My suggestion -- don't rely on magic methods.
|
| So no e.g. numpy or torch then?
| MrJohz wrote:
| I guess that's the difference between the Python and the
| TypeScript approach here. In general, if something is
| possible, valid, and idiomatic in JavaScript, then
| TypeScript attempts to model it in the type system.
| That's how you get things like conditional types and
| mapped types that allow the type system to validate quite
| complex patterns. That makes the type system more
| complex, but it means that it's possible to use existing
| JavaScript patterns and code. TypeScript is quite
| deliberately not a new language, but a way of describing
| the implicit types used in JavaScript. Tools like `any`
| are therefore an absolute last resort, and you want to
| avoid it wherever possible.
|
| When I've used Python's type checkers, I have more the
| feeling that the goal is to create a new, typed subset of
| the language, that is less capable but also easier to
| apply types to. Then anything that falls outside that
| subset gets `Any` applied to it and that's good enough.
| The problem I find with that is that `Any` is incredibly
| infective - as soon as it shows up somewhere in a
| program, it's very difficult to prevent it from leaking
| all over the place, meaning you're often back in the same
| place you were before you added types, but now with the
| added nuisance of a bunch of types as documentation that
| you can't trust.
| zahlman wrote:
| This is a strange and aggressive bit of pedantry. Yes,
| you'd also need `__radd__` for classes that participate
| in heterogenous-type addition, but it's clear what was
| meant in context. The fundamentals are not all "beginner"
| level and beginners wouldn't be implementing operator
| overloads in the first place (most educators hold off on
| classes entirely for quite a while; they're pure
| syntactic sugar after all, and the use case is often hard
| to explain to beginner).
|
| Regardless, none of that bears on the original `slow_add`
| example from the Reddit page. The entire point is that we
| have an intuition about what can be "added", but can't
| express it in the type system in any meaningful way.
| Because the rule is something like "anything that says it
| can be added according to the protocol -- which in
| practical terms is probably any two roughly-numeric types
| except for the exceptions, and also most container types
| but only with other instances of the same type, and also
| some third-party things that represent more advanced
| mathematical constructs where it makes sense".
|
| And saying "don't rely on magic methods" does precisely
| nothing about the fact that people _want_ the + symbol in
| their code to work this way. It does suggest that
| `slow_add` is a bad thing to have in an API (although
| that was already fairly obvious). But in general you do
| get these issues cropping up.
|
| Dynamic typing has its place, and many people really like
| it, myself included. Type inference (as in the Haskell
| family) solves the noise problem (for those who consider
| it a problem rather than something useful) and is elegant
| in itself, but just not the strictly superior thing that
| its advocates make it out to be. People still use Lisp
| family languages, and for good reason.
|
| But maybe Steve Yegge would make the point better.
| mjr00 wrote:
| > This is a strange and aggressive bit of pedantry.
|
| There's nothing pedantic about it. That's how Python
| works, and getting into the nuts and bolts of how Python
| works is precisely why the linked article makes type
| hinting appear so difficult.
|
| > The entire point is that we have an intuition about
| what can be "added", but can't express it in the type
| system in any meaningful way.
|
| As the post explores, your intuition is also incorrect.
| For example, as the author discovers in the process,
| addition via __add__/__radd__ is not addition in the
| algebraic field sense. There is no guarantee that adding
| types T + T will yield a T. Or that both operands are of
| the same type at all, as would be the case with "adding"
| a string and int. Or that A + B == B + A. We can't rely
| on intuition for type systems.
| pdonis wrote:
| _> The Reddit post falls under the case of "don't know"
| the type._
|
| No, it doesn't. The desired type is known; it's "Addable"
| (i.e., "doesn't throw an exception when the built-in add
| operator is used"). The problem is expressing that in
| Python's type notation in a way that catches all edge
| cases.
|
| _> If you want to allow users to pass in any objects,
| try to add and fail at runtime_
|
| Which is _not_ what the post author wants to do. They
| want to find a way to use Python 's type notation to
| catch those errors with the type checker, so they don't
| happen at runtime.
|
| _> the entire post is built upon the premise that
| accepting all types is good API design_
|
| It is based on no such thing. I don't know where you're
| getting that from.
| mjr00 wrote:
| > The desired type is known; it's "Addable" (i.e.,
| "doesn't throw an exception when the built-in add
| operator is used").
|
| The mistake both you and the reddit posts' author make is
| treating the `+` operator the same as you would an
| interface method. Despite Python having __add__/__radd__
| methods, this isn't true, nor is it true in many other
| programming languages. For example, Go doesn't have a way
| to express "can use the + operator" at all, and "can use
| comparison operators" is defined as an explicit union
| between built-in types.[0] In C# you could only do this
| as of .NET 7, which was released in Nov 2022[1] -- was
| the C# type system unusable for the 17 years prior, when
| it didn't support this scenario?
|
| If this were any operation on `a` and `b` other than a
| built-in operator, such as `a.foo(b)`, it would be
| trivial to define a Protocol (which the author does in
| Step 4) and have everything work as expected. It's only
| because of misunderstanding of basic Python that the
| author continues to struggle for another 1000 words
| before concluding that type checking is bad. It's an
| extremely cherry-picked and unrealistic scenario either
| from someone who is clueless, or knows what they're doing
| and is intentionally being malicious in order to
| engagement bait.[2]
|
| This isn't to say Python (or Go, or C#) has the best type
| system, and it certainly lacks compared to Rust which is
| a very valid complaint, but "I can't express 'type which
| supports the '+' operator'" is an insanely esoteric and
| unusual case, unsupported in _many_ languages, that it 's
| disingenuous to use it as an excuse for why people
| shouldn't bother with type hinting at all.
|
| [0] https://pkg.go.dev/cmp#Ordered
|
| [1] https://learn.microsoft.com/en-
| us/dotnet/standard/generics/m...
|
| [2] actually reading through the reddit comments, the
| author specifically says they were engagement baiting
| so... I guess they had enough Python knowledge to trick
| people into thinking type hinting was bad, fair enough!
| pdonis wrote:
| _> treating the `+` operator the same as you would an
| interface method_
|
| In other words, you _agree_ that the Python type hint
| system does not give you a good, built-in way to express
| the "Addable" type.
|
| Which means you are contradicting your claims that the
| type the article wants to express is "unknown" and that
| the article is advocating using "Any" for this case. The
| type is not unknown--it's exactly what I said: "doesn't
| throw an exception when using the + operator". That type
| is just not expressible in Python's type hint system in
| the way that would be needed. And "Any" doesn't address
| this problem, because the article is not saying that
| every pair of objects should be addable.
|
| _> "I can't express 'type which supports the '+'
| operator'" is an insanely esoteric and unusual case_
|
| I don't see why. Addition is a very commonly used
| operation, and being able to have a type system that can
| express "this function takes two arguments that can be
| added using the addition operator" seems like something
| any type system that delivers the goods it claims to
| deliver ought to have.
|
| _> unsupported in many languages_
|
| Yes, which means many languages have type systems that
| claim to deliver things they can't actually deliver. They
| can _mostly_ deliver them, but "mostly" isn't what
| advocates of using type systems in all programs claim. So
| I think the article is making a useful point about the
| limitations of type systems.
|
| _> it 's disingenuous to use it as an excuse for why
| people shouldn't bother with type hinting at all._
|
| The article never says that either. You are attacking
| straw men.
| mjr00 wrote:
| > I don't see why. Addition is a very commonly used
| operation, and being able to have a type system that can
| express "this function takes two arguments that can be
| added using the addition operator" seems like something
| any type system that delivers the goods it claims to
| deliver ought to have.
|
| If your comparison is Rust, sure, but you can't even
| express this in Java. No, Java's type system is not
| great, but it's a type system that's been used for
| approximately 500 trillion lines of production code
| powering critical systems and nobody has ever said "Java
| sucks because I can't express 'supports the + operator'
| as a generic type". (It sucks for many other reasons.)
|
| Again, it is _factually and objectively_ an esoteric and
| unusual case. Nobody in the real world is writing
| generics like this, only academics or people writing
| programming blogs about esoterica.
|
| If your argument is that all type systems are bad or
| deficient, fine, but calling out Python for this when it
| has the exact same deficiency as basically every other
| mainstream language is asinine.
|
| > The article never says that either. You are attacking
| straw men.
|
| The article says "Turning even the simplest function that
| relied on Duck Typing into a Type Hinted function that is
| useful can be painfully difficult." The subterfuge is
| that this is _not even remotely close to a simple
| function_ because the type being expressed, "supports
| the + operator", is _not even remotely close to a simple
| type_.
| drekipus wrote:
| The correct response to this is to figure what is the use
| case for your function: IE: add two numbers. Set the input
| and output as decimal and call it a day
| baobabKoodaa wrote:
| Sure. Let me just quickly refactor Pytorch.
| kstenerud wrote:
| Actually, it's not missing the point. Sometimes you really do
| want duck typing, in which case you allow Any. It's not all-
| or-nothing.
|
| What the reddit post is demonstrating is that the Python type
| system is still too naive in many respects (and that there
| are implementation divergences in behavior). In other
| languages, this is a solved problem - and very ergonomic and
| safe.
| smilliken wrote:
| The best kind of documentation is the kind you can trust is
| accurate. Type defs wouldn't be close to as useful if you
| didn't really trust them. Similarly, doctests are some of the
| most useful documentation because you can be sure they are
| accurate.
| zbentley wrote:
| The best docs are the ones you can trust are accurate. The
| second best docs are ones that you can programmatically
| validate. The worst docs are the ones that can't be validated
| without lots of specialized effort.
|
| Python's type hints are in the second category.
| seniorsassycat wrote:
| Do you have an example of the first?
| ItsHarper wrote:
| Languages with strong static type systems
| LudwigNagasena wrote:
| Is there a mainstream language where you can't
| arbitrarily cast a variable to any other type?
| btown wrote:
| I'd almost switch the order here! In a world with agentic
| coding agents that can constantly check for type errors
| from the language server powering the errors/warnings in
| your IDE, _and_ reconcile them against prose in
| docstrings... types you can programmatically validate are
| _incredibly_ valuable.
| ninetyninenine wrote:
| This is a naive realization. When type checking is used to the
| maximum extent they become as just as important as unit
| testing. It is an actual safety contribution to the code.
|
| Many old school python developers don't realize how important
| typing actually is. It's not just documentation. It can
| actually roughly reduce dev time by 50% and increase safety by
| roughly 2x.
| MangoToupe wrote:
| Static type checking (which is what I assume you mean by
| "typing") can also be a massive pain in the ass that stands
| in the way of incremental development, even if the end-goal
| is to ship an api with clear type signatures.
|
| There are developers who design apis by trying to figure out
| readable invocations. These developers discover, rather than
| design, type hierarchies and library interfaces.
|
| > Many old school python developers don't realize how
| important typing actually is.
|
| I don't think this is true. There's simply a communication
| breakdown where type-first developers don't see the benefits
| of disabling static checking to design interfaces, and
| interface-first developers don't see why they should put
| static checking ahead of interface iteration speed.
| ninetyninenine wrote:
| >There are developers who design apis by trying to figure
| out readable invocations. These developers discover, rather
| than design, type hierarchies and library interfaces.
|
| No, you're one of the old school python developers. Types
| don't hinder creativity, they augment it. The downside is
| the slight annoyance of updating a type definition and the
| run time definition vs. just updating the runtime
| definition.
|
| Let me give you an example of how it hinders creativity.
|
| Let's say you have a interface that is immensely complex.
| Many nested structures thousands of keys, and let's say you
| want to change the design by shifting 3 or 4 things around.
| Let's also say this interface is utilized by hundreds of
| other methods and functions.
|
| When you move 3 or 4 things around in a complex interface
| you're going to break a subset of those hundreds of other
| methods or functions. You're not going to know where they
| break if you don't have type checking enabled. You're only
| going to know if you tediously check every single
| method/function OR if it crashes during runtime.
|
| With a statically typed definition you can do that change
| and the type checker will identify EVERY single place where
| an additional change to the methods that use that type
| needs to be changed as well. This allows you to be creative
| and make any willy nilly changes you want because you are
| confident that ANY change will be caught by the type
| checker. This Speeds up creativity, while without it, you
| will be slowed down, and even afraid to make the breaking
| change.
|
| You are basically the stereotype I described. An old school
| python developer. Likely one who got used to programming
| without types and now hasn't utilized types extensively
| enough to see the benefit.
|
| >I don't think this is true. There's simply a communication
| breakdown where type-first developers don't see the
| benefits of disabling static checking to design interfaces,
| and interface-first developers don't see why they should
| put static checking ahead of interface iteration speed.
|
| This is true. You're it. You just don't know it. When I say
| these developers don't know I'm literally saying they think
| like you and believe the same things you believe BECAUSE
| they lack knowledge and have bad habits.
|
| The habit thing is what causes the warped knowledge. You're
| actually slowed down by types because you're not used to it
| as you spent years coding in python without types so it's
| ingrained for you to test and think without types. Adding
| additional types becomes a bit of a initial overhead for
| these types of people because their programming style is so
| entrenched.
|
| Once you get used to it and once you see that it's really
| just a slight additional effort, than you will get it. But
| it takes a bit of discipline and practice to get there.
| watwut wrote:
| > Static type checking (which is what I assume you mean by
| "typing") can also be a massive pain in the ass that stands
| in the way of incremental development,
|
| No they dont. There is nothing about types that would make
| incremental develpment harder. They keep having the same
| benefits when being incremental.
| MangoToupe wrote:
| > There is nothing about types that would make
| incremental develpment harder.
|
| Oh, please, this is either lack of imagination or lack of
| effort to think. You've never wanted to test a subset of
| a library halfway through a refactor?
| loglog wrote:
| Yes, type checkers are very good at tracking refactoring
| progress. If it turns out that you can proceed to test
| some subset, then congratulations, you found a new
| submodule.
| jampekka wrote:
| > There are developers who design apis by trying to figure
| out readable invocations. These developers discover, rather
| than design, type hierarchies and library interfaces.
|
| My hunch is that the people who see no downsides whatsoever
| in static typing are those who mostly just consume APIs.
| ninetyninenine wrote:
| There are downsides. But the upsides outweigh the
| downsides.
|
| I'm not a consumer of APIs. I've done game programming,
| robotics, embedded system development (with C++ and
| rust), (web development frontend with react/without
| react, with jquery, with angurar, with typescript, with
| js, zod) (web development backend with golang, haskell,
| nodejs typescript, and lots and lots of python with many
| of the most popular frameworks with flask + sqlalchemy,
| django, FastApi + pydantic, )
|
| I've done a lot. I can tell you. If you don't see how
| types outweigh untyped languages, you're a programmer
| with experience heavily weighed toward untyped
| programming. You don't have balanced experience to make a
| good judgement. Usually these people have a "data
| scientist" background. Data analyst or data scientist or
| machine learning engineers... etc. These guys start
| programing heavily in the python world WITHOUT types and
| they develop unbalanced opinions shaped by their initial
| styles of programming. If this describes you, then stop
| and think... I'm probably right.
| jampekka wrote:
| You are wrong. I learned programming mostly in C++ in the
| late 90's, and programmed in C, C++ and Java in
| professional settings for a decade or so, and still do
| from time to time.
| ninetyninenine wrote:
| Hm if you want or have time, can you give me a specific
| example of where no types are clearly superior to types?
| Maybe you can convince me but I still think your opinion
| is wrong despite your relevant experience.
| simonw wrote:
| It's claims like that which used to put me off embracing type
| hints!
|
| I'd been programming for 20+ years and I genuinely couldn't
| think of any situations where I'd had a non-trivial bug that
| I could have avoided if I'd had a type checker - claims like
| "reduce dev time by 50%" didn't feel credible to me, so I
| stuck with my previous development habits.
|
| Those habits involved a _lot_ of work performed interactively
| first - using the Python terminal, Jupyter notebooks, the
| Firefox /Chrome developer tools console. Maybe that's why I
| never felt like types were saving me any time (and in fact
| were slowing me down).
|
| Then I had my "they're just interactive documentation"
| realization and finally they started to click for me.
| IshKebab wrote:
| It depends on the project. If you're working always on one
| project and you have all the time in the world to learn it
| (or maybe you wrote it), then you can get away with dynamic
| types. It's still worse but possible.
|
| But if you aren't familiar with a project then dynamic
| typing makes it an order of magnitude harder to navigate
| and understand.
|
| I tried to contribute some features to a couple of big
| projects - VSCode and Gitlab. VSCode, very easy. I could
| follow the flow trivially, just click stuff to go to it
| etc. Where abstract interfaces are used it's a little more
| annoying but overall wasn't hard and I have contributed a
| few features & fixes.
|
| Gitlab, absolutely no chance. It's full of magically
| generated identifiers so even grepping doesn't work. If you
| find a method like `foo_bar` it's literally impossible to
| find where it is called without being familiar with the
| entire codebase (or asking someone who is) and therefore
| knowing that there's a text file somewhere called `foo.csv`
| that lists `bar` and the method name is generated from that
| (or whatever).
|
| In VSCode it was literally right-click->find all
| references.
|
| I have yet to succeed in modifying Gitlab at all.
|
| I did contribute some features to gitlab-runner, but again
| that is written in Go so it is possible.
|
| So in some cases those claims are not an exaggeration -
| static types take you from "I give up" to "not too hard".
| 1313ed01 wrote:
| > In VSCode it was literally right-click->find all
| references.
|
| Flip side of this is that I hate trying to read code
| written by teams relying heavily on such features, since
| typically zero time was spent on neatly organizing the
| code and naming things to make it actually readable (from
| top to bottom) or grep-able. Things are randomly spread
| out in tiny files over countless directories and it's a
| maze you stumble around just clicking identifiers to jump
| somewhere. Where something is rarely matter as the IDE
| will find it. I never develop any kind of mental image of
| that style of code and it completely rules out casually
| browsing the code using simpler tools.
| IshKebab wrote:
| That hasn't been my experience at all. I think maybe it
| _feels_ more like a maze because when you go-to-
| definition you often don 't actually check where you are
| in the filesystem, so you don't build a mental map of the
| repo as quickly as you do when you are _forced_ to
| manually search through all the files. But I wouldn 't
| say that is better.
|
| Kind of like how you don't learn an area when you always
| use satnav as quickly as you do when you manually
| navigate with paper maps. But do you want to go back to
| paper maps? I don't.
| JimDabell wrote:
| > It can actually roughly reduce dev time by 50% and increase
| safety by roughly 2x.
|
| Type annotations don't double productivity. What does
| "increase safety by 2x" even mean? What metric are you
| tracking there?
|
| In my experience, the main non-documentation benefit of type
| annotations is warning where the code is assuming a value
| where None might be present. Mixing up any other kind of
| types is an extremely rare scenario, but NoneType gets
| everywhere if you let it.
| ninetyninenine wrote:
| >Type annotations don't double productivity. What does
| "increase safety by 2x" even mean? What metric are you
| tracking there?
|
| My own anecdotal metric. Isn't that obvious? The initial
| post was an anecdotal opinion as well. I don't see a
| problem here.
|
| >In my experience, the main non-documentation benefit of
| type annotations is warning where the code is assuming a
| value where None might be present. Mixing up any other kind
| of types is an extremely rare scenario, but NoneType gets
| everywhere if you let it.
|
| It's not just None. Imagine some highly complex object with
| nested values and you have some function like this:
| def modify_direction(direction_object) -> ...
|
| wtf is direction object? Is it in Cartesian or is it in
| polar? Is in 2D or 3D? Most old school python devs
| literally have to find where modify_direction is called and
| they find this: def modify_data(data) ->
| ... ... modify_direction(data.quat)
|
| Ok then you have to find where modify data is called, and
| so on and so forth until you get to here:
| def combind_data(quat) -> ... def create_quat()
| -> quat
|
| And then boom you figure out what it does by actually
| reading all the complex quaternion math create_quat does.
|
| Absolutely insane. If I have a type, I can just look at the
| type to figure everything out... you can see how much
| faster it is.
|
| Oh and get this. Let's say there's someone who feels euler
| angles are better. So he changes create_quat to
| create_euler. He modifies all the places create_quat is
| used (which is about 40 places) and he misses 3 or 4 places
| where it's called.
|
| He then ships it to production. Boom The extra time
| debugging production when it crashes, ans also extra time
| tediously finding where create_quat was used. All of that
| could have been saved by a type checker.
|
| I'm a big python guy. But I'm also big into haskell. So I
| know both the typing worlds and the untyped worlds really
| well. Most people who complain like you literally have
| mostly come from a python background where typing isn't
| used much. Maybe you used types occasionally but not in a
| big way.
|
| If you used both untyped languages and typed languages
| extensively you will know that types are intrinsically
| better. It's not even a contest. Anyone who still debates
| this stuff just lacks experience.
| JimDabell wrote:
| > My own anecdotal metric. Isn't that obvious? The
| initial post was an anecdotal opinion as well. I don't
| see a problem here.
|
| WTF is "an anecdotal metric"!? That just sounds like an
| evasive way to say _"I want to make up numbers I can't
| justify"_.
|
| > wtf is direction object? Is it in Cartesian or is it in
| polar? Is in 2D or 3D?
|
| This seems very domain-specific.
|
| > Most people who complain like you literally have mostly
| come from a python background where typing isn't used
| much. Maybe you used types occasionally but not in a big
| way.
|
| > If you used both untyped languages and typed languages
| extensively you will know that types are intrinsically
| better. It's not even a contest. Anyone who still debates
| this stuff just lacks experience.
|
| I've got many years of experience with static typed
| languages over a 25 year career. Just because somebody
| disagrees with you, it doesn't mean they are a clueless
| junior.
| IshKebab wrote:
| > WTF is "an anecdotal metric"
|
| It's a metric (how much more productive he is), and
| anecdotal (base only on his experience). Pretty obvious I
| would have thought.
|
| > This seems very domain-specific.
|
| It was an example from one domain but all domains have
| types of things. Are you really trying to say that only
| 3D games _specifically_ would benefit from static types?
|
| > Just because somebody disagrees with you, it doesn't
| mean they are a clueless junior.
|
| Clueless senior then I guess? Honestly I don't know how
| you can have this much experience and still not come to
| the obvious conclusion. Perhaps you only write small
| scripts or solo projects where it's more feasible to get
| away without static types?
|
| What would you say to someone who said "I have 25 years
| of experience reading books with punctuation and I think
| that punctuation is a waste of time. Just because you
| disagree with me doesn't mean I'm clueless."?
| ninetyninenine wrote:
| >WTF is "an anecdotal metric"!? That just sounds like an
| evasive way to say "I want to make up numbers I can't
| justify".
|
| What I have to have scientific papers for every fucking
| opinion I have? The initial Parent post was an anecdotal
| opinion. Your post is an opinion. I can't have opinions
| here without citing a scientific paper that's 20 pages
| long and no is going to read but just blindly trust
| because it's "science"? Come on. What I'm saying is self
| evident to people who know. There are thousands of things
| like this in the world where people just know even though
| statistical proof hasn't been measured or established.
| For example eating horse shit everyday probably isn't
| healthy even though it there isn't SCIENCE that proves
| this action as unhealthy directly. Type checking is just
| one of those things.
|
| OBVIOUSLY I think development is overall much better,
| much faster and much safer with types. I can't prove it
| with metrics, but I'm confident my "anecdotal" metrics
| with I prefaced with "roughly" are "roughly" ballpark
| trueish.
|
| >This seems very domain-specific.
|
| Domain specific? Basic orientation with quaternions and
| euler angles is specific to reality. Orientation and
| rotations exist in reality and there are thousands and
| thousands of domains that use it.
|
| Also the example itself is generic. Replace euler angles
| and quats with vectors and polar coordinates. Or cats and
| dogs. Same shit.
|
| >I've got many years of experience with static typed
| languages over a 25 year career. Just because somebody
| disagrees with you, it doesn't mean they are a clueless
| junior.
|
| The amount of years of experience is irrelevant. I know
| tons of developers with only 5 years of experience who
| are better than me and tons of developers with 25+ who
| are horrible.
|
| I got 25 years as well. If someone disagrees with me (on
| this specific topic), it absolutely doesn't mean they are
| a junior. It means they lack knowledge and experience.
| This is a fact. It's not an insult. It just means for a
| specific thing they don't have experience or knowledge
| which is typical. I'm sure there's tons of things where
| you could have more experience. Just not this topic.
|
| If you have experience with static languages it likely
| isn't that extensive. You're likely more of a old school
| python guy who spend a ton of time programming without
| types.
| JimDabell wrote:
| > What I have to have scientific papers for every fucking
| opinion I have?
|
| No, but if you're going to say things like "increase
| safety by roughly 2x" then if you can't even identify the
| _unit_ then you are misleading people.
|
| It's _absolutely fine_ to have an opinion. It's _not_
| fine to make numbers up.
|
| > I'm confident my "anecdotal" metrics with I prefaced
| with "roughly" are "roughly" ballpark trueish.
|
| Okay, so if it's 1.5x, 2.0x, or 2.5x... again, what
| metric? What unit are we dealing with?
|
| You're claiming that it's "in the ballpark", but _what_
| is "in the ballpark"? The problem is not one of accuracy,
| the problem is that it's made up.
|
| > If someone disagrees with me (on this specific topic),
| it absolutely doesn't mean they are a junior. It means
| they lack knowledge and experience. This is a fact.
|
| It's not a fact, it's ridiculous. You genuinely believe
| that if somebody disagrees with you, it's a _fact_ that
| they lack knowledge and experience? It's not even
| remotely possible for somebody to have an informed
| difference of opinion with you?
| ninetyninenine wrote:
| >No, but if you're going to say things like "increase
| safety by roughly 2x" then if you can't even identify the
| unit then you are misleading people.
|
| So when I talk about multipliers I have to have a unit?
| What is the unit of safety? I can't say something like 2x
| more safe? I just have to say more safe? What if I want
| to emphasize that it can DOUBLE safety?
|
| Basically with your insane logic people can't talk about
| productivity or safety or multipliers at the same time
| because none of these concepts have units.
|
| Look I told YOU it's anecdotal, EVERYONE can read it.
| You're no longer "deceived" and no one else is.
|
| >Okay, so if it's 1.5x, 2.0x, or 2.5x... again, what
| metric? What unit are we dealing with?
|
| If you don't have the capacity to understand what I'm
| talking about without me specifying a unit than I'll make
| one up:
|
| I call it safety units. The amount of errors you catch in
| production. That's my unit: 1 caught error in prod in a
| year. For Untyped languages let's say you catch about 20
| errors a year. With types that goes down to 10.
|
| >It's not a fact, it's ridiculous. You genuinely believe
| that if somebody disagrees with you, it's a fact that
| they lack knowledge and experience? It's not even
| remotely possible for somebody to have an informed
| difference of opinion with you?
|
| What? and you think all opinions are equal and everyone
| has the freedom to have any opinion they want and no one
| can be right or wrong because everything is just an
| opinion? Do all opinions need to be fully respected even
| though it's insane?
|
| Like my example, if you have the opinion that eating
| horse shit is healthy, I'm going to make a judgement call
| that your opinion is WRONG. Lack of Typing is one of
| these "opinions"
| JimDabell wrote:
| Take a step back and look at what you are saying:
|
| > If someone disagrees with me (on this specific topic),
| it absolutely doesn't mean they are a junior. It means
| they lack knowledge and experience. This is a fact.
|
| You think it's impossible for anybody to have an informed
| opinion that disagrees with yours. You literally think
| yours is the only possible valid opinion. If that doesn't
| set off big warning bells in your head, you are in dire
| need of a change in attitude.
|
| This conversation is not productive, let's end it.
| ninetyninenine wrote:
| >You think it's impossible for anybody to have an
| informed opinion that disagrees with yours. You literally
| think yours is the only possible valid opinion. If that
| doesn't set off big warning bells in your head, you are
| in dire need of a change in attitude.
|
| I mean do you think we should have a fair and balanced
| discussion about the merits of child molestation and
| rape? We should respect other people's opinion and not
| tell them they are wrong if there opinion differs? That's
| what I think of your opinion. I think your opinion is
| utterly wrong, and I do think my opinion is the valid
| opinion.
|
| Now that doesn't mean I disrespect your opinion. That
| doesn't mean your not allowed to have a different
| opinion. It just means I tell you straight up, you're
| wrong and you lack experience. You're free to disagree
| with that and tell me the exact same thing. I'm just
| blunt, and I welcome you to be just as blunt to me. Which
| you have.
|
| The thing I don't like about you is that you turned it
| into discussion about opinions and the nature of holding
| opinions. Dude. Just talk about the topic. If you think
| I'm wrong. Tell me straight up. Talk about why I'm wrong.
| Don't talk about my character and in what manner I should
| formulate opinions and what I think are facts.
|
| >This conversation is not productive, let's end it.
|
| I agree let's end it. But let's be utterly clear. YOU
| chose to end it with your actions by shifting the
| conversation into saying stuff like "you literally think
| yours is the only possible opinion." Bro. All you need to
| do is state why you think my opinion is garbage and prove
| it wrong. That's the direction of the conversation, you
| ended it by shifting it to a debate on my character.
| jampekka wrote:
| > If you used both untyped languages and typed languages
| extensively you will know that types are intrinsically
| better. It's not even a contest. Anyone who still debates
| this stuff just lacks experience.
|
| Or have enough experience to have lived e.g. the J2EE and
| C++ template hells and see where this is going.
| ninetyninenine wrote:
| typing can get extreme to the point where it becomes
| proof based typing. So I know what you mean here. I've
| lived through it and done it.
|
| In general types outweigh no types EVEN with the above.
| akdor1154 wrote:
| > Type annotations don't double productivity.
|
| Obviously this post is still firmly in made up statistics
| land, but i agree with OP, in some cases they absolutely
| do.
|
| New code written by yourself? No, probably not. But
| refactoring a hairy old enterprise codebase? Absolutely a
| 2x, 3x multiplier to productivity / time-to-correctness
| there.
| lelanthran wrote:
| > The thing that finally got me on board with optional type
| hints in Python was realizing that they're mainly valuable as
| documentation.
|
| > But it's really valuable documentation! Knowing what types
| are expected and returned just by looking at a function
| signature is super useful.
|
| So ... you didn't have this realisation prior to using Python
| type hints? Not from any other language you used prior to
| Python?
| simonw wrote:
| I didn't. I've been mainly a Python, PHP and JavaScript
| programmer for ~25 years and my experience with typed
| languages was mostly pre-type-inference Java which felt
| _wildly_ less productive than my main languages.
| chpatrick wrote:
| That was more because of Java than static typing.
| lelanthran wrote:
| > I didn't. I've been mainly a Python, PHP and JavaScript
| programmer for ~25 years
|
| Maybe its time you expanded your horizons, then. Try a few
| statically typed languages.
|
| Even plain C gives you a level of confidence in deployed
| code that you will _not_ get in Python, PHP or Javascript.
| sevensor wrote:
| Maybe if your C has aggressive test coverage and you're
| using Valgrind religiously and always checking errno when
| you're supposed to and you're checking the return value
| of everything. Otherwise lol. C as it's written by
| middling teams is a soup of macros, three-star variables,
| and questionable data structure implementations, where
| everybody fiddles with everybody else's data. I'll take
| good C over bad Python, but good C is rare.
| lelanthran wrote:
| > C as it's written by middling teams is a soup of
| macros, three-star variables, and questionable data
| structure implementations, where everybody fiddles with
| everybody else's data. I'll take good C over bad Python,
| but good C is rare.
|
| Ironically, the worst production C written in 2025 is
| almost guaranteed to be better than the average
| production Python, Javascript, etc.
|
| The only people really _choosing_ C in 2025 are those
| with a ton of experience under their belt, who are
| comfortable with the language and its footguns due to
| decades of experience.
|
| IOW, those people with little experience are _not_
| choosing C, and those that _do_ choose it have already,
| over decades, internalised patterns to mitigate many of
| the problems.
|
| At the end of the day, in 2025, I'd still rather maintain
| a system written in a statically typed language than a
| system written in a dynamically typed language.
| ModernMech wrote:
| > The only people really choosing C in 2025 are those
| with a ton of experience under their belt, who are
| comfortable with the language and its footguns due to
| decades of experience.
|
| Experienced users of C can't be the only people who use
| it if the language is going to thrive. It's very bad for
| a language when the only ones who speak it are those who
| speak it well. The only way you get good C programmers is
| by cultivating bad C programmers, you can't have one
| without the other. If you cut off the bad programmers (by
| shunning or just not appealing to them, or loading your
| language with too many beginner footguns), there's no
| pipeline to creating experts, and the language dies when
| the experts do.
|
| The people who come along to work on their legacy systems
| are better described as archaeologists than programmers.
| COBOL of course is the typical example, there's no real
| COBOL programming community to speak of, just COBOL
| archeologists who maintain those systems until they too
| shall die and it becomes someone else's problem, like the
| old Knight at the end of Indiana Jones.
| lelanthran wrote:
| > Experienced users of C can't be the only people who use
| it if the language is going to thrive.
|
| I don't think it's going to thrive. It's going to die.
| Slowly, via attrition, but there you go.
| simonw wrote:
| I find automated tests give me plenty of confidence in
| the Python code I deploy. I'd rather deploy a codebase
| with comprehensive tests and no types over one with types
| and no tests.
|
| I've been dabbling with Go for a few projects and found
| the type system for that to be pleasant and non-
| frustrating.
| lelanthran wrote:
| > I'd rather deploy a codebase with comprehensive tests
| and no types over one with types and no tests.
|
| With Python, PHP and Javascript, you only option _is_
| "comprehensive tests and no types".
|
| With statically typed languages, you have options other
| than "types with no tests". For example, static typing
| _with_ tests.
|
| Don't get me wrong; I _like_ dynamically typed languages.
| I like Lisp in particular. But, TBH, in statically typed
| languages I find myself producing tests that test the
| business logic, while in Python I find myself producing
| tests that ensure all callers in a runtime call-chain
| have the correct type.
|
| BTW: You did well to choose Go for dipping your toes into
| statically typed languages - the testing comes builtin
| with the tooling.
| __MatrixMan__ wrote:
| Type hints as documentation are a gateway drug to type hints
| for bug finding. Keep at it :)
| Syntaf wrote:
| This resonates with me this so much. I feel like half the
| comments in this thread are missing the value typing, but maybe
| they've never had the misfortune of working with hundreds of
| other developers on a project with no defined contracts on
| aggregates / value objects outside of code comments and wishful
| thinking.
|
| I've worked on large python codebases for large companies for
| the last ~6 years of my career; types have been the single
| biggest boon to developer productivity and error reduction on
| these codebases.
|
| Just having to THINK about types eliminates so many
| opportunities for errors, and if your type is too complex to
| express it's _usually_ a code smell; most often these
| situations can be re-written in a more sane albeit slightly
| verbose fashion, rather than using the more "custom" typing
| features.
|
| No one gets points for writing "magical" code in large
| organizations, and typing makes sure of this. There's
| absolutely nothing wrong with writing "boring" python.
|
| Could we have accomplished this by simply having used a
| different language from the beginning? Absolutely, but often
| times that's not a option for a company with a mature stack.
|
| TL;DR -- Typing in python is an exception tool to scale your
| engineering organization on a code-base.
| tecoholic wrote:
| I love typing in Python. I learnt programming with C++ and OOPs.
| It was freeing when I took up Python to note care about types,
| but I have come to enjoy types as I got older.
|
| But, boy have we gone overboard with this now? The modern
| libraries seem to be creating types for the sake of them. I am
| drowning in nested types that seem to never reach native types.
| The pain is code examples of the libraries don't even show them.
|
| Like copy paste an OpenAI example and see if LSP is happy for
| example. Now I have gotten in this situation where I am mentally
| avoiding type errors of some libraries and edging into wishing
| Pydantic et al never happened.
| AlienRobot wrote:
| My love for python was critically hurt when I learned about
| typing.TYPE_CHECKING.
|
| For those unaware, due to the dynamic nature of Python, you
| declare a variable type like this foo: Type
|
| This might look like Typescript, but it isn't because "Type" is
| actually an object. In python classes and functions are first-
| class objects that you can pass around and assign to variables.
|
| The obvious problem of this is that you can only use as a type
| an object that in "normal python" would be available in the
| scope of that line, which means that you can't do this:
| def foo() -> Bar: return Bar()
| class Bar: pass
|
| Because "Bar" is defined AFTER foo() it isn't in the scope when
| foo() is declared. To get around this you use this weird
| string-like syntax: def foo() -> "Bar":
| return Bar()
|
| This already looks ugly enough that should make Pythonists ask
| "Python... what are you doing?" but it gets worse.
|
| If you have a cyclic reference between two files, something
| that works out of the box in statically typed languages like
| Java, and that works in Python when you aren't using type hints
| because every object is the same "type" until it quacks like a
| duck, that isn't going to work if you try to use type hints in
| python because you're going to end up with a cyclic import.
| More specifically, you don't need cyclic imports in Python
| normally because you don't need the types, but you HAVE to
| import the types to add type hints, which introduces cyclic
| imports JUST to add type hints. To get around this, the
| solution is to use this monstrosity: if
| typing.TYPE_CHECKING: import Foo from foo
|
| And that's code that only "runs" when the static type check is
| statically checking the types.
|
| Nobody wants Python 4 but this was such an incredibly
| convoluted way to add this feature, specially when you consider
| that it means every module now "over-imports" just to add type
| hints that they previously didn't have to.
|
| Every time I see it makes me think that if type checks are so
| important maybe we shouldn't be programming Python to begin
| with.
| dandiep wrote:
| Isn't this solved in 3.14/PEP-649?
| analog31 wrote:
| At last, Pi-thon.
| aw1621107 wrote:
| I want to say it (or something similar at least) was
| originally addressed by from __future__ import annotations
| back in Python 3.7/3.8 or thereabouts? I definitely
| remember having to use stringified types a while back but I
| haven't needed to for quite a while now.
| sgarland wrote:
| Yes, annotations allows you to use the declared types as
| they are, no strings.
| FreakLegion wrote:
| It turns them into thunks (formerly strings)
| automatically, an important detail if you're inspecting
| annotations at run time because the performance hit of
| resolving the actual type can be significant.
| sgarland wrote:
| TIL, thanks! It looks like 3.14 is also changing it so
| that all evaluations are lazy.
| zahlman wrote:
| > that isn't going to work if you try to use type hints in
| python because you're going to end up with a cyclic import.
| More specifically, you don't need cyclic imports in Python
| normally because you don't need the types, but you HAVE to
| import the types to add type hints, which introduces cyclic
| imports JUST to add type hints.
|
| Yes, `typing.TYPE_CHECKING` is there so that you can
| conditionally avoid imports that are only needed for type
| annotations. And yes, importing modules can have side effects
| and performance implications. And yes, I agree it's ugly as
| sin.
|
| But Python does in fact allow for cyclic imports -- as long
| as you're importing the modules themselves, rather than
| importing names `from` those modules. (By the way, the syntax
| is the other way around: `from ... import ...`.)
|
| https://stackoverflow.com/questions/744373/
| ninetyninenine wrote:
| You're actually missing the benefit of this. It's actually a
| feature.
|
| With python, because types are part of python itself, they
| can thus be programmable. You can create a function that
| takes in a typehint and returns a new typehint. This is legal
| python. For example below I create a function that
| dynamically returns a type that restricts a Dictionary to
| have a specific key and value. from typing
| import TypedDict def make_typed_dict(name: str,
| required_key: str, value_type: type): return
| TypedDict(name, {required_key: value_type, id: int})
| # Example UserDict = make_typed_dict("UserDict",
| "username", str) def foo(data: UserDict):
| print(data["username"])
|
| With this power in theory you can create programs where types
| essentially can "prove" your program correct, and in theory
| eliminate unit tests. Languages like idris specialize in
| this. But it's not just rare/specialized languages that do
| this. Typescript, believe it or not, has programmable types
| that are so powerful that writing functions that return types
| like the one above are Actually VERY common place. I was a
| bit late to the game to typescript but I was shocked to see
| that it was taking cutting edge stuff from the typing world
| and making it popular among users.
|
| In practice, using types to prove programs to be valid in
| place of testing is actually a bit too tedious compared with
| tests so people don't go overboard with it. It is a much more
| safer route then testing, but much harder. Additionally as of
| now, the thing with python is that it really depends on how
| powerful the typechecker is on whether or not it can enforce
| and execute type level functions. It's certainly possible,
| it's just nobody has done it yet.
|
| I'd go further than this actually. Python is actually a
| potentially more powerfully typed language than TS. In TS,
| types are basically another language tacked onto javascript.
| Both languages are totally different and the typing language
| is very very limited.
|
| The thing with python is that the types and the language ARE
| the SAME thing. They live in the same universe. You
| complained about this, but there's a lot of power in that
| because basically types become turing complete and you can
| create a type that does anything including proving your whole
| program correct.
|
| Like I said that power depends on the typechecker. Someone
| needs to create a typechecker that can recognize type level
| functions and so far it hasn't happened yet. But if you want
| to play with a language that does this, I believe that
| language is Idris.
| quietbritishjim wrote:
| That's not a benefit. That's a monstrosity.
|
| And, as you heavily imply in your post, type checkers won't
| be able to cope with it, eliminating one if the main
| benefits of type hints. Neither will IDEs / language
| servers, eliminating the other main benefit.
| ninetyninenine wrote:
| >And, as you heavily imply in your post, type checkers
| won't be able to cope with it
|
| I implied no such thing. literally said there's a
| language that already does this. Typescript. IDE's cope
| with it just fine.
|
| >That's not a benefit. That's a monstrosity.
|
| So typescript is a monstrosity? Is that why most of the
| world who uses JS in node or the frontend has moved to
| TS? Think about it.
| baobun wrote:
| I don't believe Typescript (nor Idris) type systems work
| like you describe, though? Types aren't programmable with
| code like that (in the same universe, as you say) and TS
| is structurally typed, with type erasure (ie types are
| not available at runtime).
|
| I am not that deeply familiar with Python typings
| development but it sounds fundamentally different to the
| languages you compare to.
| ninetyninenine wrote:
| Typescript types (and Idris) are Turing complete. You can
| actually get typescript types to run doom.
|
| https://www.youtube.com/watch?v=0mCsluv5FXA&t
|
| Idris on the other hand is SPECIFICALLY designed so types
| and the program live in the same language. See the
| documentation intro: https://www.idris-
| lang.org/pages/example.html
|
| THe powerful thing about these languages is that they can
| prove your program correct. For testing you can never
| verify your program to be correct.
|
| Testing is a statistical sampling technique. To verify a
| program as correct via tests you have to test every
| possible input and output combination of your program,
| which is impractical. So instead people write tests for a
| subset of the possibilities which ONLY verifies the
| program as correct for that subset. Think about it. If
| you have a function: def add(x: int, y:
| int) -> int
|
| How would you verify this program is 100% correct? You
| have to test every possible combination of x, y and
| add(x, y). But instead you test like 3 or 4 possibilities
| in your unit tests and this helps with the overall safety
| of the program because of statistical sampling. If a
| small sample of the logic is correct, it says something
| about the entire population of the logic..
|
| Types on the other hand prove your program correct.
| def add(x: int, y: int) -> int: return x + y
|
| If the above is type checked, your program is proven
| correct for ALL possible types. If those types are made
| more advanced via being programmable, then it becomes
| possible for type checking to prove your ENTIRE program
| correct.
|
| Imagine: def add<A: addable < 4, B:
| addable < 4>(x: A, y: B) -> A + B: return x
| + y
|
| With a type checker that can analyze the above you can
| create a add function that at most can take an int that
| is < 4 and return an int that is < 8. Thereby verifying
| even more correctness of your addition function.
|
| Python on the other hand doesn't really have type
| checking. It has type hints. Those type hints can de
| defined in the same language space as python. So a type
| checker must read python to a limited extent in order to
| get the types. Python at the same time can also read
| those same types. It's just that python doesn't do any
| type checking with the types while the type checker
| doesn't do anything with the python code other than
| typecheck it.
|
| Right now though, for most typecheckers, if you create a
| function in python that returns a typehint, the
| typechecker is not powerful enough to execute that
| function to find the final type. But this can certainly
| be done if there was a will because Idris has already
| done this.
| bgwalter wrote:
| The syntax is a monstrosity. You can also extract a
| proven OCaml program from Coq and Coq has a beautiful
| syntax.
|
| If you insist on the same language for specifying types,
| some Lisp variants do that with a _much_ nicer syntax.
|
| Python people have been indoctrinated since ctypes that a
| monstrous type syntax is normal and they reject anything
| else. In fact Python type hints are basically stuck on
| the ctypes level syntax wise.
| ninetyninenine wrote:
| That's just a sugar thing. Yeah it can get a bit more
| verbose.
| dashdotme wrote:
| Are there really productive projects which rely on types as
| a proofing system? I've always thought it added too much
| complexity to the code, but I'd love to see it working well
| somewhere. I love the idea of correctness by design.
| ninetyninenine wrote:
| No too my knowledge nothing is strict about a proofing
| system because like I said it becomes hard to do. It
| could be useful for ultra safe software but for most
| cases the complexity isn't worth it.
|
| But that doesn't mean it's not useful to have this
| capability as part of your typesystem. It just doesn't
| need to be fully utilized.
|
| You don't need to program a type that proves everything
| correct. You can program and make sure aspects of the
| program are MORE correct than just plain old types.
| typescript is a language that does this and it is very
| common to find types in typescript that are more "proofy"
| than regular types in other languages.
|
| See here: https://www.hacklewayne.com/dependent-types-in-
| typescript-se...
|
| Typescript does this. Above there's a type that's only a
| couple of lines long that proves a string reversal
| function reverses a string. I think even going that deep
| is overkill but you can define things like Objects that
| must contain a key of a specific string where the value
| is either a string or a number. And then you can create a
| function that dynamically specifies the value of the key
| in TS.
|
| I think TS is a good example of a language that
| practically uses proof based types. The syntax is
| terrible enough that it prevents people from going
| overboard with it and the result is the most practical
| application of proof based typing that I seen. What
| typescript tells us that proof based typing need only be
| sprinkled throughout your code, it shouldn't take it all
| over.
| AlienRobot wrote:
| That's horrible. Nobody needs imperative metaprogramming
| for type hints. In fact, it would be absolute insanity for
| a typechecker to check this because it would mean opening a
| file in VS code = executing arbitrary python code. What
| stops me from deleting $HOME inside make_typed_dict?
|
| TypeScript solves this with its own syntax that never gets
| executed by an interpreter because types are striped when
| TS is compiled to JS.
| ninetyninenine wrote:
| >VS code = executing arbitrary python code. What stops me
| from deleting $HOME inside make_typed_dict?
|
| Easy make IO calls illegal in the type checker. The type
| checker of course needs to execute code in a sandbox. It
| won't be the full python language. Idris ALREADY does
| this.
| meander_water wrote:
| There's actually another issue with ForwardRefs. They don't
| work in the REPL. So this will work when run as a module:
| def foo() -> "Bar": return Bar()
|
| But will throw an error if copy pasted into a REPL.
|
| However, all of these issues should be fixed in 3.14 with
| PEP649 and PEP749:
|
| > At compile time, if the definition of an object includes
| annotations, the Python compiler will write the expressions
| computing the annotations into its own function. When run,
| the function will return the annotations dict. The Python
| compiler then stores a reference to this function in
| __annotate__ on the object.
|
| > This mechanism delays the evaluation of annotations
| expressions until the annotations are examined, which solves
| many circular reference problems.
| pcwelder wrote:
| It doesn't throw error in the REPL though. Surely you meant
| to share some other example?
| meander_water wrote:
| Please ignore my first assertion that the behavior between
| REPL and module is different.
|
| This would have been the case if the semantics of the
| original PEP649 spec had been implemented. But instead,
| PEP749 ensures that it is not [0]. My bad.
|
| [0] https://peps.python.org/pep-0749/#behavior-of-the-repl
| Too wrote:
| This is trivial to solve by simply not having circular
| imports. Place the types in one file and the usage of it in
| others.
|
| This has many benefits, like forcing you to think about the
| dependencies and layers of your architecture. Here is a good
| read about why, from F# that has the same limitation
| https://fsharpforfunandprofit.com/posts/cyclic-dependencies/
|
| As others already mentioned, importing __annotations__ also
| works.
| _flux wrote:
| If the type is a class with methods, then this method
| doesn't work, though adding intermediate interface classes
| (possibly with Generic types) might help in most cases.
| Python static type system isn't quite the same level as F#.
|
| > Well, these complaints are unfounded.
|
| "You're holding it wrong." I've also coded quite a bit of
| OCaml and it had the same limitation (which is where F#
| picked it up in the first place), and while the issue can
| be worked around, it still seemed to creep up at times.
| Rust, also with some virtual OCaml ancestry, went
| completely the opposite way.
|
| My view is that while in principle it's a nice property
| that you can read and and understand a piece of code by
| starting from the top and going to the bottom (and a REPL
| is going to do exactly that), in practice it's not the
| ultimate nice property to uphold.
| Too wrote:
| > If the type is a class with methods, then this method
| doesn't work
|
| Use typing.Self
| _flux wrote:
| I meant if you have two classes that need to refer to
| each other. But good pointer anyway, I hadn't noticed it,
| thanks!
| alfons_foobar wrote:
| I ran into some code recently where this pattern caused
| me so much headache - class A has an attribute which is
| an instance of class B, and class B has a "parent"
| attribute (which points to the instance of class A that
| class B is an attribute of): class Foo:
| def __init__(self, bar): self.bar = bar
| class Bar: def __init__(self, foo):
| self.foo = foo
|
| Obviously both called into each other to do $THINGS...
| Pure madness.
|
| So my suggestion: Try not to have interdependent classes
| :D
| _flux wrote:
| Well, at times having a parent pointer is rather useful!
| E.g. a callback registration will be able to unregister
| itself from everywhere where it has been registered to,
| upon request. (One would want to use weak references in
| this case.)
| alfons_foobar wrote:
| Agreed that this "hack" is very ugly!
|
| On the other hand, I tend to take it as a hint that I should
| look at my module structure, and see if I can avoid the
| cyclic import (even if before adding type hints there was no
| error, there still already was a "semantic dependency"...)
| JackSlateur wrote:
| from __future__ import annotations
| actinium226 wrote:
| > If you have a cyclic reference between two files,
|
| Don't have cyclic references between two files.
|
| It makes testing very difficult, because in order to test
| something in one file, you need to import the other one, even
| though it has nothing to do with the test.
|
| It makes the code more difficult to read, because you're
| importing these two files in places where you only need one
| of them, and it's not immediately clear why you're importing
| the second one. And it's not very satisfying to learn that
| you you're importing the second one not because you "need" it
| but because the circular import forces you to do so.
|
| Every single time you have cyclic references, what you really
| have are two pieces of code that rely on a third piece of
| code, so take that third piece, separate it out, and have the
| first two pieces of code depend on the third piece.
|
| Now things can be tested, imports can be made sanely, and
| life is much better.
| AlienRobot wrote:
| Using the typical "Rust-killer" example: if you have a
| linked list where the List in list.py returns a Node type
| and Node in node.py takes a List in its constructor, you
| already have a cyclic reference.
| pton_xd wrote:
| > But, boy have we gone overboard with this now? The modern
| libraries seem to be creating types for the sake of them. I am
| drowning in nested types that seem to never reach native types.
|
| Thought you were talking about TypeScript for a moment there.
| afiori wrote:
| Except that typescript structural typing and features make it
| much easier to swim.
|
| Also python is far less aggressive with lint warnings so it
| is much easier to make mistakes
| ninetyninenine wrote:
| I learned C++ before learning python as well and python felt
| like a breath of fresh air.
|
| At first I thought it was because of the lack of types. But in
| actuality the lack of types was a detriment for python. It was
| an illusion. The reason why python felt so much better was
| because it had clear error messages and a clear path to find
| errors and bugs.
|
| In C++ memory leaks and seg faults are always hidden from view
| so EVEN though C++ is statically typed, it's actually
| practically less safe then python and much more harder to
| debug.
|
| The whole python and ruby thing exploding in popularity back in
| the day was a trick. It was an illusion. We didn't like it more
| because of the lack of typing. These languages were embraced
| because they weren't C or C++.
|
| It took a decade for people to realize this with type hints and
| typescript. This was a huge technical debate and now all those
| people were against types are proven utterly wrong.
| raincole wrote:
| > It was an illusion. We didn't like it more because of the
| lack of typing. These languages were embraced because they
| weren't C or C++.
|
| It's an illusion only you once had. Java (a language that is
| not C or C++) got mainstream way before Python.
| Too wrote:
| Java on the other hand had the most verbose syntax known to
| man, especially those early versions of it. Nowadays it's
| getting more tolerable.
| afiori wrote:
| I don't understand, the parent says that not being C/C++
| was a strong point and you give an counter example of a
| successful language that is not C/C++
| _zoltan_ wrote:
| modern C++ is great, to be honest.
| biimugan wrote:
| In addition to what others have mentioned, it also just makes it
| easier to come back later to a code base and make changes,
| especially refactoring. In many cases you don't even really have
| to add many type hints to get benefits from it, since many
| popular libraries are more-or-less already well-typed. It can
| also substitute for many kinds of unit tests that you would end
| up writing even 5 years ago. If you're an infrastructure engineer
| or data scientist that's usually just writing a lot of glue code,
| then it greatly helps speed up your output (I've found)
| ashu1461 wrote:
| This
|
| Without typing it is literally 100x harder to refactor your
| code, types are like a contract which if are maintained after
| the refactor gives you confidence. Over time it leads to faster
| development
| frou_dh wrote:
| Because you almost always have a specific type in mind for that
| function parameter, so you might as well just write it down.
| iandanforth wrote:
| I hate typing in Python. I spend a good chunk of my day fighting
| the type checker and adding meaningless assertions, casts, and
| new types all to satisfy what feels like an obsessive compulsive
| nitpicker. "Type partially unknown" haunts my dreams.
|
| Duck typing is one of the best things about Python. It provides a
| developer experience second to none. Need to iterate over a
| collection of things? Great! Just do it! As long as it is an
| iterable (defined by methods, not by type) you can use it
| anywhere you want to. Want to create a data object that maps any
| hashable type to just about anything else? Dict has you covered!
| Put anything you want in there and don't worry about it.
|
| If we ended up with a largely bug free production system then it
| might be worth it, but, just like other truly strongly typed
| languages, that doesn't happen, so I've sacrificed my developer
| experience for an unfulfilled promise.
|
| If I wanted to use a strongly typed language I would, I don't,
| and the creeping infection of type enforcement into production
| codebases makes it hard to use the language I love
| professionally.
| maleldil wrote:
| > Need to iterate over a collection of things?
|
| Iterable[T]
|
| > Want to create a data object that maps any hashable type to
| just about anything else?
|
| Mapping[T, U]
| dwattttt wrote:
| Beyond the advantage that a type-checker/linter can tell if
| you're doing the right thing when writing those functions, it
| lets an IDE infer what type you're iterating over, in order
| to provide more support/completion/hinting/checks (without
| recursively analyzing arbitrary code, so: 'instantly' vs
| 'maybe not ever).
| jgb1984 wrote:
| Couldn't agree more! I've been using Python for almost 20
| years, my whole career is built on it, and I never missed
| typing. Code with type hints is so verbose and unpythonic,
| making it much harder to read. Quite an annoying evolution.
| pansa2 wrote:
| As the article says, type hints represent a fundamental
| change in the way Python is written. Most developers seem to
| prefer this new approach (especially those who'd rather be
| writing Java, but are stuck using Python because of its
| libraries).
|
| However it is indeed annoying for those of us who liked
| writing Python 2.x-style dynamically-typed executable
| pseudocode. The community is now actively opposed to writing
| that style of code.
|
| I don't know if there's another language community that's
| more accepting of Python 2.x-style code? Maybe Ruby, or Lua?
| jgb1984 wrote:
| There is nothing python-2 about my python-3 dynamically
| typed code. I'm pretty confident a majority of new python
| code is still being written without type hints.
|
| Hell, python type annotations were only introduced in
| python 3.5, the language was 24 years old by then! So no,
| the way I write python is the way it was meant to be, type
| hints are the gadget that was bolted on when the language
| was already fully matured, it's pretty ridiculous painting
| code without type hints as unpythonic, that's the world
| upside down.
|
| If I wanted to write very verbose typed code I would switch
| to Go or Rust. My python stays nimble, clean and extremely
| readable, without type hints.
| pansa2 wrote:
| I agree completely! To be clear, I don't consider
| describing code as "Python 2-style" to be a bad thing.
| It's how I describe my own Python code!
|
| Overall, I have found very few Python 3 features are
| worth adopting (one notable exception is f-strings). IMO
| most of them don't pull their weight, and many are just
| badly designed.
| jmward01 wrote:
| Type hints in python are just that, hints. Use them to help with
| clarity but enforcing them and requiring them everywhere
| generally leads to the worst of all worlds. Lots of boilerplate,
| less readable code and throwing away many of the features that
| make python powerful. Use the best language for the job and use
| the right language features at the right time. I see too many
| black or white arguments in the developer community, there is a
| middle ground and the best code is almost always written there.
| IshKebab wrote:
| > Use the best language for the job
|
| Sometimes you don't have a choice though, and other people have
| picked Python despite it rarely being the best language for any
| job.
|
| In that case it's nice to be able to use static type hints and
| benefit from improved readability, productivity and
| reliability.
| zahlman wrote:
| It's the other way around, IMO: people who think the language
| should at least have type hints are now more willing to use it,
| now that there's better tooling for checking those hints.
| pansa2 wrote:
| Yes. And people who preferred the language (and its culture)
| before the "fundamental change" of adding type hints are now
| less willing to use it.
| zahlman wrote:
| Probably some people are. I just mostly don't think about the
| annotations.
| k3vinw wrote:
| I really think that Rust has one of the best designed/inspired
| type systems.
|
| If I had to rewrite a Python project, I would consider Rust or
| another statically typed language before choosing to continue in
| a dynamic language with types bolted on. I hope the situation
| improves for dynamic languages with optional types, but it still
| feels weird and bolted onto the language because it is.
| yeasku wrote:
| I am suspicius of every codder who does not appreciate types.
| a_t48 wrote:
| Has anyone had good luck with auto-annotation of types of
| existing codebases? Either via LLM or via various runtime hooks?
| I work in a codebase that started off in Python 2 and isn't
| annotated with types in the majority of places, and I feel the
| pain every time I have to wonder what exactly the arguments to a
| method is.
| EdwardDiego wrote:
| Yep, I've used this pretty successfully, the ideal is to run it
| under realistic prod traffic over time to capture as many types
| as can flow into a given function, but a good set of
| unit/integration tests can also provide good coverage.
|
| And if you re-use the same type store (SQLite DB) across
| multiple instrumented runs, you can further improve it.
|
| https://github.com/Instagram/MonkeyType
| dandanua wrote:
| This is why I think Julia will win in the long run. It has an
| amazing type system, simple yet powerful. In particular, abstract
| types are much easier to define and use than abstract classes in
| Python.
| jakobnissen wrote:
| Ooh, I completely disagree. Julia has a worse type system
| overall, IMO. The big downside of Julia is that Julia has no
| interfaces or protocols. So, you can't type assert that
| something is an iterable of integers, for example.
|
| Another issue is that abstract types are completely
| undocumented and have no tooling support. You say it's easier
| to use an abstract type. Can you tell me what I need to define
| to create a working subtype of AbstractDict? Or Number? Or IO?
| It's completely undefined, and the only way to do it is to just
| define the type and then try it out and patch when it breaks
| because a method was missing.
|
| Finally, there is no multiple inheritance. That means I can't
| define something which is both a subtype of AbstractArray and
| IO, for example.
| dandanua wrote:
| There are no traits in Julia by default, that's true. But
| since types are first class citizens in Julia, traits can be
| implemented within the language. There is a package
| SimpleTraits.jl that implements Holy's trait trick, see also
| this tutorial https://ahsmart.com/pub/holy-traits-design-
| patterns-and-best...
|
| An ability to work with types within the language is already
| a win for me.
| ashu1461 wrote:
| A huge supporter of typing in python, but have observed that type
| sense which pycharm provides out of the box has its fair share of
| bugs as well.
|
| Also should check out ty by astral, it is pretty fast and does a
| good job at typechecking.
|
| https://docs.astral.sh/ty/editors/
| teiferer wrote:
| Misleading title. I was expecting to read about why devs actually
| embrace type hints. What the article is about is why you should
| and how you can use type hints. That's valuable, but different
| from what the title suggests.
|
| Besides, the lack of static typic is what makes a lot of the
| appeal for beginners. It's much harder to convince a non-CS
| beginner why they should bother with the extra burden of type
| hits. They are optional anyway and just slow folks down (so they
| might think). Careful with generally demanding that everybody use
| them.
|
| But they probably help coding assistants to make fewer mistakes,
| so maybe that will soon be an argument if it isn't already.
| (That's an angle I expected in the article.)
| ambyra wrote:
| With duck typing, you don't need type hints. You're just supposed
| to use the variable however you "feel" it should be used when
| you're using it, and it automagically just works!!! Try it! /s
| Havoc wrote:
| It's ok. The mild ground of typing feels pretty clunky to me
| though
|
| Definitely not a best of both world type outcome
| lukaslalinsky wrote:
| I was extremely skeptical when typing was introduced. What's the
| point if runtime ignores them. I forced myself to use them as
| documentation and now I'm on the other side of the spectrum, all
| code should have them. It already helped me a lot during
| refactors and I always wished more code had types. I think the
| same is true for AIs, they will benefit from having the types
| explicitly said. It's a shame they currently default to untyped
| Python.
| JodieBenitez wrote:
| > What's the point if runtime ignores them.
|
| I've been using this sparingly: https://pypi.org/project/type-
| enforced/
| fithisux wrote:
| I started using Python at work with type hints. I am very
| satisfied.
| zoom6628 wrote:
| Boring old me would be reaching for mojo in order to have types
| that actually are "real" rather than just an editing overlay of
| decorators/DSL/tooling.
| Too wrote:
| Too bad Mojo gave up on Python compatibility on code level. Now
| it's just one of a dozen "Python inspired" languages, with the
| only benefit that they aim for easily calling into other Python
| code.
| defraudbah wrote:
| Python developers are embracing RuntimeError.. It's amazing
| language that had it place, now it's time to sunset it and forget
| it. Leave it to prototyping only
| seanparsons wrote:
| As a static typing advocate I do find it funny how all the
| popular dynamic languages have slowly become statically typed.
| After decades of people saying it's not at all necessary and
| being so critical of statically typed languages.
|
| When I was working on a fairly large TypeScript project it became
| the norm for dependencies to have type definitions in a
| relatively short space of time.
| adalacelove wrote:
| People adapt to the circumstances. A lot of Python uses are no
| longer about fast iteration on the REPL. Instead of that we are
| shipping Python to execute in clusters on very long running
| jobs or inside servers. It's not only about having to start all
| over after hours, it's simply that concurrent and distributed
| execution environments are hostile to interactive programming.
| Now you can't afford to wait for an exception and launch the
| debugger in postmortem. Or even if you do it's not very useful.
|
| And now my personal opinion: If we are going the static typing
| way I would prefer simply to use Scala or similar instead of
| Python with types. Unfortunately in the same way that high
| performance languages like C attracts premature optimizers
| static types attract premature "abstracters" (C++ both). I also
| think that dynamic languages have the largest libraries for
| technical merit reasons. Being more "fluid" make them easier to
| mix. In the long term the ecosystem converges organically on
| certain interfaces between libraries.
|
| And so here we are with the half baked approach of gradual
| typing and #type: ignore everywhere.
| yurishimo wrote:
| PHP is a great example of the convergence of interfaces. Now
| they have different "PSR" standards for all sorts of things.
| There is one for HTTP clients, formatting, cache interfaces,
| etc. As long as your library implements the spec, it will
| work with everything else and then library authors are free
| to experiment on the implementation and contribute huge
| changes to the entire ecosystem when they find a performance
| breakthrough.
|
| Types seem like a "feature" of mature software. You don't
| need to use them all the time, but for the people stuck on
| legacy systems, having the type system as a tool in their
| belt can help to reduce business complexity and risk as the
| platform continues to age because tooling can be built to
| assert and test code with fewer external dependencies.
| pydry wrote:
| Here we are because:
|
| * Types are expensive and dont tend to pay off on
| spikey/experimental/MVP code, most of which gets thrown away.
|
| * Types are incredibly valuable on hardened production code.
|
| * Most _good_ production code started out spikey,
| experimental or as an MVP and _transitioned_.
|
| And so here we are with gradual typing because "throwing away
| all the code and rewriting it to be "perfect" in another
| language" has been known for years to be a shitty way to
| build products.
|
| Im mystified that more people here dont see that the value
| and cost of types is NOT binary ("they're good! theyre bad!")
| but exists on a continuum that is contingent on the status of
| the app and sometimes even the individual feature.
| tossandthrow wrote:
| The issue with moving the ship where it's passanger wants
| it to be makes it more difficult for new passengers to get
| on.
|
| This is clearly seen with typescript and the movement for
| "just use JS".
|
| Furthermore, with LLMs, it should be easier than ever to
| experiment in one language and use another language for
| production loads.
| adalacelove wrote:
| In some fields throwing away and rewriting is the standard,
| and it works, more or less. I'm thinking about
| scientific/engineering software: prototype in Python or
| Matlab and convert to C or C++ for performance/deployment
| constraints. It happens frequently with compilers too. I
| think migrating languages is actually more successful than
| writing second versions.
| cyberax wrote:
| > * Types are expensive and dont tend to pay off on
| spikey/experimental/MVP code, most of which gets thrown
| away.
|
| Press "X" to doubt. Types help _a_ _lot_ by providing
| autocomplete, inspections, and helping with finding errors
| while you're typing.
|
| This significantly improves the iteration speed, as you
| don't need to run the code to detect that you mistyped a
| varible somewhere.
| novok wrote:
| I've found the transition point where types are useful to
| start even within a few hundred lines of code, and I've
| found types are not that restrictive if at all, especially
| if the language started out typed. The rare case I need to
| discard types that is available usually, and a code smell
| your doing something wrong.
|
| Even within a recent toy 1h python interview question
| having types would've saved me some issues and caught an
| error that wasn't obvious. Probably would've saved 10m in
| the interview.
| whizzter wrote:
| Yep, depends on your memory context capacity.
|
| For me I often don't feel any pain-points when working
| before about 1kloc (when doing JS), however if a project
| is above 500loc it's often a tad painful to resume it
| months later when I've started to forget why I used
| certain data-structures that aren't directly visible
| (adding types at that point is usually the best choice
| since it gives a refresher of the code at the same time
| as doing a soundness check).
| pydry wrote:
| The transition to where type hints become valuable or
| even necessary isnt about how many lines of code you have
| it is about how much you rely upon their correctness.
|
| Type strictness also isnt binary. A program with lots of
| dicts that should be classes doesnt get much safer just
| because you wrote : dict[str, dict] everywhere.
| Mond_ wrote:
| > * Types are expensive and dont tend to pay off on
| spikey/experimental/MVP code, most of which gets thrown
| away.
|
| This is what people say, but I don't think it's correct.
| What _is_ correct is that say, ten to twenty years ago, all
| the statically typed languages had other unacceptable
| drawbacks and "types bad" became a shorthand for these
| issues.
|
| I'm talking about C (nonstarter for obvious reasons), C++
| (a huge mess, footguns, very difficult, presumably requires
| a cmake guy), Java (very restrictive, slow iteration and
| startups, etc.). Compared to _those_ just using Python
| sounds decent.
|
| Nowadays we have Go and Rust, both of which are pretty easy
| to iterate in (for different reasons).
| jampekka wrote:
| > Nowadays we have Go and Rust, both of which are pretty
| easy to iterate in (for different reasons).
|
| It's common for Rust to become very difficult to iterate
| in.
|
| https://news.ycombinator.com/item?id=40172033
| dahauns wrote:
| I think Java was the main one. C/C++ are (relatively)
| close to the metal, system-level languages with explicit
| memory management - and were tacitly accepted to be the
| "complicated" ones, with dynamic typing not really
| applicable at that level.
|
| But Java was the high-level, GCed, application
| development language - and more importantly, it was the
| one dominating many university CS studies as an education
| language before python took that role. (Yeah, I'm grossly
| oversimplifying - sincere apologies to the functional
| crowd! :) )
|
| The height of the "static typing sucks!" craze was more
| like a "The Java type system sucks!" craze...
| hnlmorg wrote:
| > Types are expensive and dont tend to pay off on
| spikey/experimental/MVP code, most of which gets thrown
| away.
|
| I find I've spent so much time writing with typed code that
| I now find it harder to write POC code in dynamic languages
| because I use types to help reason about how I want to
| architect something.
|
| Eg "this function should calculate x and return", well if
| you already know what you want the function to do then you
| know what types you want. And if you don't know what types
| you want then you haven't actually decided what that
| function should do ahead of building it.
|
| Now you might say "the point of experimental code is to
| figure out what you want functions to do". But even if
| you're writing an MVP, you should know what that each
| function should do by the time you've finished writing it.
| Because if you don't know who to build a function then how
| do you even know that the runtime will execute it
| correctly?
| overgard wrote:
| I don't think types are expensive for MVP code unless
| they're highly complicated (but why would you do that?)
| Primitives and interfaces are super easy to type and worth
| the extra couple seconds.
| marcosdumay wrote:
| Software quality only pays off on the long time. For the
| short time, garbage is quick and gets the job done.
|
| Also, in my experience, the long time for software arrives
| in a couple of weeks.
| zero_bias wrote:
| Python is ubiquitous in ML, often you have no choice but to
| use it
| aurareturn wrote:
| Javascript is no longer was just scripting. Very large and
| complex billion dollar apps were being written in pure
| Javascript. It grew up.
|
| I guess Python is next.
| Elucalidavah wrote:
| > how all the popular dynamic languages have slowly become
| statically typed
|
| Count the amount of `Any` / `unknown` / `cast` / `var::type` in
| those codebases, and you'll notice that they aren't
| particularly statically typed.
|
| The types in dynamic languages are useful for checking validity
| in majority of the cases, but can easily be circumvented when
| the types become too complicated.
|
| It is somewhat surprising that dynamic languages didn't go the
| pylint way, i.e. checking the codebase by auto-determined types
| (determined based on actual usage).
| jakobnissen wrote:
| Julia (by default) does the latter, and its terrible. It
| makes it a) slow, because you have to do nonlocal inference
| through entire programs, b) impossible to type check generic
| library code where you have no actual usage, c) very hard to
| test that some code works generically, as opposed to just
| with these concrete types, and finally d) break whenever you
| have an Any anywhere in the code so the chain of type
| information is broken.
| pansa2 wrote:
| > _all the popular dynamic languages have slowly become
| statically typed_
|
| I've heard this before, but it's not really true. Yes, maybe
| the majority of JavaScript code is now statically-typed, via
| Typescript. Some percentage of Python code is (I don't know the
| numbers). But that's about it.
|
| Very few people are using static typing in Ruby, Lua, Clojure,
| Julia, etc.
| Kwpolska wrote:
| How many people are using Ruby, Lua, Clojure, Julia, etc.?
| pansa2 wrote:
| Fair enough, apart from Ruby they're all pretty niche.
|
| OTOH I'm not arguing that most code should be dynamically-
| typed. Far from it. But I do think dynamic typing has its
| place and shouldn't be rejected entirely.
|
| Also, I would have preferred it if Python had concentrated
| on being the best language in that space, rather than
| trying to become a jack-of-all-trades.
| Hamuko wrote:
| I have my doubts about majority of JavaScript being
| TypeScript.
| pansa2 wrote:
| You're probably right. RedMonk [0] shows JavaScript and
| TypeScript separately and has the former well above the
| latter.
|
| [0] https://redmonk.com/sogrady/2025/06/18/language-
| rankings-1-2...
| seanparsons wrote:
| Even if they're not written as TypeScript, there are
| usually add on definitions like "@types/prettier" and the
| like.
| majoe wrote:
| I disagree for Julia, but that probably depends on the
| definition of static typing.
|
| For the average Julia package I would guess, that most types
| are statically known at compile time, because dynamic
| dispatch is detrimental for performance. I consider, that to
| be the definition of static typing.
|
| That said, Julia functions seldomly use concrete types and
| are generic by default. So the function signatures often look
| similar to untyped Python, but in my opinion this is
| something entirely different.
| iLoveOncall wrote:
| PHP as well has become statically typed.
|
| All the languages you name are niche languages compared to
| Python, JS (/ TS) and PHP. Whether you like it or not.
| tinnet wrote:
| At least in ruby theres mayor code bases using stripes sorbet
| and the official RBS standard for type hints. Notably its big
| code bases with large amounts of developers, fitting in with
| the trend most people in this discussion point to.
| jascha_eng wrote:
| Types become very useful when the code base reaches a certain
| level of sophistication and complexity. It makes sense that
| for a little script they provide little benefit but once you
| are working on a code base with 5+ engineers and no longer
| understand every part of it having some more strict
| guarantees and interfaces defined is very very helpful. Both
| for communicating to other devs as well as to simply
| eradicate a good chunk of possible errors that happen when
| interfaces are not clear.
| seanparsons wrote:
| My last job was working at a company that is notorious for
| Ruby and even though I was mostly distant from it, there
| seemed to be a big appetite for Sorbet there.
| pansa2 wrote:
| The big difference between static typing in Python and Ruby
| is that Guido et al have embraced type hints, whereas Matz
| considers them to be (the Ruby equivalent of) "unpythonic".
| Most of each language's community follows their (ex-)BDFL's
| lead.
| vladms wrote:
| I like static types but advocating for enforcing them in any
| situation is different. Adding them when you need (Python
| currently) seems a better strategy than forcing you to set them
| always (Typescript is in between as many times it can determine
| them).
|
| Many years ago I felt Java typing could be overkill (some types
| could have been deduced from context and they were too long to
| write) so probably more an issue about the maturity of the
| tooling than anything else.
| flohofwoe wrote:
| OTH I only came to realize that I actually like duck typing in
| some situations when I tried to add type hints to one of my
| Python projects (and then removed them again because the
| actually important types consisted almost entirely of sum
| types, and what's the point of static typing if anything is a
| variant anyway).
|
| E.g. when Python is used as a 'scripting language' instead of a
| 'programming language' (like for writing small command line
| tools that mainly process text), static typing often just gets
| in the way. For bigger projects where static typing makes sense
| I would pick a different language. Because tbh, even with type
| hints Python is a lousy programming language (but a fine
| scripting language).
| lolive wrote:
| Note1: Type hints are hints for the reader. If you cleverly
| discovered that your function is handling any type of data,
| hint that!
|
| Note2: From my experience, in Java, i have NEVER seen a
| function that consumes explicitely an Object. In Java, you
| always name things. Maybe with parametric polymorphism, to
| capture complex typing patterns.
|
| Note 3: unfortunately, you cannot subclass String, to capture
| the semantic of its content.
| 1313ed01 wrote:
| > Java, i have NEVER seen a function that consumes
| explicitely an Object
|
| So you did not see any Java code from before version 5 (in
| 2004) then, because the language did not have generics for
| the first several years it was popular. And of course many
| were stuck working with older versions of the language (or
| variants like mobile Java) without generics for many years
| after that.
| lolive wrote:
| Exactly, I have never seen such codes [*].
|
| Probably because the adoption of the generics has been
| absolutely massive in the last 20 years. And I expect the
| same thing to eventually happen with Typescript and
| [typed] Python.
|
| [*]: nor have I seen EJB1 or even EJB2. Spring just
| stormed them, in the last 20 years.
| lelanthran wrote:
| > Because tbh, even with type hints Python is a lousy
| programming language (but a fine scripting language).
|
| I'd be interested in seeing you expand on this, explaining
| the ways you feel Python doesn't make the cut for programming
| language while doing so for scripting.
|
| The reason I say this is because, intuitively, I've felt this
| way for quite some time but I am unable to properly
| articulate why, other than "I don't want all my type errors
| to show up at runtime only!"
| integralid wrote:
| If you like dynamic types have you considered using
| protocols? They are used precisely to type duck typed code.
| zo1 wrote:
| Sounds to be more of a symptom of the types of programs and
| functions you have written, rather than something inherent
| about types or Python. I've never encountered the type of
| gerry-mangled scenario you have described no matter how
| throwaway the code is.
| lolive wrote:
| Next stop is to agree that JSON is really NOT the semantic data
| exchange serialization for this "properly typed" world.
| dotancohen wrote:
| Then what is?
|
| Everybody knows the limitations of JSON. Don't state the
| obvious problem without stating a proposed solution.
| lolive wrote:
| The RDF structure is a graph of typed instances of typed
| objects, serializable as text.
|
| Exchanging RDF, more precisely its [more readable]
| "RDF/turtle" variant, is probably what will eventually come
| to the market somehow.
|
| Each object of a RDF structure has a global unique
| identifier, is typed, maintains typed links with other
| objects, have typed values.
| lolive wrote:
| For an example of RDF being exchanged between a server
| and a client, you can test
|
| https://search.datao.net/beta/?q=barack%20obama
|
| Open your javascript console, and hover the results on
| the left hand side of the page with your mouse. The
| console will display which RDF message triggered the viz
| in the center of the page.
|
| Update: you may want to FIRST select the facet "DBPedia"
| at the top of the page, for more meaningful messages
| exchanged.
|
| Update2: the console does not do syntax higlighting, so
| here is the highlighted RDF https://datao.net/ttl.jpg
| linked to the 1st item of " https://search.datao.net/beta
| /?q=films%20about%20barack%20ob... "
| dotancohen wrote:
| That's a circular argument. What serialization format
| would you recommend? JSON?
| lolive wrote:
| Turtle directly.
|
| JSON forces you to fit your graph of data into a tree
| structure, that is poorly capturing the cardinalities of
| the original graph.
|
| Plus of course, the concept of object type is not
| existing in JSON.
| dotancohen wrote:
| Thank you, I did not realize that RDF has its own
| serialization format. I'm reading about it now.
| bushbaba wrote:
| I think both found middle ground. In Java you don't need to
| define the type of variables within the method. In Python
| people have learned types in method arguments is a good thing.
| isodev wrote:
| > After decades of people saying
|
| You have to admit that the size and complexity of the software
| we write has increased dramatically over the last few
| "decades". Looking back at MVC "web applications" I've created
| in the early 2000s, and comparing them to the giant workflows
| we deal with today... it's not hard to imagine how dynamic
| typing was/is ok to get started, but when things exceed one's
| "context", you type hints help.
| jmorenoamor wrote:
| Coming from Java extreme verbosity, I just loved the freedom of
| python 20 years ago. Working with complex structures with mixed
| types was a breeze.
|
| Yes, it was your responsibility to keep track of correctness,
| but that also taught me to write better code, and better tests.
| procaryote wrote:
| Writing tests is harder work than writing the equvalent
| number of type hints though
| ivanjermakov wrote:
| Writing and maintaining tests that just do type checking is
| madness.
|
| Dynamic typing also gives tooling such as LSPs and linters a
| hard time figuring out completions/references lookup etc.
| Can't imagine how people work on moderate to big projects
| without type hints.
| afiori wrote:
| In the discussion of static vs dynamic typing solutions like
| typescript or annotated python were not really considered.
|
| IMHO the idea of a complex and inference heavy type system that
| is mostly useless at runtime and compilation but focused on
| essentially interactive linting is relatively recent and its
| popularity is due to typescript success
|
| I think that static typing proponents were thinking of
| something more along the lines of Haskell/OCaml/Java rather
| than a type-erased system a language where [1,2] > 0 is true
| because it is converted to "NaN" > "0"
| al_be_back wrote:
| dynamically-typed languages were typically created for
| scripting tasks - but ended up going viral (in part due to
| d-typing), the community stretched the language to its limits
| and pushed it into markets it wasn't designed/thought for
| (embedded python, server-side js, distributed teams, dev
| outsourcing etc).
|
| personally i like the dev-sidecar approach to typing that
| Python and JS (via TS) have taken to mitigate the issue.
| kubb wrote:
| What I would need is a statically typed language that has first
| class primitives for working with untyped data ergonomically.
|
| I do want to be able to write a dynamically typed function or
| subsystem during the development phase, and ,,harden" with
| types once I'm sure I got the structure down.
|
| But the dynamic system should fit well into the language, and I
| should be able to easily and safely deal with untyped values
| and convert them to typed ones.
| promiseofbeans wrote:
| So... Typescript?
| whizzter wrote:
| Yes, the sad part is that some people experienced early
| TypeScript that for some reason had the idea of forcing
| "class" constructs into a language where most people wasn't
| using or needing them (and still aren't).
|
| Sometimes at about TypeScript 2.9 finally started adding
| constructs that made gradual typing of real-world JS code
| sane, but by then there was a stubborn perception of it
| being bad/bloated/Java-ish,etc despite maturing into
| something fairly great.
| pjmlp wrote:
| Thing is, famous dynamic languages of the past, Common Lisp,
| BASIC, Clipper, FoxPro, all got type hints for a reason, then
| came a new generation of scripting languages made application
| languages, and everyone had to relearn why the fence was in the
| middle of the field.
| cardanome wrote:
| > slowly become statically typed
|
| They don't. They become gradually typed which is a thing of
| it's own.
|
| You can keep the advantages of dynamic languages, the ease of
| prototyping but also lock down stuff when you need to.
|
| It is not a perfect union, generally the trade-off is that you
| can either not achieve the same safety level as in a purely
| statically typed language because you need to provide same
| escape hatches or you need a extremely complex type system to
| catch the expressiveness of the dynamic side. Most of the time
| it is a mixture of both.
|
| Still, I think this is the way to go. Not dynamic typing won or
| static typing won but both a useful and having a language
| support both is a huge productivity boost.
| Sharlin wrote:
| Everything goes in cycles. It has happened before and it will
| happen again. The softward industry is _incredibly_ bad at
| remembering lessons once learned.
| mhitza wrote:
| I think you're ignoring how for some of us, gradual typing, is
| a far better experience than languages with static types.
|
| For example what I like about PHPStan (tacked on static
| analysis through comments), that it offers so much flexibility
| when defining type constraints. Can even specify the literal
| values a function accepts besides the base type. And subtyping
| of nested array structures (basically support for comfortably
| typing out the nested structure of a json the moment I decode
| it).
| seanparsons wrote:
| Not ignoring, I just didn't write an essay. In all that time
| working with TypeScript there was very little that I found to
| be gradually typed, it was either nothing or everything,
| hence my original comment. Sure some things might throw in a
| bunch of any/unknown types but those were very much the
| rarity and often some libraries were using incredibly
| complicated type definitions to make them as tight as
| possible.
| choomahs187 wrote:
| Worked with python, typescript and now php, seems that
| phpstan allows this gradual typing, while typescript kinda
| forces you to start with strict in serious projects.
| crabbone wrote:
| Same nonsense repeated over and over again... There aren't
| dynamic languages. It's not a thing. The static types aren't
| what you think they are... You just don't know what you are
| saying and your conclusion is just a word salad.
|
| What happened to Python is that it used to be a "cool"
| language, whose community liked to make fun of Java for their
| obsession with red-taping, which included the love for
| specifying unnecessary restrictions everywhere. Well, just like
| you'd expect from a poorly functioning government office.
|
| But then everyone wanted to be cool, and Python was adopted by
| the programming analogue of the government bureaucrats: large
| corporations which treat programming as a bureaucratic mill.
| They don't want fun or creativity or one-of bespoke solutions.
| They want an industrial process that works on as large a scale
| as possible, to employ thousands of worst quality programmers,
| but still reliably produce slop.
|
| And incrementally, Python was made into Java. Because, really,
| Java is great for producing slop on an industrial scale. But
| the "cool" factor was important to attract talent because there
| used to be a shortage, so, now you have Python that was remade
| to be a Java. People who didn't enjoy Java left Python over a
| decade ago. So that Python today has nothing in common with
| what it was when it was "cool". It's still a worse Java than
| Java, but people don't like to admit defeat, and... well,
| there's also the sunk cost fallacy: so much effort was already
| spent at making Python into a Java, that it seems like a good
| idea to waste even more effort to try to make it a better Java.
| ModernMech wrote:
| Yeah, this is the lens through which I view it. It's a sort
| of colonization that happens, when corporations realize a
| language is fit for plunder. They start funding it, then they
| want their people on the standards boards, then suddenly the
| direction of the language is matched very nicely to their
| product roadmap. Meanwhile, all the people who used to make
| the language what it was are bought or pushed out, and the
| community becomes something else entirely.
| whizzter wrote:
| That's because many do small things that don't really need it,
| sure there are some people doing larger stuff and are happy to
| be the sole maintainer of a codebase or replace the language
| types with unit-test type checks.
|
| And I think they can be correct for rejecting it, banging out a
| small useful project (preferably below 1000 loc) flows much
| faster if you just build code doing things rather than start
| annotating (that quickly can be come a mind-sinkhole of naming
| decisions that interrupts a building flow).
|
| However, even less complex 500 loc+ programs without typing can
| become a pita to read after the fact and approaching 1kloc it
| can become a major headache to pick up again.
|
| Basically, can't beat speed of going nude, but size+complexity
| is always an exponential factor in how hard continuing and/or
| resuming a project is.
| ktosobcy wrote:
| Well, we do coalesce on certain things... some static type
| languages are dropping type requirements (Java and `var` in
| certain places) :D
| constantcrying wrote:
| var does absolutely nothing to make Java a less strictly
| typed language. There is absolutely no dropping of the
| requirement that each variable has a type which is known at
| compile time.
|
| Automatic type inference and dynamic typing are totally
| different things.
| hirvi74 wrote:
| I have not written a line of Java in at least a decade, but
| does Java not have any 'true' dynamic typing like C# does?
| Truth be told, the 'dynamic' keyword in C# should only be
| used in the most niche of circumstances. Typically, only
| practitioners of Dark Magic use the dynamic type. For the
| untrained, it often leads one down the path of hatred,
| guilt, and shame. For example:
|
| dynamic x = "Forces of Darkness, grant me power";
|
| Console.WriteLine(x.Length); // Dark forces flow through
| the CLR
|
| x = 5;
|
| Console.WriteLine(x.Length); // Runtime error: CLR consumed
| by darkness.
|
| C# also has the statically typed 'object' type which all
| types inherit from, but that is not technically a true
| instance of dynamic typing.
| moefh wrote:
| There's no dropping of type requirements in Java, `var` only
| saves typing.
|
| When you use `var`, everything is as statically typed as
| before, you just don't need to spell out the type when the
| compiler can infer it. So you can't (for example) say `var x
| = null` because `null` doesn't provide enough type
| information for the compiler to infer what's the type of `x`.
| procaryote wrote:
| > `var` only saves typing.
|
| this is a lovely double entendre
| constantcrying wrote:
| The need for typing changed, when the way the language is used
| changed.
|
| When JavaScript programs were a few hundred lines to add
| interactivity to some website type annotationd were pretty
| useless. Now the typical JavaScript project is far larger and
| far more complex. The same goes for python.
| LudwigNagasena wrote:
| Static typing used to be too rigid and annoying to the point of
| being counterproductive. After decades of improvement of
| parsers and IDEs they finally became usable for rapid
| development.
| DarkNova6 wrote:
| Huh. It's almost like these people didn't know what they were
| talking about. How strange.
| tetha wrote:
| I think that the practically available type checkers evolved to
| a point where many of the common idioms can be expressed with
| little effort.
|
| If one thinks back to some of the early statically typed
| languages, you'd have a huge rift: You either have this
| entirely weird world of Caml and Haskell (which can express
| most of what python type hints have, and could since many
| years), and something like C, in which types are merely some
| compiler hints tbh. Early Java may have been a slight
| improvement, but eh.
|
| Now, especially with decent union types, you can express a lot
| of idioms of dynamic code easily. So it's a fairly painless way
| to get type completion in an editor, so one does that.
| theptip wrote:
| Type hints / gradual typing is crucially different from full
| static typing though.
|
| It's valid to say "you don't need types for a script" and "you
| want types for a multi-million LOC codebase".
| alex_suzuki wrote:
| I recently discovered that the folks building uv and ruff are
| also building a type checker, and it already works really well
| (and fast!), despite beta status:
|
| https://github.com/astral-sh/ty
| Marazan wrote:
| My view on typing in Python (a language I have used for decades)
| is that if I wanted types I would use a language designed from
| the ground up with strong and consistent typing built-in. Not
| bolt on a sort of type system which actively fights against the
| way I use the language on a day to day basis.
|
| I use plenty of statically typed languages, Python's type hinting
| does not bring me joy.
| Hackbraten wrote:
| > Not bolt on a sort of type system which actively fights
| against the way I use the language on a day to day basis.
|
| Can you help me out with an example of a Python usage pattern
| against which the type system seems to be fighting?
| Marazan wrote:
| Ok, so this is just one of many examples but the most
| immediate one is where I don't care about the immutable
| sanctity of the variable I have just declared.
|
| I often use Python for data munging and I'll frequently write
| code that goes foo = initial_value ...
| foo = paritally_cleaned_up_value ... if check:
| foo = fianllylikethis else: foo = orlikethis
|
| Where the type of the value being assigned to foo is
| different each time. Now, obviously (in this simplistic
| example that misses subtleties) I could declare a new
| variable for each transformation step or do some composite
| type building type thing or refactor this into separate
| functions for each step that requires a different type but
| all of those options are unnecessary busy work for what
| should be a few simple lines of code.
| Hackbraten wrote:
| Thanks, now I get why you feel like the type system is
| fighting your style of programming.
|
| > all of those options are unnecessary busy work for what
| should be a few simple lines of code
|
| If you re-type your variable often, then how do you make
| sure you're really keeping track of all those types?
|
| If you re-type it only a few times, then I'm not entirely
| convinced that declaring a few additional variables really
| constitutes busywork.
|
| Small example with additional variables instead of re-
| typing the same variable: # pylint:
| disable=disallowed-name, missing-function-docstring,
| missing-module-docstring, redefined-outer-name
| from typing import NewType NEEDS_CHECKING =
| True NotCleaned = NewType("NotCleaned", str)
| Checked = NewType("Checked", str) Cleaned =
| NewType("Cleaned", str) original_foo = ["SOME
| ", "dirty ", " Data"] annotated_foo =
| [NotCleaned(item) for item in original_foo]
| cleaned_foo = [
| Cleaned(item.lower().strip().replace("dirty", "tidy"))
| for item in annotated_foo ] foo:
| list[Checked | Cleaned] if NEEDS_CHECKING:
| for idx, item in enumerate(cleaned_foo): if
| item and (item[0] == " " or item[-1] == " "):
| raise RuntimeError(f"Whitespace found in item #{idx}:
| {item=}") if "dirt" in item:
| raise RuntimeError(f"Item #{idx} is dirty: {item=}")
| foo = [Checked(item) for item in cleaned_foo] else:
| foo = list(cleaned_foo) print(foo) #
| => ['some', 'tidy', 'data']
|
| This survives strict type checking (`mypy --strict`). I
| don't feel that renaming the variables introduces much
| noise or busywork here? One might argue that renaming even
| adds clarity?
| hauntsaninja wrote:
| pyright will accept this. mypy should accept this when
| using --allow-redefinition-new as well
| JackSlateur wrote:
| One can hope that cpython will use them, one day
|
| "if a parameter is typed as an int, then only run the specialized
| 'int' code to process it"
|
| This would increase performance and make typing more useful
| aunderscored wrote:
| Without significant language changes, this is not possible.
| While your code may be typed as an int, I can simply redefine
| what int means. I can also modify the code in your method.
| JackSlateur wrote:
| Yes
|
| I guess it would work with the ongoing jit work, which (as
| far as I understood..) run the code "as usual", then notice
| that a specific variable is always a dict (or whatever). Then
| it patches the code to run the dict-optimized code by default
| (and fallback to the generic code if, somehow, the variable
| is no longer a dict).
|
| With typing, the generic code could be avoided altogether.
| The algorithm would be: - notice that some
| variable can be processed by a dict-optimized code (because
| its typing is a dict, or something that looks like a dict
| etc) - when processing, check that the variable is
| indeed a "dict", raise an exception if not - run the
| optimized code - if the typing information changes
| (because the class has been redefined and the variable is no
| longer a "dict"), then go to step 1 and either stick with the
| current optimized code, use another one, or use the generic
| one
|
| This would: - enforce types (you said that
| variable is a Thing but a Thing was not given: exception)
| - improve the jit by removing the bootstrap phase (where the
| jit watches and then try to guess what could be improved)
|
| (or perhaps this is a stupid idea that cannot work :) )
| aunderscored wrote:
| There are already some bits of this with specific bytecode
| and the upcoming jit, it's not using annotations at all
| though
| ciupicri wrote:
| I think you're forgetting that int is actually what other
| people call a BigInt, an integer with unlimited precision, not
| int32 or int64.
| picafrost wrote:
| My experience adding types to un-typed Python code has convinced
| me that static typing should be required for anything more
| complicated than a single purpose script. Even in old and battle
| tested code bases so many tiny bugs and false assumptions are
| revealed and then wiped out.
|
| It's not perfect in Python, and I see some developers introduce
| unnecessary patterns trying to make type-"perfect" `class
| Foo(Generic[T, V])` (or whatever) abstractions where they are not
| really necessary. But if the industry is really going all-in on
| Python for more than scripting, so should we for typed Python.
| entropyneur wrote:
| I know I am going to be in the minority, but I don't understand
| why we can't let Python be Python. Static typing is great, and
| there are already other statically typed languages for all your
| needs. Why not use them?
|
| Well, at least it doesn't create two incompatible Pythons like
| async and (I assume) free threading.
| Galanwe wrote:
| I used to be of the same opinion, but after giving type hints a
| real try, I changed my mind.
|
| You should not see type hints as real, hard types, but more as
| a kind of documentation that helps your linter and type checker
| catch mistakes.
| Matthyze wrote:
| > Why not use them?
|
| Because you can now use typing WITH the entire Python
| ecosystem.
| Ekaros wrote:
| I sometimes felt that Python was rather strong in many parts of
| typing. As such being able to track what type of something is
| would often have been useful. Instead of waiting it to crash to
| some error.
|
| Like back in 2.7 difference between byte-array and string...
| Offloading such cases is mentally useful.
| chpatrick wrote:
| Because Python has a lot of things it's great at (numeric
| stuff, ML, computer vision, scripting), and with types you can
| actually rely on it to work. It's the best of both worlds.
| gooodvibes wrote:
| Isn't this a very 2018-2019 topic? I don't get the motivation to
| write about it in 2025, it's like telling people to use version
| control.
| Hackbraten wrote:
| https://xkcd.com/1053/
| yoshi389111 wrote:
| Beyond the usual advantages of Python's type hints, it seems they
| can also improve code suggestions and completions when working
| with AI coding tools.
| ciupicri wrote:
| Is there a type checker that works with _numbers.Number_?
| spooky_deep wrote:
| Python with type hints still lacks the performance benefits of
| static typing in a compiled language setting?
| maxfurman wrote:
| It's the developer performance benefit of catching type bugs
| early, not the application performance benefit from a compiler,
| that Python developers find compelling
| pansa2 wrote:
| Yes. It also lacks the ease-of-deployment of a compiled
| language.
| chpatrick wrote:
| You generally don't write Python if you want it to be really
| fast anyway (non-Python parts like numpy notwithstanding).
| tmarice wrote:
| Type hints in Python add a great amount of visual noise to the
| code, and I actively avoid them wherever possible. If static
| typing is a must, use a language where static typing is not an
| afterthought, and let Python be Python.
| ctxc wrote:
| I guess one man's noise is another man's treasure :P
| corwinxpro wrote:
| Indeed, I almost can't read untyped python code these days.
| It just feels like "what the hell is going on here?" and
| "what is this object?" ever so often. Sorry to say that but
| most people who write python just aren't good API designers,
| or software engineers in general, and type hints can at least
| help others get a vague idea of what the intent was.
| chrysoprace wrote:
| Would you rather deal with a little visual noise or a runtime
| exception that you could've caught before code got to
| production? For me it's about tradeoffs, and so far the
| tradeoff has been well worth it.
| mgaunard wrote:
| in general I see two types of Python in the wild: - simple self-
| contained scripts, everything is a free function, no type hints -
| over-engineered hierarchies of classes spread over dozens of
| files and modules, type hints everywhere
|
| I personally largely prefer the first kind, but it seems even the
| standard formatting rules are against it (two empty lines between
| free functions etc.)
| Matthyze wrote:
| I'm always surprised when people suggest using a different
| language if you want typing in Python. Python's (second?) largest
| appeal is probably its extensive ecosystem. Whenever people
| suggest just changing languages, I wonder if they work in
| isolation, without the need for certain packages or co-worker
| proficiency in that language.
| sigmoid10 wrote:
| Typing has only been around since python 3.5. As someone who
| has formally learned 2.7 in university when 3.0 had already
| been around for a few years, I suppose there are many who still
| lag years behind what the language can do due to old codebases
| and fears of incompatibility.
| f311a wrote:
| I think people usually say it for a different reason. Types are
| not enforced. You can annotate your code that looks correct to
| the type checker, but the actual data flow at runtime can be
| with different types.
|
| And it happens quite often in large codebases. Sometimes
| external dependencies report wrong types, e.g., a tuple instead
| of a list. It's easy to make such a mistake when a library is
| written in a compiled language and just provides stubs for
| types. Tuples and lists share the same methods, so it will work
| fine for a lot of use cases. And since your type checker will
| force you to use a tuple instead of a list, you will never know
| that it's actually a list that can be modified unless you
| disable type checking and inspect the data.
| chpatrick wrote:
| To be pedantic compiled languages only check types at compile
| time as well. If you have a C library that takes void* then
| it can easily go wrong at runtime.
| ctxc wrote:
| For some reason, I find typing in Python to be more ergonomic and
| "get out of your way" compared to Typescript.
|
| But they both seem to handle typing similarly.
|
| I can't put my finger on why. Anybody else?
| chrysoprace wrote:
| TypeScript is kind of all or nothing.
|
| It's not quite all or nothing, but it's annoying to work with
| it if you only use it for some things and not for others. I
| find that if you have a mixture of TS and JS in various files I
| would rather just go all in on TypeScript so I don't have to
| manually annotate.
|
| With Python you're still just working with Python files.
| xurukefi wrote:
| For me, type hints are mainly useful because they're the only
| reliable way to get decent IDE auto-completion. Beyond that, they
| feel like a bolted-on compromise that goes against the spirit of
| Python. If you really need strict typing, you're probably better
| off using a statically typed language.
| kitd wrote:
| JSDoc plays a similar role with Javascript. Moreover it is
| supported out of the box by VSCode, so add a few JSDoc comments
| to your types and functions, and intellisense instantly kicks
| in.
| Dr_Birdbrain wrote:
| I actually don't like python type hints!
|
| At my work we have a jit compiler that requires type hints under
| some conditions.
|
| Aside from that, I avoid them as much as possible. The reason is
| that they are not really a part of the language, they violate the
| spirit of the language, and in high-usage parts of code they
| quickly become a complete mess.
|
| For example a common failure mode in my work's codebase is that
| some function will take something that is indexable by ints. The
| type could be anything, it could be List, Tuple, Dict[int, Any],
| torch.Size, torch.Tensor, nn.Sequential, np.ndarray, or a huge
| host of custom types! And you better believe that every single
| admissible type will eventually be fed to this function.
| Sometimes people will try to keep up, annotating it with a Union
| of the (growing) list of admissible types, but eventually the
| list will become silly and the function will earn a # pyre-ignore
| annotation. This defeats the whole point of the pointless
| exercise.
|
| So, if the jit compiler needs the annotation I am happy to
| provide it, but otherwise I will proactively not provide any, and
| I will sometimes even delete existing annotations when they are
| devolving into silliness.
| detaro wrote:
| Can't you define your own hint for "type that has __getitem__
| taking int"?
| crabbone wrote:
| The way I understand parent is that such a type would be too
| broad.
|
| The bigger problem is that the type system expressed through
| hints in Python is not the type system Python is actually
| using. It's not even an approximation. You can express in the
| hint type system things that are nonsense in Python and write
| Python that is nonsense in the type system implied by hints.
|
| The type system introduced through typing package and the
| hints is a tribute to the stupid fashion. But, also, there is
| no syntax and no formal definitions to describe Python's
| actual type system. Nor do I think it's a very good system,
| not to the point that it would be useful to formalize and
| study.
|
| In Russian, there's an expression "like a saddle on a cow",
| I'm not sure what the equivalent in English would be. This
| describes a situation where someone is desperately trying to
| add a desirable feature to an exiting product that ultimately
| is not compatible with such a feature. This, in my mind, is
| the best description of the relationship between Python's
| actual type system and the one from typing package.
| bc569a80a344f9c wrote:
| > In Russian, there's an expression "like a saddle on a
| cow", I'm not sure what the equivalent in English would be
|
| "To fit a square peg into a round hole"
| crabbone wrote:
| Close but not the same. In Russian, the expression
| implies an "upgrade", a failed attempt at improving
| something that either doesn't require improvement or
| cannot be improved in this particular way. This would be
| a typical example of how it's used: "I'm going to be a
| welder, I need this bachelor's degree like a saddle on a
| cow!".
| throw-the-towel wrote:
| "Lipstick on a pig"? Although that's quite more combative
| than the Russian phrase.
| crabbone wrote:
| Yeah... this seems like it would fit the bill nicely. At
| least, this is the way I'd translate it if I had to. Just
| didn't think about it.
| thr0w4w4y1337 wrote:
| from typing import Protocol, TypeVar
|
| T_co = TypeVar("T_co", covariant=True)
|
| class Indexable(Protocol[T_co]): def __getitem__(self, i: int)
| -> T_co: ...
|
| def f(x: Indexable[str]) -> None: print(x[0])
|
| I am failing to format it proprely here, but you get the idea.
| empiko wrote:
| There is also bunch of prepackaged types, such as
| collections.abc.Sequence that could be used in this case.
| thr0w4w4y1337 wrote:
| Sequence does not cut it, since the op mentioned int
| indexed dictionaries. But yeah.
| sevensor wrote:
| Sequence[SupportsFloat] | Mapping[int,SupportsFloat]
|
| Whether or not you explicitly write out the type, I find
| that functions with this sort of signature often end up
| with code that checks the type of the arguments at
| runtime anyway. This is expensive and kind of pointless.
| Beware of bogus polymorphism. You might as well write two
| functions a lot of the time. In fact, the type system may
| be gently prodding you to ask yourself just what you
| think you're up to here.
| whilenot-dev wrote:
| Just fyi: https://news.ycombinator.com/formatdoc
|
| > Text after a blank line that is indented by two or more
| spaces is reproduced verbatim. (This is intended for code.)
|
| If you'd want monospace you should indent the snippet with
| two or more spaces: from typing import
| Protocol, TypeVar T_co = TypeVar("T_co",
| covariant=True) class Indexable(Protocol[T_co]):
| def __getitem__(self, i: int) -> T_co: ... def
| f(x: Indexable[str]) -> None: print(x[0])
| amluto wrote:
| I give Rust a lot of points for putting control over
| covariance into the language without making anyone remember
| which one is covariance and which one is contravariance.
| sevensor wrote:
| One of the things that makes typing an existing codebase
| difficult in Python is dealing with variance issues. It
| turns out people get these wrong all over the place in
| Python and their code ends up working by accident.
|
| Generally it's not worth trying to fix this stuff. The type
| signature is hell to write and ends up being super complex
| if you get it to work at all. Write a cast or Any, document
| why it's probably ok in a comment, and move on with your
| life. Pick your battles.
| dhussoe wrote:
| Kotlin uses "in" and "out":
| https://kotlinlang.org/docs/generics.html
| ndriscoll wrote:
| Co- means with. Contra- means against. There are lots of
| words with these prefixes you could use to remember
| (cooperate, contradict, etc.).
| unethical_ban wrote:
| It sounds like that function is rightfully eligible to be
| ignored or to use the Any designation. To me that's why the
| system is handy. For functions that have specific inputs and
| outputs, it helps developers keep things straight and document
| code.
|
| For broad things, write Any or skip it.
| 9dev wrote:
| That's the same complaints people had about TypeScript in the
| beginning, when libraries such as Express used to accept a wide
| range of input options that would be a pain to express in types
| properly. If you look at where the ecosystem is now, though,
| you'll see proper type stubs, and most libraries get written in
| TS in the first place anyway. When editing TS code, you get
| auto-completion out of the box, even for deeply nested
| properties or conditional types. You can rely on types being
| what the compiler says they are, and runtime errors are a
| rarity now (in properly maintained code bases).
|
| > The reason is that they are not really a part of the
| language, they violate the spirit of the language, and in high-
| usage parts of code they quickly become a complete mess.
|
| I'll admit that this is what I hate Python, and it's probably
| this spirit of the language as you call it. I never really
| _know_ what parameters a function takes. Library documentation
| often shows a few use cases, but doesn 't really provide a
| reference; so I end up having to dig into the source code to
| figure it out on my own. Untyped and undocumented kwargs?
| Everywhere. I don't understand how someone could embrace so
| much flexibility that it becomes entirely undiscoverable for
| anyone but maintainers.
| zelphirkalt wrote:
| Because the flexibility has been a boon and not a problem.
| The problem only comes when you try to express everything in
| the type system, that is third party (the type checkers for
| it) and added on top.
| fn-mote wrote:
| > Because the flexibility has been a boon and not a problem
|
| Well, you could say that the problem in this case was the
| lack of documentation, if you wanted. The type signature
| could be part of the documentation, from this point of
| view.
|
| Let me give a kind-of-concrete example: one year I was
| working through a fast.ai course. They have a Python layer
| above the raw ML stuff. At the time, the library
| documentation was mediocre: the code worked, there were
| examples, and the course explained what was covered in the
| course. There were no type hints. It's free (gratis), I'm
| not complaining. _However_ , once I tried making my own
| things, I constantly ran into questions about "can this
| function do X" and it was really hard to figure out whether
| my earlier code was wrong or whether the function was never
| intended to work with the X situation. In my case, type
| hints would have cleared up most of the problems.
| makeitdouble wrote:
| > the lack of documentation
|
| If the code base expects flexibility, trusting
| documentation is the last thing you'd want to do. I know
| some people live and die by the documentation, but that's
| just a bad idea when duck typing or composition is
| heavily used for instance, and documentation should be
| very minimal in the first place.
|
| When a function takes a myriad of potential input, "can
| this function do X" is an answer you get by reading the
| function or the tests, not the prose on how it was
| intended 10 years ago or how some other random dev thinks
| it works.
| 9dev wrote:
| Documentation doesn't have to be an essay. A simple,
| automatically generated reference with proper types goes
| a long way to tell me ,,it can do that" as opposed to
| ,,maybe it works lol". That's not the level of
| engineering quality I'm going for in my work.
| makeitdouble wrote:
| This whole discussion is about how you might not want to
| be listing every single types a function accepts. I also
| kinda wonder how you automatically generate that for duck
| typing.
| Balinares wrote:
| It's a boon if the goal is to write code then go home. It's
| a loaded footgun if the goal is to compose a stack and run
| it in production within SLO.
|
| Python type hints manage to largely preserve the
| flexibility while seriously increasing confidence in the
| correctness, and lack of crashing corner cases, of each
| component. There's really no good case against them at this
| point outside of one-off scripts. (And even there, I'd
| consider it good practice.)
|
| As a side bonus, lack of familiarity with Python type hints
| is a clear no-hire signal, which saves a lot of time.
| coldtea wrote:
| > _It 's a boon if the goal is to write code then go
| home. It's a loaded footgun if the goal is to compose a
| stack and run it in production within SLO._
|
| Never has been an issue in practice...
| stackskipton wrote:
| Ops type here, I've got multiple stories where devs have
| screwed up with typing and it's caused downstream
| problems.
| untrust wrote:
| Did you forget /s at the end of this?
|
| I work at big tech and the number of bad deploys and
| reverts I've seen go out due to getting types wrong is in
| the hundreds. Increased type safety would catch 99% of
| the reverts I've seen.
| almosthere wrote:
| Also have fun depending on libraries 10 years old as no
| one likes upgrades over fear of renames.
| Izkata wrote:
| Except Typescript embraces duck typing. You can say "accept
| any object with a quack() method", for example, and it'll
| accept an unexpected quacking parrot. It can even tell when
| two type definitions are close enough and merge them.
| pjmlp wrote:
| Kind of, depends on the compiler configuration.
| shepherdjerred wrote:
| Doesn't Go also use structural typing?
| jmholla wrote:
| So does Python. They're called protocols. [0]
|
| [0]: https://typing.python.org/en/latest/spec/protocol.html
| dragonwriter wrote:
| > Except Typescript embraces duck typing.
|
| So does Python:
|
| https://typing.python.org/en/latest/spec/protocol.html
| kketch wrote:
| They don't violate the spirit of the language. They are
| optional. They don't change the behaviour at runtime.
|
| Type annotations can seem pointless indeed if you are unwilling
| to learn how to use them properly. Using a giant union to type
| your (generic) function is indeed silly, you just have to make
| that function generic as explained in another comment or I
| guess remove the type hints
| pansa2 wrote:
| > _They don't violate the spirit of the language. They are
| optional._
|
| That in itself violates the spirit of the language, IMO.
| "There should be one obvious way to do it".
| graynk wrote:
| the whole language violates this principle tbh, so it's
| very in spirit
| tdeck wrote:
| Yeah that ship sailed some time before they added a third
| way to do templated string interpolation.
| kketch wrote:
| Well, precisely:
|
| - There is one obvious way to provide type hints for your
| code, it's to use the typing module provided by the
| language which also provides syntax support for it.
|
| - You don't have to use it because not all code has to be
| typed
|
| - You can use formatted strings, but you don't have to
|
| - You can use comprehensions but you don't have to
|
| - You can use async io, but you don't have to. But it's the
| one obvious way to do it in python
|
| The obvious way to annotate a generic function isn't with a
| giant Union, it's with duck typing using a Protocol +
| TypeVar. Once you known that, the obvious way is... pretty
| obvious.
|
| The obvious way not be bothered with type hints because you
| don't like them is not to use them!
|
| Python is full of optional stuff, dataclasses, named
| tuples, meta programming, multiple ancestor inheritance.
| You dont have to use these features, but there are only one
| way to use them
| zx8080 wrote:
| > but there are only one way to use them
|
| Optional nature of those features conflicts with this
| statement. As optionality means two ways already.
| preciousoo wrote:
| classes are optional in python, does that violate the
| spirit?
| TZubiri wrote:
| How so? There is one way to do it. If you want typing, you
| use type hints. You wouldn't say that, say, functions are
| unpythonic because you can either use functions or not use
| them, therefore there's two ways to do things, would you?
| bityard wrote:
| "There should only be one way to do it" has not really been
| a thing in Python for at least the last decade or longer.
| It was originally meant as a counterpoint to Perl's
| "there's more than one way to do it," to show that the
| Python developers put a priority on quality and depth of
| features rather than quantity.
|
| But times change and these days, Python is a much larger
| language with a bigger community, and there is a lot more
| cross-pollination between languages as basic philosophical
| differences between the most popular languages steadily
| erode until they all do pretty much the same things, just
| with different syntax.
| lexicality wrote:
| on that note, which is better, using `map()` or a generator
| expression?
| xzel wrote:
| And Python failed at that decades ago. People push terribly
| complicated, unreadable code under the guise of Pythonic. I
| disagree with using Pythonic as reasoning for anything.
| xzel wrote:
| And Python failed at that decades ago. People push terribly
| complicated, unreadable code under the guise of Pythonic. I
| disagree with using Pythonic as reasoning for anything.
| zelphirkalt wrote:
| Yeah, but then you get into the issues with when and where
| generic types are bound and narrowed, which can then make it
| more complicated, at which point one might be better off
| stepping back, redesigning, or letting go of perfect type
| hint coverage, for dynamic constructs, that one couldn't even
| write in another type safe language.
| yladiz wrote:
| Actually in Python it can. Since the type hints are
| accessible at runtime, library authors can for example change
| which values in kwargs are allowed based on the type of the
| argument.
|
| So on the language level it doesn't directly change the
| behavior, but it is possible to use the types to affect the
| way code works, which is unintuitive. I think it was a bad
| decision to allow this, and Python should have opted for a
| TypeScript style approach.
| kketch wrote:
| You can make it change the behaviour at runtime is
| different than it changes the behaviour at runtime I think?
|
| Lots of very useful tooling such as dataclasses and
| framework like FastAPI rely on this and you're opinion is
| that it's a bad thing why?
|
| In typescript the absence of type annotations reflection at
| runtime make it harder to implement things that people
| obviously want, example, interop between typescript and zod
| schemas. Zod resorts instead to have to hook in ts compiler
| to do these things.
|
| I'm honestly not convinced Typescript is better in that
| particular area. What python has opted for is to add first
| class support for type annotations in the language (which
| Javascript might end up doing as well, there are proposals
| for this, but without the metadata at runtime). Having this
| metadata at runtime makes it possible to implement things
| like validation at runtime rather than having to write your
| types in two systems with or without codegen (if Python
| would have to resort to codegen to do this, like its
| necessary in typescript, I would personally find this less
| pythonic).
|
| I think on the contrary it allows for building intuitive
| abstractions where typescript makes them harder to build?
| j1elo wrote:
| No idea about Python type system, but doesn't it have anything
| like this? interface IntIndexable {
| [key: number]: any }
| sdeframond wrote:
| It does!
|
| You can specify a protocol like this: class
| IntIndexable(Protocol[T]): def __getitem__(self,
| index: int, /) -> T: ...
|
| (Edit: formatting)
| j1elo wrote:
| The syntax is definitely harder to grasp but if the
| mechanism is there, I guess the parent poster's concern can
| be solved like that.
|
| Although I understant that it might have been just a
| simplified example. Usually the " _Real World_ " can get
| very complex.
| sdeframond wrote:
| > The syntax is definitely harder to grasp
|
| Yes it is. I believe the reason is that this is all valid
| python while typescript is not valid javascript. Also,
| python's type annotations are available at runtime (eg.
| for introspection) while typescript types aren't.
|
| That said, typescript static type system is clearly both
| more ergonomic and more powerful than Python's.
| tdeck wrote:
| I like Python a lot, and have been using it for personal
| projects since about 2010. It was only once I started working
| and encountering long-lived unfamiliar Python codebases
| regularly that I understood the benefits of type hints. It's
| not fun to have to trace through 5 or 6 different functions to
| try to figure out what type is being passed in or returned from
| something. It's even less fun to find out that someone made a
| mistake and it's actually two different incompatible things
| depending on the execution path.
|
| That era of Python codebases were miserable to work in, and
| often ended up in the poorly though out "we don't know how this
| works and it has too many bugs, let's just rewrite it"
| category.
| rlpb wrote:
| > It's not fun to have to trace through 5 or 6 different
| functions to try to figure out what type is being passed in
| or returned from something.
|
| My position is that what is intended must be made clear
| between type hints and the docstring. Skipping this makes for
| difficult to read code and has no place in a professional
| setting in any non-trivial codebase.
|
| This doesn't require type hints to achieve. :param and :rtype
| in the docstring are fine if type hints aren't present, or
| for complex cases, plain English in the docstring is usually
| better.
| tdeck wrote:
| I agree, although I've found that correct and comprehensive
| use of the doctoring for this purpose has not existed in
| the environments I've worked in, or the open source
| codebases I have needed to understand. Something about type
| hinting makes people more likely to do it.
| Balinares wrote:
| :param and :rtype _are_ type hints, just type hints that
| cannot be validated by tooling and are guaranteed to go out
| of sync with the code eventually.
|
| Proper type hints are typically very easy to add if the
| codebase is not a mess that passes things around far and
| wide with no validation. If it is, the problem is not with
| the type hints.
| boltzmann64 wrote:
| I am sorry, but whats wrong with doing something like,
| `print(type(var)); exit()` and just running it once instead
| of digging through 5-6 stack frames?
| TZubiri wrote:
| So the type is anything that implements the index function ([],
| or __getitem__), I thnink that's a Sequence, similar to
| Iterable.
|
| >from typing import Sequence
|
| >def third(something: Sequence):
|
| > return indexable[3]
|
| however if all you are doing is just iterate over the thing,
| what you actually need is an Iterable
|
| >from typing import Iterable
|
| >def average(something:Iterable):
|
| > for thing in something:
|
| > ...
|
| Statistically, the odds of a language being wrong, are much
| lower than the programmer being wrong. Not to say that there
| aren't valid critiques of python, but we must think of the
| creators of programming languages and their creations as the
| top of the field. If a 1400 chess elo player criticizes Magnus
| Carlsen's chess theory, it's more likely that the player is
| missing some theory rather than he found a hole in Carlsen's
| game, the player is better served by approaching a problem with
| the mentality that he is the problem, rather than the master.
| pansa2 wrote:
| > _we must think of the creators of programming languages and
| their creations as the top of the field_
|
| The people at the top of the type-system-design field aren't
| working on Python.
| bgwalter wrote:
| That is sort of ironic because the Pythonistas did not leave
| out any opportunity to criticize Java. Java was developed by
| world class experts like Gosling and attracted other type
| experts like Philip Wadler.
|
| No world class expert is going to contribute to Python after
| 2020 anyway, since the slanderous and libelous behavior of
| the Steering Council and the selective curation of allowed
| information on PSF infrastructure makes the professional and
| reputational risk too high. Apart from the fact that Python
| is not an interesting language for language experts.
|
| Google and Microsoft have already shut down several failed
| projects.
| TZubiri wrote:
| >"Guido: Java is a decent language," 1999
|
| I get the idea that Python and Java went in opposite
| directions. But I'm not aware of any fight between both
| languages. I don't think that's a thing either.
|
| Regarding stuff that happens in the 2020. Python was
| developed in the 90s, python 3 was launched in 2008.
| Besides some notable PEPs like type hints, WSGI, the rest
| of development are footnotes. The same goes for most
| languages (with perhaps the exception of the evergrowing
| C++), languages make strong bc guarantees and so the bulk
| of their innovation comes from the early years.
|
| Whatever occurs in the 20th and 30th year of development is
| unlikely to be revolutionary or very significant.
| Especially ignoreable is the drama that might emerge in
| these discussions, slander, libel inter-language criticism?
|
| Just mute that out. I've read some news about some
| communities like Ruby on Rails or Nix that become overtaken
| by people and discussions of political nature rather than
| development, they can just be ignored I think.
| anankaie wrote:
| > Google and Microsoft have already shut down several
| failed projects
|
| Could you elaborate on this?
| bgwalter wrote:
| Sure: Google fired the Python language team in 2024 that
| contained a couple of the worst politicians who were
| later involved in slandering Tim Peters.
|
| Before that, Google moved heavily from Python to Go.
|
| Microsoft fired the "Faster CPython Team" this year.
| coldtea wrote:
| > _you better believe that every single admissible type will
| eventually be fed to this function_
|
| That's your problem right there. Why are random callers sending
| whatever different input types to that function?
|
| That said, there are a few existing ways to define that
| property as a type, why not a protocol type "Indexable"?
| knome wrote:
| >why not a protocol type
|
| it was a sin that python's type system was initially released
| as a nominal type system. they should have been the target
| from day one.
|
| being unable to just say "this takes anything that you can
| call .hello() and .world() on" was ridiculous, as that was
| part of the ethos of the dynamically typed python ecosystem.
| typechecking was generally frowned upon, with the idea that
| you should accept anything that fit the shape the receiving
| code required. it allowed you to trivially create resource
| wrappers and change behaviors by providing alternate objects
| to existing mechanisms. if you wanted to provide a fake file
| that read from memory instead of an actual file, it was
| simple and correct.
|
| the lack of protocols made hell of these patterns for years.
| marcosdumay wrote:
| AFAIK, Python is missing a fully-featured up to date
| centralized documentation on how to use type annotations.
|
| The current docs are "Microsoft-like", they have
| everything, spread through different pages, in different
| hierarchies, some of them wrong, and with nothing telling
| you what else exists.
| david422 wrote:
| Yes. It's not the type system that's broken, it's the design.
| Fix the design, and the type system works for you, not
| against you.
| oivey wrote:
| > That's your problem right there. Why are random callers
| sending whatever different input types to that function?
|
| Because it's nice to reuse code. I'm not sure why anyone
| would think this is a design issue, especially in a language
| like Python where structural subtyping (duck typing) is the
| norm. If I wanted inheritance soup, I'd write Java.
|
| Ironically, that's support for structural subtyping is why
| Protocols exist. It's too bad they aren't better and the
| primary way to type Python code. It's also too bad that
| TypedDict actively fought duck typing for years.
| dragonwriter wrote:
| > Why are random callers sending whatever different input
| types to that function?
|
| Probably because the _actual_ type it takes is well-
| understood (and maybe even documented in informal terms) by
| the people making and using it, but they just don't
| understand how to express it in the Python type system.
| zenkey wrote:
| In my experience, the right tooling makes Python typing a big
| win. Modern IDEs give comprehensive real-time feedback on type
| errors, which is a big productivity boost and helps catch
| subtle bugs early (still nowhere near Rust, but valuable
| nonetheless). Push it too far though, and you end up with
| monsters like Callable[[Callable[P, Awaitable[T]]],
| TaskFunction[P, T]]. The art is knowing when to sprinkle types
| just enough to add clarity without clutter.
| ddavis wrote:
| When you hit types like that type aliases come to the rescue;
| a type alias combined with a good docstring where the alias
| is used goes a long way
| sevensor wrote:
| I don't know anything about your jit compiler, but generally
| the value I get from type annotations has nothing to do with
| what they do at runtime. People get so confused about Python's
| type annotations because they resemble type declarations in
| languages like C++ or Java. For the latter, types tell the
| compiler how to look up fields on, and methods that apply to,
| an object. Python is fine without that.
|
| Python's types are _machine-checkable constraints on the
| behavior of your code._. Failing the type checker isn't fatal,
| it just means you couldn't express what you were doing in terms
| it could understand. Although this might mean you need to
| reconsider your decisions, it could just as well mean you're
| doing something perfectly legitimate and the type checker
| doesn't understand it. Poke a hole in the type checker using
| Any and go on with your day. To your example, there are several
| ways described in comments by me and others to write a succinct
| annotation, and this will catch cases where somebody tries to
| use a dict keyed with strings or something.
|
| Anyway, you don't have to burn a lot of mental energy on them,
| they cost next to nothing at runtime, they help document your
| function signatures, and they help flag inconsistent
| assumptions in your codebase even if they're not airtight.
| What's not to like?
| gostsamo wrote:
| why not a protocol with getitem with an int arg?
| oivey wrote:
| I feel pretty similarly on this. Python's bolted on type system
| is very poor at encoding safe invariants common in the
| language. It's a straight jacketed, Java-style OOP type system
| that's a poor fit for many common Python patterns.
|
| I would love it if it were better designed. It's a real downer
| that you can't check lots of Pythonic, concise code using it.
| humdaanm wrote:
| the issue of having multiple inputs able to be indexable by
| ints, is exactly why i prefer that type hints remain exactly as
| "hints" and not as mandated checks. my philosophy for type
| hints is that they are meant to make codebases easier to
| understand without getting into a debugger. their functional
| equivalence should be that of comments. it's a cleaner more
| concise way of describing a variable instead of using a full on
| docstring.
|
| though maybe there's a path forward to give a variable a sort
| of "de-hint" in that in can be everything BUT this type(i.e. an
| argument can be any indexable type, except a string)
| true_blue wrote:
| >though maybe there's a path forward to give a variable a
| sort of "de-hint" in that in can be everything BUT this type
|
| I think this is called a negation type, and it acts like a
| logical NOT operator. I'd like it too, and I hear that it
| works well with union types (logical OR) and intersection
| types (logical AND) for specifying types precisely in a
| readable way.
| lucasyvas wrote:
| This is like saying you don't like nails because you don't
| understand how to use a hammer though. Developers are not
| understanding how to use the hints properly which is causing
| you a personal headache. The hints aren't bad, the programmers
| are untrained - the acknowledgement of this is the first step
| into a saner world.
| jonas21 wrote:
| > _eventually the list will become silly and the function will
| earn a # pyre-ignore annotation. This defeats the whole point
| of the pointless exercise._
|
| No, this is the great thing about gradual typing! You can use
| it to catch errors and provide IDE assistance in the 90% of
| cases where things have well-defined types, and then turn it
| off in the remaining 10% where it gets in the way.
| bartread wrote:
| > The reason is that they are not really a part of the
| language, they violate the spirit of the language
|
| This is a good way of expressing my own frustration with
| bolting strong typing on languages that were never designed to
| have it. I hate that TypeScript has won out over JavaScript
| because of this - it's ugly, clumsy, and boilerplatey - and I'd
| be even more disappointed to see the same thing happen to the
| likes of Python and Ruby.
|
| My background is in strongly typed languages - first C++, then
| Java, and C# - so I don't hate them or anything, but nowadays
| I've come to prefer languages that are more sparing and
| expressive with their syntax.
| mhitza wrote:
| Sounds like the ecosystem needs an "indexable" type annotation.
| Make it an "indexable<int>" for good measure.
| theptip wrote:
| Right, this was my thought.
|
| Can't you just use a typing.Protocol on __getitem__ here?
|
| https://typing.python.org/en/latest/spec/protocol.html
|
| Something like from typing import Protocol
| class Indexable(Protocol): def __getitem__(self,
| i: int) -> Self: ...
|
| Though maybe numpy slicing needs a bit more work to support
| nbadg wrote:
| Indeed.
|
| IMO, the trick to really enjoying python typing is to
| understand it on its own terms and really get comfortable
| with generics and protocols.
|
| That being said, especially for library developers, the
| not-yet-existant intersection type [1] can prove
| particularly frustrating. For example, a very frequent
| pattern for me is writing a decorator that adds an
| attribute to a function or class, and then returns the
| original function or class. This is impossible to type hint
| correctly, and as a result, anywhere I need to access the
| attribute I end up writing a separate "intersectable" class
| and writing either a typeguard or calling cast to
| temporarily transform the decorated object to the
| intersectable type.
|
| Also, the second you start to try and implement a library
| that uses runtime types, you've come to the part of the map
| where someone _should_ have written HERE BE DRAGONS in big
| scary letters. So there 's that too.
|
| So it's not without its rough edges, and protocols and
| overloads can be a bit verbose, but by and large once you
| really learn it and get used to it, I personally find that
| even just the value of the annotations as documentation is
| useful enough to justify the added work adding them.
|
| [1] https://github.com/python/typing/issues/213
| burnerRhodov2 wrote:
| You explained some hyper niche instance where type hints should
| be ignored. 99% of the time, they are extremely helpful.
| fyrn_ wrote:
| You can use a Protocol type for that, makes a lot mote sense
| than nominal typing for typing use case.
| vjerancrnjak wrote:
| Exactly, sounds like misuse of unions.
|
| Although Python type hints are not expressive enough.
| the__alchemist wrote:
| I like your point! I think the advantage in its light is this:
| People often use Python because it's convention in the domain,
| the project already uses it, or it's the language the rest of
| the team uses. So, you are perhaps violating the spirit, but
| that's OK. You are making the most of tools available. It's not
| the Platonic (Pythonic??) ideal, but good enough.
| bobbiechen wrote:
| Isn't this supported by typing.SupportsIndex?
| https://docs.python.org/3/library/typing.html#typing.Support...
|
| Mind you, I haven't used it before, but it feels very similar
| to the abstract Mapping types.
| detaro wrote:
| __index__ is not what you think it is
| bobbiechen wrote:
| Oops, thanks for the correction. That's on me for drive-by
| commenting.
| thrance wrote:
| For this very specific example, isn't there something like
| "Indexable[int]"?
| nurettin wrote:
| Why not do Indexable = Any and pass that? Even if it doesn't
| help your jit or the IDE, at least it is more explicit than
| def lol(blarg): # types? haha you wish. rtfc you poor sod.
| Pytharn spirit ftw!!! ... return
| omg[0].wtf["lol freedom"].pwned(Good.LUCK).figuring * out
| jlnthws wrote:
| Use them for what they are (hints, documentation). Use it for
| gradual typing when implementation makes it hard to understand
| return or parameters types. But don't enforce it across your code
| base, use another language or another mindset instead.
| ktosobcy wrote:
| I liked python in my early days because it felt simple and easy
| and when I tried other languages having to deal with types felt
| so annoying... but then I grew and had to work with bigger
| codebases and guess what - having types (and static type checking
| during compilatin) helps A LOT... :)
| physicsguy wrote:
| I like it but in my experience a lot of teams use them loosely
| without a type checker, more for understanding than for
| correctness. Reason for that is largely that it can be difficult
| to make the checkers happy...
| procaryote wrote:
| I like the type hints. The're not perfect and they've changed a
| lot between versions, but they really help catch issues early
| that you'd usually need to write unit tests for. Adding type
| hints is easier than writing those unit tests.
|
| Then you can focus your tests on more interesting things
|
| You just need to set your build up to actually do the checking as
| type hints by default are just documentation
| setopt wrote:
| My main complaint about them is no first-party support for type
| checking, you need external packages like beartype decorators.
| procaryote wrote:
| Yeah, it would have been much better to have them be default
| enforces if present. Keeping them optional is fine, but I
| don't get the use-case for "you can add them but not check
| them"... that just leads to actively misleading hints
| zelphirkalt wrote:
| Python's dynamic nature can make it quite difficult to express
| some things correctly. That, or the type checkers have issues
| when it comes to understanding what would be considered safe in
| other languages. Years ago when I knew far less about types and
| programming, I never had such problems in for example Java. It
| was sometimes stupid, but I always found a way to express things.
| Although it could also be, that I merely want more out of
| inference and and safety. For example recently I wanted a
| pipeline of steps, but the steps could have any input and output
| type, as long as that type aligns with the previous step's types
| and the type checker should also know what the final output type
| is, and I additionally wanted it to work so that I don't have to
| add all the steps at once, so that I can construct the pipeline
| step by step. Tried for hours, but didn't find a working solution
| that type checks. Also tried with the help of LLMs, which gave
| superficially looking great code for this, but then there was
| always some type error somewhere, and they struggled to fix that.
| Ultimately, I gave up on the type checking between steps and
| output type of the pipeline, as I realized, that I invested hours
| into something that might be impossible or way waaay too much
| work for what I get from it. I would not have spent any time on
| this without type annotating and would have simply gone with a
| dynamic solution.
| whilenot-dev wrote:
| That doesn't sound like it'd have something to do with the
| dynamic nature of python. Type checking is a static analysis of
| the source code, so if you'd want something to be inferred
| dynamically, then you'll have to make use of generics:
| from typing import Callable class
| Pipeline[T]: def __init__(self, value: T) -> None:
| self._value = value def step[U](self, cb:
| Callable[[T], U]) -> 'Pipeline[U]': return
| Pipeline(cb(self._value)) def terminate(self) ->
| T: return self._value def
| _float_to_int(value: float) -> int: return int(value)
| def _int_to_str(value: int) -> str: return str(value)
| def main() -> None: result = Pipeline(3.14)\
| .step(_float_to_int)\ .step(_int_to_str)\
| .terminate() print(result)
| if __name__ == '__main__': main()
|
| You could further constrain the generic type through type
| variables:
| https://docs.python.org/3/library/typing.html#typing.TypeVar
| zelphirkalt wrote:
| I think this pipeline implementation does some things
| different from what I wanted (but did not precisely describe.
| It seems that each step is run right away, as it is "added",
| rather than collected and run when `terminate` is called.
| Also each step can only consume the result of the previous
| step, not the results of earlier steps. This can be worked
| around, by ending the pipeline and then starting multiple
| pipelines from the result of the first pipeline, if needed. I
| think you would need to import Generic and write something
| like `class Pipeline(Generic[T]):` as well? Or is `class
| Pipeline[T]:` a short form of that?
|
| In my experiment I wanted to get a syntax like this:
| pipeline = Pipeline() ...some code here...
| pipeline.add_step(Step(...some meta data..., ...actual
| procedure to run...))
|
| So then I would need generics for `Step` too and then
| Pipeline would need to change result type with each call of
| `add_step`, which seems like current type checkers cannot
| statically check.
|
| I think your solution circumvents the problem maybe, because
| you immediately apply each step. But then how would the
| generic type work? When is that bound to a specific type?
| whilenot-dev wrote:
| > Or is `class Pipeline[T]:` a short form of that?
|
| Yes, since 3.12.
|
| > Pipeline would _need to change result type_ with each
| call of `add_step`, which seems like current type checkers
| cannot statically check.
|
| Sounds like you want a dynamic type with your
| implementation (note the emphasis). Types shouldn't change
| at runtime, so a type checker can perform its duty. I'd
| recommend rethinking the implementation.
|
| This is the best I can do for now, but it requires an
| internal cast. The caller side is type safe though, and the
| same principle as above applies: from
| functools import reduce from typing import cast,
| Any, Callable, Mapping, TypeVar def
| _id_fn[T](value: T) -> T: return value
| class Step[T, U]: def __init__(
| self, metadata: Mapping[str, Any],
| procedure: Callable[[T], U], ) -> None:
| self._metadata = metadata self._procedure =
| procedure def run(self, value: T) -> U:
| return self._procedure(value)
| TInput = TypeVar('TInput') class
| Pipeline[TInput, TOutput = TInput]: def
| __init__( self, steps:
| tuple[*tuple[Step[TInput, Any], ...], Step[Any, TOutput]] |
| None = None, ) -> None:
| self._steps: tuple[*tuple[Step[TInput, Any], ...],
| Step[Any, TOutput]] = ( steps or
| (Step({}, _id_fn),) )
| def add_step[V](self, step: Step[TOutput, V]) ->
| 'Pipeline[TInput, V]': steps = (
| *self._steps, step, )
| return Pipeline(steps) def run(self,
| value: TInput) -> TOutput: return cast(
| TOutput, reduce(
| lambda acc, val: val.run(acc),
| self._steps, value,
| ), ) def
| _float_to_int(value: float) -> int: return
| int(value) def _int_to_str(value: int) ->
| str: return str(value) def
| main() -> None: step_a = Step({},
| _float_to_int) step_b = Step({}, _int_to_str)
| foo = Pipeline[float]()\ .add_step(step_a)\
| .add_step(step_b)\ .run(3.14)
| print(foo) bar = Pipeline[float]()\
| .run(3.14) print(bar) if
| __name__ == '__main__': main()
| zelphirkalt wrote:
| Thanks for your efforts. I didn't expect and couldn't
| expect anyone to invest time into trying to make this
| work. I might try your version soon.
| ksynwa wrote:
| How do type hints work if for example you import a library that
| has not implemented type hints into your project in which you
| hope to have type hints? Do you just manually assign types to the
| outputs of this library?
| geenat wrote:
| Company selling a product based on what's being glazed in the
| article.
|
| It's always a small vocal fraction or they'd be using a different
| language.
| davidatbu wrote:
| I doubt that Meta (the company that sponsors the work on
| pyrefly) is looking forward to selling a product based on
| Python typing (assuming that's what's "what's being glazed in
| the article").
| storus wrote:
| They are optional until Pydantic is forced on you by some
| required library.
| dvcoolarun wrote:
| I believe types are a great way to encourage good practices with
| relatively little investment. They provide type-safety, act as
| living documentation, and add an extra layer of protection in
| production.
|
| However, in a large codebase, consistency can become a challenge.
| Different developers often approach the same problem in different
| ways, leading to a mix of type patterns and styles, especially
| when there's no clear standard or when the problem itself is
| complex.
|
| With the rise of LLM-generated code, this issue becomes even more
| pronounced -- code quality and craftsmanship can easily degrade
| if not guided by proper conventions.
| totalhack wrote:
| It's optional, and that's great, because its necessity or benefit
| is situational.
| sota_pop wrote:
| Python types - all the onus of static types, with none of the
| performance!
|
| I enjoy packages like pydantic and SOME simple static typing, but
| if I'm implementing anything truly OOP, I wouldn't first reach
| for Python anyway; the language doesn't even do multiple
| constructors or public/private props.
|
| Edit: as a side note, I was interested to learn that for more
| verbose type specification, it's possible to define a type in
| variable-like syntax at the top: mytype = int|str|list|etc.
| the__alchemist wrote:
| There is an important (I would say primary) benefits of types
| that isn't performance: it's making a program structure [you |
| your IDE | LLMs] can reason about.
| sota_pop wrote:
| Agreed, it definitely improves my experience when the
| compiler "knows" the variable types.
| coldtea wrote:
| One shouldn't be implementing anything "trully OOP" to begin
| with...
| sota_pop wrote:
| Quotes speak louder than words... However it's hard to say
| "what one should or shouldn't" be implementing in general
| terms.
| __MatrixMan__ wrote:
| What does "multiple constructors" buy you that you can't get
| from multiple static methods that return an object of the
| enclosing class's type.
|
| Maybe I'm missing out on something cool...
| sota_pop wrote:
| Perhaps just a fuzzy feeling. I suppose I haven't tried using
| static methods for that purpose. Will give it a shot!
| blibble wrote:
| I find the type hints harder and slower than java/C/...
|
| try typing a decorator, or anything using file IO
|
| I find it extremely difficult, if not impossible, and I did
| type theory
|
| (the type checkers being really, really stupid doesn't help
| either)
| sevensor wrote:
| So don't? Just annotate the stuff that's not annoying. I
| agree, IO is annoying to type. Decorators are fine, it's just
| a function that returns a function. It's still a win, however
| much you decide to annotate.
| grumbel wrote:
| The most annoying part is that the type checking exists outside
| the regular runtime. I constantly run into situation where the
| type checker is happy, but the thing explodes at runtime or the
| type checker keeps complaining about working code. And
| different type checkers will even complain about different
| things regularly too. It's a whole lot of work making every
| part of the system happy and the result still feels extremely
| brittle.
| throwaway106382 wrote:
| Ruby doesn't have multiple constructors and literally
| everything in Ruby is an object so it's partically impossible
| to avoid "doing OOP". I don't see how being "truely OOP" has
| anything to do with the language supporting method overloads.
| marcosdumay wrote:
| > with none of the performance!
|
| If you care about micro-optimizations, the first one that
| overwhelms everything else is to not use Python.
|
| Anyway, if your types are onerous, you are using them wrong.
| Even more in a progressive type system where you always have
| the option of not using them or putting an "Any" there.
| coldtea wrote:
| More likely "Python developers phone-in AI code that uses type
| hints".
| lupusreal wrote:
| Types are invaluable in modern code bases because they end up
| saving a ton of tokens when agentic coding tools are trying to
| comprehend let alone modify the code. Python isn't intrinsically
| a great language for LLMs to work with, except in practice it is
| because they've had a great deal of training data for python.
| Type hints help a lot with this.
| pif wrote:
| Only lazy and lame developers can prefer dynamic type.
| DarkNova6 wrote:
| Shocker. Static typing wins once again.
| david422 wrote:
| I used python on a large code base for quite a while. Many team
| members did not like type hints, and a codebase that doesn't
| maintain type hints makes it harder to use them.
|
| However, if I had a choice, rather than use typehints in python,
| I would much rather just use a statically typed language. Short,
| tiny scripts in python? Sure. Anything that grows or lives a long
| time? Use something where the compiler helps you out.
| olokobayusuf wrote:
| I'm founding a company that is building an AOT compiler for
| Python (Python -> C++ -> object code) and it works by propagating
| type information through a Python function. That type propagation
| process is seeded by type hints on the function that gets
| compiled:
|
| https://blog.codingconfessions.com/i/174257095/lowering-to-c...
| franktankbank wrote:
| Have you talked to anyone about where this flat out will not
| work? Obviously it will work in simple cases but someone with
| good language understanding will probably be able to point out
| cases where it just won't. I didn't read your blog so apologies
| if this is covered. How does this compiler fit into your
| company business plan?
| olokobayusuf wrote:
| Our primary use case is cross-platform AI inference
| (unsurprising), and for that use case we're already in
| production by startups to larger co's.
|
| It's kind of funny: our compiler currently doesn't support
| classes, but we support many kinds of AI models (vision, text
| generation, TTS). This is mainly because math, tensor, and AI
| libraries are almost always written with a functional
| paradigm.
|
| Business plan is simple: we charge per endpoint that
| downloads and executes the compiled binary. In the AI world,
| this removes a large multiplier in cost structure (paying per
| token). Beyond that, we help co's find, eval, deploy, and
| optimize models (more enterprise-y).
| franktankbank wrote:
| I understood some of it. Sounds reasonable if your market
| already is running a limited subset of the language, but I
| guess there is a lot of custom bullshit you actually wind
| up maintaining.
| olokobayusuf wrote:
| Yup that's true. We do benefit from massive efficiencies
| though, thanks to LLM codegen.
| loglog wrote:
| This sounds even worse than Modular/Mojo. They made their
| language look terrible by trying to make it look like Python,
| only to effectively admit that source compatibility will not
| really work any time soon. Is there any reason to believe that
| a different take on the same problem with stricter source
| compatibility will work out better?
| throwaway106382 wrote:
| Ruby has had static typing via RBS for a while now, and I don't
| know if it's because I'm primarily a Rails developer and DHH
| doesn't like static typing so using these with Rails feels third-
| class or maybe just that I'm really just all the way in "the ruby
| way" but it feels antithetical to a dynamically typed language to
| start shoehorning in static types. Even as a type definition in a
| separate file it just feels wrong.
|
| Ruby particularly is already strongly typed so there isn't too
| many suprises with automatic conversions or anything like that.
| RBS also just makes metaprogramming more annoying - and Ruby's
| ability to do metaprogramming easily is one of its biggest
| strengths in my opinion.
|
| If I wanted a statically typed language I would just use a
| statically typed language.
| tedivm wrote:
| I've been working with Python for years (since 2014) and typing
| makes the code less buggy and easier to maintain. I also would
| hardly call it "shoehorning", as years of design went into it.
|
| Honestly the only people I see who really push back against it
| are the people who haven't bothered learning it. Once people
| use it for a bit, in my experience at least, they don't want to
| go back.
| throwaway106382 wrote:
| Maybe it's just because Python is just kindof a lousy
| language to use in the first place. I started with Java and
| C++, did Python for a bit and switched to Ruby and never
| looked back. Being forced to use Python for anything feels
| like a punishment.
|
| Years of design also went into Ruby's type system, and for
| the people that enjoy it - be my guest - but I would never
| use it for my own code.
| vintagedave wrote:
| My permanent instructions to Claude are:
|
| * Always strongly type, for local variables, method parameters,
| and return types
|
| * Avoid Any unless absolutely required
|
| * hasattr() and get() are often code smells; if the type can be
| known, use that type
|
| * Use beartype for all methods.
|
| I _love_ beartype and want to plug it to everyone on HN:
| https://github.com/beartype/beartype
|
| I'm building my own coding agent, like Claude, and it is built
| with opinionated style. Strongly typing Python and using beartype
| are what it will try to do unless the user specifies otherwise.
| lend000 wrote:
| Not willingly, but it's a lost cause getting AI generated code to
| avoid it.
| beebmam wrote:
| I just don't see why people use Python in the AI era. Statically
| typed languages help AI reason about code enormously during
| compilation.
| pedrellimath wrote:
| Python is amazing for that reason. You choose whether you want to
| do it or not.
| notatoad wrote:
| an underrated benefit of type hints is how much better my copilot
| autocompletions are on type hinted code.
| rao-v wrote:
| I'd love to see an analysis of how much typing hurts LLMs that
| need to read / edit your code (due to increased context) vs helps
| (due to more clear type context).
|
| I want to believe that corrected typed python code is easier for
| smaller models to generate / interact with, but who knows how the
| trade-offs actually work out.
| _alternator_ wrote:
| The reason to use type hints is simple: it vastly improves
| scalability, making LLM agents much less error prone. Try it:
| tell Claude to type hint every function (e.g., in your Claude.md
| file) and see how much easier it is to scale your agents.
|
| This also works for humans, but many python programmers who
| learned python before type hints can't be bothered. :sad_panda:
| dajonker wrote:
| A dynamic language with type hints has all of the disadvantages
| of a dynamic language with all the disadvantages of a static
| language on top of it.
___________________________________________________________________
(page generated 2025-09-28 23:01 UTC)