Hacker News new | ask | show | jobs
by cogman10 5 days ago
It's not an all or nothing thing.

I think types are particularly valuable for libraries. A library author using copious types really helps the downstream user to know "Ok, this function returns a dict(Foo, Bar)". But after that, it's a matter of preference if you want to add those types to your own code or not.

Having the types in the libraries makes it a lot easier for your tools/IDEs to give good suggestions and catch bugs that you might otherwise miss.

4 comments

Yes, where would I be without the _RelationshipBackPopulatesArgument type of

        sqlalchemy.orm.relationship(argument: _RelationshipArgumentType[Any] | None = None, secondary: _RelationshipSecondaryArgument | None = None, *, uselist: bool | None = None, collection_class: Type[Collection[Any]] | Callable[[], Collection[Any]] | None = None, primaryjoin: _RelationshipJoinConditionArgument | None = None, secondaryjoin: _RelationshipJoinConditionArgument | None = None, back_populates: _RelationshipBackPopulatesArgument | None = None, order_by: _ORMOrderByArgument = False, backref: ORMBackrefArgument | None = None, overlaps: str | None = None, post_update: bool = False, cascade: str = 'save-update, merge', viewonly: bool = False, init: _NoArg | bool = _NoArg.NO_ARG, repr: _NoArg | bool = _NoArg.NO_ARG, default: _NoArg | _T = _NoArg.NO_ARG, default_factory: _NoArg | Callable[[], _T] = _NoArg.NO_ARG, compare: _NoArg | bool = _NoArg.NO_ARG, kw_only: _NoArg | bool = _NoArg.NO_ARG, hash: _NoArg | bool | None = _NoArg.NO_ARG, lazy: _LazyLoadArgumentType = 'select', passive_deletes: Literal['all'] | bool = False, passive_updates: bool = True, active_history: bool = False, enable_typechecks: bool = True, foreign_keys: _ORMColCollectionArgument | None = None, remote_side: _ORMColCollectionArgument | None = None, join_depth: int | None = None, comparator_factory: Type[RelationshipProperty.Comparator[Any]] | None = None, single_parent: bool = False, innerjoin: bool = False, distinct_target_key: bool | None = None, load_on_pending: bool = False, query_class: Type[Query[Any]] | None = None, info: _InfoType | None = None, omit_join: Literal[None, False] = None, sync_backref: bool | None = None, dataclass_metadata: _NoArg | Mapping[Any, Any] | None = _NoArg.NO_ARG, \*kw: Any) → _RelationshipDeclared[Any]*
It's not for you, it's for your IDE. And if you aren't using an IDE then you can pretty much ignore it anyways.

You are in exactly the same position as if you knew or didn't know that type.

If you're not using and IDE nor an LLM
>> I think types are particularly valuable for libraries.

> Yes, where would I be without the _RelationshipBackPopulatesArgument type of ...

(proceeds to list a signature with over 40 parameters)

You would be left wondering which of the 40+ arguments provided to a given invocation is not what was allowed without a compiler to tell you.

Have fun tracking down which one, or ones, is causing the problem.

What function signature isn't going to look messy with 36 keyword arguments.

https://github.com/sqlalchemy/sqlalchemy/blob/0798e6cbe11b30...

Part of it is due to the clunky `_NoArg.NO_ARG` business for optional params. Pretty-printing it would also go a long way, but that technology seems too advanced for any language circa 2026.
This is a big part of the reason that I've embraced ths sqlc (d/re)evolution.

Writing queries in sql and then generating for the target language also provides a flexibility that has reduced rewrite cost. Add to this ease of organization and layoit, and I'm not going back.

It's probably hard to come up with something messier than SqlAlchemy here. Not an expert, but spent more than enough time spelunking queries in the debugger. I much prefer bugs that can be surfaced at compile-time rather than run-time.
_RelationshipBackPopulatesArgument = Union[ str, PropComparator[Any], Callable[[], Union[str, PropComparator[Any]]], ]
I do think it is somewhat of an all or nothing thing. I can write dynamic languages, sure; I prefer having static types, but I have written a lot of dynamically typed code. However if I'm working in an editor with LSP integration, the experience is much worse when some things are missing types.

As an example, I may have a variable with types:

    const something = somelibrary.getSomething();
and I can type `something.` and see methods and properties. However, if my own code doesn't use types consistently, it's so easy to lose type info. For example:

    const something = someWrapper(someLibrary.getSomething())
or:

    function doSomethingWith(something) {
        ...
    }
    doSomethingWith(someLibrary.getSomething()
or any number of other patterns which accidentally strips type info from the variable if you don't use types everywhere.

I would much rather have a language where the compiler complains if some variable doesn't have a static type, than a language where I can accidentally leave something untyped. I don't understand which case I would want a variable or function to not have associated static type information.

> It's not an all or nothing thing.

It kind of is? All the partial-typing systems are too complex and usually broken in various ways. Compare to eg Elm or Gleam which are typed and super simple.

It kind of isn't. We are talking about using types in type optional languages. We aren't talking about the quality of those type systems or whether or not they are good type systems.

If I was comparing type systems then it'd be relevant to talk about statically typed languages like Elm or Gleam.

This is even worse because you attempt to try to sell why types SOMETIMES make sense. But you aim with this for a language that did not have nor need types to begin with. People don't seem to understand that this is an issue.

The library-situation is really not different from having types everywhere, and some people will do that too.

> catch bugs that you might otherwise miss.

People repeat this a lot. In about 22 years of writing ruby code, I have never ran into a situation once where I would have caught a bug through types. I don't understand why people keep on repeating this. Repetition does not make it anymore true.

Think in the opposite way: if types would have been necessary to begin with, why would ruby have been successful back in 2006? It was successful without types already. And types were never needed - they came because some people THINK they are needed. This is the biggest problem - the thinking part. They think they are right and all who do not use types, must be wrong and very foolish people.

Have you considered these people in general aren't some outsiders out to attack you or your favorite language?

The people who do end up making and using type checkers are people who have or are actively using these dynamic languages and found out that they CAN help THEM with preventing bugs.

Also, really? 22 years in which not one type-related error happened? Never? I don't want to say I don't believe you, but I really don't.

> In about 22 years of writing ruby code, I have never ran into a situation once where I would have caught a bug through types

You must be the world's greatest programmer with perfect memory. Every nil pointer exception is a bug a (good) type checker could have caught. You've never had a NameError or NoMethodError in Ruby?

This is perhaps the least believable comment I have seen on HN, ever. It would be more believable for someone using C to say "In about 22 years of writing C code. I have never ran into a memory bug".
This is not as uncommon as you may think.

Avoiding "memory bugs" in C is trivial, but tedious, so too many C programmers fail to use an appropriate programming style. Nonetheless, there are some who have never encountered a "memory bug" in programs written by them.

I agree that a programming language should enforce such features, instead of counting on competent programmers.

SRE here, I've had multiple outages caused by lack of typing in both Ruby and Python where bad types get passed, something doesn't catch it and either data corruption or constant crashes. Couple cost us big money because it screwed up billing and we were forced to eat the billing cost.
>In about 22 years of writing ruby code, I have never ran into a situation once where I would have caught a bug through types.

I've definitely ran into that although much less common at places with good test discipline.

I think the related and often conflated problem is errors caught by compilers which you don't hit til runtime in Ruby/Python without good test coverage. For example, referencing an undefined variable

> In about 22 years of writing ruby code, I have never ran into a situation once where I would have caught a bug through types.

In 22 years you have never seen `nil` show up in places it wasn't expected? Really?

Your app didn't silently break when you upgrade rails or any other gem?

If ruby was statically typed the typechecker would have caught it.