I've recently found about Protocol / structural subtyping in Python and found this sort of pattern really useful as duck typing is so common in py code.
Have some bad memories with zope.interface. Worked on a team composed mainly of ex enterprise .NET developers forced to work with Python (myself included). Some embraced the Python paradigm, others stubbornly clinged to old enterprise .NET habits. zope.interface was heavily used by the latter to essentially write something as close as possible to an enterprise .NET application, only in Python.
I tried to create a web service using Zope in 2002 or so. I struggled for weeks trying to figure out how to get anything done, never did produce anything useful.
Not sure that says more about Zope or my bootstrapping skills, which are admittedly pretty poor.
Yea, Zope was weird. I learnt python in around 2000 and immediately fell in love with the language. Then I needed to to do some web stuff and wanted to move beyond simple cgi scripts and for some reason decided to pick up Zope. Almost stopped using Python all together then and there.
I never worked with pure Zope, my first job in the mid 2000 was using Plone, a CMS build on top of it. Certainly overkill for simple websites, but I found it much more enjoyable than other big CMS of the time.
It had some cool things, that I started missing once I moved on. How well the permission system, workflow engine and hierarchical content structure worked together, undo functionality, accessing things via urls like “/path/to/object/method” instead uf unreadable params, component based UI, having a single configuration file (zc.buildout) to have a reproducible environment for development and production, etc.
In many regards they were ahead of the time I think, at least in the space of things between simple script driven websites and very enterprisey solutions.
2. The type system is both gradual and not enforced by default. This means you benefit from the rapid prototyping and general freedom of dynamically-typed code, but you have the option to layer on the additional safety of static type checking as the project grows. There aren't many other gradually-typed languages out there anyway; Julia, Typed Racket, and Common Lisp aren't exactly in widespread industry use for general-purpose server dev.
You can either start with JS and add types later on (you can mix them on a per-module/file basis), or just start with TypeScript, with a loose configuration.
You have to say that builtins.set implements the interface. If there's a receiver protocol, it'll just accept a set of that matches the protocol, no registration required.
Not without modifying the existing type. Since Interfaces rely on nominal typing, each type implementing an interface must explicitly declare that they do so. On the other hand, since Protocols are checked structurally you can declare a protocol after several types already implement it, and type checking will pass without having to modify the implementing types.
Explicitly declaring which types provide which interfaces is the whole point of explicit interfaces.
But I don't think the "you can declare a protocol after several types already implement it" is any different under explicit vs implicit conformance checking.
I can just say
implementer(IReceiver)(builtins.set)
at any time. There's no temporal restriction on when I can do that.
Right - so if you're introducing type annotations into an existing project and have a method expecting some interface, used by many call-sites spread across various parts of the project, then you can go around wrapping the original type at each call-site as you've indicated.
Or add a single type annotations to the method declaring that the parameter satisfies a protocol.
In Java, you have to explicitly mark a class as conforming to an interface inside the class's declaration. You need to have the source and modify it.
In Haskell, you mark a type as conforming to an interface (called typeclass) by adding functions that operate on its instances and implement the interface's requirements. You can do it anywhere, and write an implementation for an existing type, which is normal practice.
In Python, you cannot easily add interface conformance, but possibly you can make a trivial subclass of the desired class, and mark it as conforming to the desired interface (Protocol), without modifying the source.
Or you can use an ABC with no implementation logic. I don't agree with the author quickly dismissing them at the beginning. They seem like a relevant solution to when you want nominal typing instead of structural.
Yes, they can contain implementation logic. They don't have to though.
25 comments
[ 2.7 ms ] story [ 59.5 ms ] threadHighly recommend reading:
https://www.python.org/dev/peps/pep-0544/
https://docs.python.org/3/library/typing.html#nominal-vs-str...
https://docs.python.org/3/library/typing.html#typing.Protoco...
Cool example:
https://github.com/jordaneremieff/mangum/blob/main/mangum/ty...
Not sure that says more about Zope or my bootstrapping skills, which are admittedly pretty poor.
It had some cool things, that I started missing once I moved on. How well the permission system, workflow engine and hierarchical content structure worked together, undo functionality, accessing things via urls like “/path/to/object/method” instead uf unreadable params, component based UI, having a single configuration file (zc.buildout) to have a reproducible environment for development and production, etc.
In many regards they were ahead of the time I think, at least in the space of things between simple script driven websites and very enterprisey solutions.
- (number_of_people_who_enjoy_coding_with_python_more_than_coding_with_c_sharp_or_java > 0) == True
- Some people have large existing codebases, and would rather add types gradually than have to port all their logic to another language.
- In terms of being free and open source, Python > C# > Java (meta: can you even do a comparison like that in C# and/or Java?)
2. The type system is both gradual and not enforced by default. This means you benefit from the rapid prototyping and general freedom of dynamically-typed code, but you have the option to layer on the additional safety of static type checking as the project grows. There aren't many other gradually-typed languages out there anyway; Julia, Typed Racket, and Common Lisp aren't exactly in widespread industry use for general-purpose server dev.
You can either start with JS and add types later on (you can mix them on a per-module/file basis), or just start with TypeScript, with a loose configuration.
Python is strongly typed. The support for external tools is to enable static type checking, not strong typing.
> Why not just use Java or C#?
Why add “dynamic” to C#, why not just use Python?
Can't interfaces do that too? You can just say builtins.set implements the receiver interface.
But I don't think the "you can declare a protocol after several types already implement it" is any different under explicit vs implicit conformance checking.
I can just say
at any time. There's no temporal restriction on when I can do that.Or add a single type annotations to the method declaring that the parameter satisfies a protocol.
In Java, you have to explicitly mark a class as conforming to an interface inside the class's declaration. You need to have the source and modify it.
In Haskell, you mark a type as conforming to an interface (called typeclass) by adding functions that operate on its instances and implement the interface's requirements. You can do it anywhere, and write an implementation for an existing type, which is normal practice.
In Python, you cannot easily add interface conformance, but possibly you can make a trivial subclass of the desired class, and mark it as conforming to the desired interface (Protocol), without modifying the source.
Yes, they can contain implementation logic. They don't have to though.