25 comments

[ 2.7 ms ] story [ 59.5 ms ] thread
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.

This is what I was thinking about reading this post. Why add things to Python to make it strongly typed? Why not just use Java or C#?
Because Java and especially C# aren't 'cool'
Not an exhaustive list of possible reasons:

- (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?)

I thought Java being not-open-source in 2021 was a myth, no? What about OpenJDK (GPL licensed)?
GPL2 has no explicit patent grant, and Oracle's behavior does not signal good intentions.
1. Because people like Python.

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.

Don't forget JavaScript/TypeScript.

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.

> Why add things to Python to make it strongly typed?

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?

The libraries that make my job easier are in python. A language ecosystem is often more important than the language itself.
> Unlike Interfaces, Protocols can describe the types of things that already exist.

Can't interfaces do that too? You can just say builtins.set implements the receiver interface.

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.
(comment deleted)
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.

    implementer(IReceiver)(builtins.set)
only needs to be written once, not once at each call site. It's telling the global registry that builtins.set implements IReceiver.
Depends on the language.

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.

(comment deleted)
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.

For me, not having the metaclass overhead of abc is a benefit of protocols. Unfortunately you can't mix metaclass types.