Answering off-list by moderator request.
Before I go on to respond to the details, let me start by saying I'm
definitely beginning to understand why you like the Rust syntax for
traits, and maybe even some feeling for the semantics, although
they're not very well documented anywhere I found in a couple hours of
Googling and browsing. On the other hand, I don't think some of
Rust's semantics are a good fit for Python (and go into that below).
Soni L. writes:
> zope.interface appears to be more based on java interfaces than rust
> traits? I could be wrong tho.
zope.interface precedes Rust traits by at least two decades. I don't
know what the relationship is between zope.interface and Java's
interface is. Java was released in 1995, Zope in 1998, but Zope's
predecessor, the "Bobo object publisher," was released to the public
in the early 1990s. Of course interface checking in a very primitive
form (function prototypes) go back to C++'s predecessor "C with
Classes" in 1979, and I imagine Lisp has had them even longer, and in
more elaborated form. C++ got virtual functions in 1985, which is
much closer to the modern concept of separating interface from
implementation, and abstract classes (classes containing one or more
pure virtual functions) in 1989. So this stuff was in the air for
several years before either Python or Java started development.
> *forget* Schärli et al., this is too hard to explain if you keep
> expecting Schärli et al. behaviour
Not gonna happen. Thing is, I can hold two behaviors in my mind at
the same time, but it would help if you paid some respect to the
seminal paper that preceded Rust by more than a decade. At least call
them "Rust traits". But that doesn't help much, since the Rust
documents are really sparse, even about behavior, let alone about
rationale for the behavior. I had to Google bug reports to find even
a mention of method name collisions.
> when Rust quite explicitly doesn't seem to follow that.
I now think you're wrong about Rust following Schärli et al., although
it's impossible to be sure since there are differences, and the design
decision rationales aren't to be found in the places I looked.
> now everyone's been gaslighting me because I got fed up with this
> and idk what to do about that. but anyway,
"Gaslighting" is lying about something that both parties can see is
false. That's not happening here. There's definitely a lot of
confusion about what you've been talking about.
It's one thing to ask one person (such as me) to learn Rust; it's
another to ask all the core developers to do so. It's reasonable for
you to say that your time is worth as much as anybody else's, even
Guido's (though I don't recommend saying *that* out loud!) It's not
reasonable to say that your time is worth as much as everybody else's.
> > In the TOSWidget example, as I understand it, in Rust:
> > 1. In the trivial case where exactly one of TOSWidget, Pack, and
> > Place implements 'config', you get that implementation, and
> > any code that's not happy with that is incorrect.
> Yes, but also not quite. Rust has a bit of implicitness here for
> ergonomics. If there's no conflict, it can easily figure out what you
If there's no conflict, strait figures out what you want, too.
> Also, it's not that Pack or Place implements 'config' - they
> *define* a 'config' interface. TOSWidget implements Pack.config
> and/or Place.config.
It can, but it doesn't necessarily do so. The traits can supply
default implementations. For reasons I don't understand (but presume
are valid), Rust emphasizes traits' role in providing interfaces over
> > 2. In the case TOSWidget implements 'config', and Pack or Place or
> > both implements it, you get TOSWidget's implementation, but
> > anything expecting Pack or Place behavior will not get it, and is
> > incorrect.
> No, anything expecting Pack behaviour will get Pack behaviour, anything
> expecting Place behaviour gets Place behaviour, and anything dealing
> with TOSWidget directly gets TOSWidget behaviour. They're effectively
"Expect" here means what the author of the code that invokes a method
on a TOSWidget object expects. Of course you can use UFCS to
disambiguate, but that's not what most of us mean by "expecting",
that's explicitly invoking the behavior. In Python, "expecting" means
"duck typing (ie, a method invocation) does the right thing", but UFCS
is effectively a cast, and uses normal function call syntax. In
English, your use of that word is perfectly correct, but I guarantee
using it that way in this context will totally confuse most
> > 3. If both Pack and Place implement 'config', but TOSWidget does not,
> > you get a compile-time error.
> No, unless you try to interact with 'config' on a TOSWidget.
Of course. That's what most Python programmers expect. "Duck typing."
> The error happens in the caller, not the implementer, and then you
> need to disambiguate, in the *caller*, which implementation you
> meant to call.
I really don't like that *for Python*. Rust can do it at low risk
because it resolves the call at compile time. Python doesn't, so this
means a runtime exception, possibly after I've spent many CPU seconds
and hours of wall time on a computation. I suspect a lot of
Pythonistas will feel the same way.
> This can either be done by expecting Place or Pack explicitly
> (i.e. having Place or Pack in the function signature) or by
> explicitly specifying that you want to use TOSWidget's
> implementation of Place or Pack. In Rust, a TOSWidget can be both a
> Place and a Pack,
Literally being both is not possible in Python at all if there are
method collisions because of the way multiple inheritance works.
Python can't invoke a trait in the function signature, because Python
functions don't have typed arguments. It would be possible in MyPy if
you implemented traits as classes, but that doesn't help you at
compile time, you'd have to add checking at runtime. So making this
possible would be a major change in Python semantics, creating a new
kind of data namespace below the class level. You won't get that in
Python without convincing a lot of people that they can't live without
true traits in some form, and then that emphasizing the same aspects
of traits that Rust does is the right balance.
> and things expecting Place behaviour expect it explicitly and get
> it explicitly, whereas things expecting Pack behaviour also expect
> it explicitly and get it explicitly.
If you have to be explicit, I don't see how this has a big advantage
over having Place and Pack trait components as instance attributes,
and a metaclass that automatically promotes trait methods to instance
methods when there is no name collision.
> I might've gone too far on this one, sorry.
Apology accepted. No offense taken.