← Back to context

Comment by eloisius

1 year ago

Of course I’ve used an IDE before. I still prefer Vim to an IDE. And I enjoy writing typed languages in Vim because the compiler catches mistakes.

I agree part of the problem is cultural. Maybe a bunch of Python coders are eager to use types, or maybe linters are pushing them to type every last variable because that is “right.” I don’t know.

I don’t hate typed languages at all. In fact I love writing Rust. Even C++ is tolerable from a type perspective. I don’t agree that _RelationshipJoinConditionArgument is a meaningful type. It feels like bolting a type system onto the language after the fact is weird and necessitates crazy types like that to make some linter happy, maybe to make VS Code users happy, at the expense of readability.

You can run mypy as the Python equivalent of the typey bit of a compiler.

As for SQLAlchemy, I wouldn't assume that the object model would be particularly different in any other OO language for the problem it's solving.

> _RelationshipJoinConditionArgument

Is it particularly different from Rust's unusual types like `Map<Chain<FromRef<Box dyn Vec<Foo>>>>>` that you can get when doing chained operations on iterators?

Protocol/Trait based typing necessitates weird names for in-practice traits/protocols that are used.

Edit: IDK why that function signature is that ridiculous, reformatting it as:

    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: str | 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, 
        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, 
        **kw: Any
    ) → Relationship[Any]

It's 2-3 expected arguments and then ~30 options (that are all like Optional[bool] or Optional[str] to customize the relationship factory. Types like `_ORMColCollectionArgument` do stick out, but they're mainly there because these functions accept `Union[str, ResolvedORMType]` and will convert some sql string to a resolved type for you, and like, this is an ORM, there are going to be some weird ORM types.

It definitely seems to be a target audience issue. I use VS code and MyPy regularly catches mistakes, some of which would have been fairly subtle.

I have MyPy and Ruff going all the time and generally aim for zero linter errors.