Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

That's what you get from duck typing.

Python API are defined solely by how the API uses its argument. The requirement is already encoded as far as the computer is concerned, except the check are by default all done at run-time. A Python compiler could work its way backward to try to verify them at compilation time. Making them explicit would solely be as a helper for the programmer, which might as well just be in straight documentation, which can ba as brief as the name of the parameter.

It's all a feature, and this is being actively exploited in code, providing exceptional flexibility. Its no worse than other language with type inference: their types can be extremely complex and reading them would not help most of the time. You're better off with a succint, high-level description, like a URL-like string, a file-like object, an object indexable by such and such.



Well, the problem is on annotating types, when you only actually care about behavior.

Duck typing isn't a bad thing. In fact, it's great. You just need to annotate the ducks instead of the types. For a great example of how to do it, look at Haskell's type classes.

(In fact, Haskell's easyness of integrating generic code is visible even to a beginner, but I never notice that this is because the entire language is based on duck typing.)


To be pedantic, Haskell technically doesn't use duck typing, it uses structural typing. Duck typing is run-time coercion of types, structural typing is compile-time inference of minimum interfaces.


Noticed.

Interface based typing may be a better generic term.


Yeah, I immediately thought of Rust traits, which I hear are very like typeclasses. Python already has something like these, in the form of Abstract Base Classes: collections.Callable for function-like things, collections.Iterable for things that conform to the iterator protocol... But if gradual typing is to be useful, it really needs ABCs for all the common ducks that Python code uses: file-like objects, things that dict() can convert into a dictionary, things that can be converted into strings...


I'm not sure any committee could agree as to what defines a filelike object (does it implement seek?)

In addition you'd need an IRO (interface resolution order) if you truly intended to prove everything would work

To say nothing of accidentally implementing an interface and getting an error because if it

Doesn't sound like my kind of python...


You have a seekable filelike interface that is a superset of the base filelike interface.


>I'm not sure any committee could agree as to what defines a filelike object (does it implement seek?)

You step back a layer of abstraction. Maybe it implements seek, maybe it doesn't. Either way it implements has_seek.


Well... either your library invents its own type classes, and all client code must implement them (boilerplate!). Or it relies on agreed-upon type classes which come from another library. If it's not basic classes like Functor or Monad that's just not manageable (dependency hell!).


Dependency hell is the situation where A depends on both B and C, but B depends on D, and C depends on D', where D and D' are not compatible.

Type classes absolutely do not create this kind of situation, as they are duck typing. But modules do create it, so it happens both on Haskell and on Python.

Now, in practice you use both, basic classes and library specific ones. And yes, if you want to create some behavior, you'll need to implement the specific code that enables it. You do not escape from that in Python either.


I know dependency hell when I see it. It's already bothersome if I can't just apt-get install the right library version because another package depends on a conflicting version, or the latest boost version isn't available yet. I refuse to learn tools like pip or stack for every language I use, and to create sandboxes for new projects only to get the latest library versions. That's just never going to be portable software.

You can actually escape dependency hell for most APIs. That's the Unix culture of using plain text (read: very simple data types -- in C that would be arrays and structures of integral types) for communication.

Of course that won't work for libraries that provide transformations on parameterized structures. But let's face it, there's no point in depending on a Monad library just to save two lines of pure code.


"Duck typing" can be done statically through row polymorphism. For more info, read up on OCaml's object system.


You only need row polymorphism if you want full type inference. You can get away with width subtyping with bounded parametric polymorphism if you are willing to give up on inferring all types. Examples: Go, TypeScript, Flow...


as we totally accept two-element lists here as well as two-tuples.

This is a little a symptom of lack of overloading (and lack of static typing therefore), but should be not hard to solve buy disjunctive hints like this one: [a]|(a,b) (and in case of Python, looks like Union[] would do?).

The URL case is also pretty much the same and for example in Java you would have to write a different method signature for each such case and that would be natural. Again, disjunctive hints would solve this.

Given that, I do not know what is the complaint really here. Perhaps that syntax is horrible, or it is hard to know what are the actual types in Python?




Consider applying for YC's Winter 2027 batch! Applications are open till November 2.

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

Search: