In Rust, you can have:
trait Foo {
fn x(&self);
}
trait Bar {
fn x(&self);
}
struct Baz {}
impl Foo for Baz {
fn x(&self) {
}
}
impl Bar for Baz {
fn x(&self) {
}
}
with strait, you can't have both Foo and Bar on Baz - it just raises by
default. if you don't want it to raise, you have to specify an x, at
which point it behaves like mixins, not giving you the niceties of Rust
traits.
for proper traits, you need to be able to select, implicitly or
explicitly, which trait impl you want to call. in Rust, this is done in
two (three) ways:
1. function has a bound on a trait: (not relevant for python or other
dynamically/duck typed languages(!), is the most common way of doing it
in Rust)
fn foo<T: Bar>(obj: T) {...}
2. function takes a trait object, basically a wrapper object around the
real object:
fn foo(obj: &Bar) {...}
3. function explicitly calls the trait method on the object:
let obj: Baz = ...;
<Baz as Bar>::x(obj);
in my python-based traits library, these become, respectively from the
start: the trait, struct and impl definitions:
class Foo(Trait):
def x(self):
raise NotImplementedError
class Bar(Trait):
def x(self):
raise NotImplementedError
class Baz(TraitObject): # "mirrors" class Baz(object):
@impl(Foo)
class Foo:
def x(self):
pass
@impl(Bar)
class Bar:
def x(self):
pass
"the function has a bound on a trait" intentionally doesn't have an
equivalent.
the function takes a trait object:
def foo(obj):
obj = Bar(obj)
# or, ideally, as sugar for the above:
# def foo(Bar(obj)):
# pass
the function explicitly calls the trait method on the object:
obj = Baz();
Bar(obj).x() # or Baz.Bar.x(obj) if you know the name under which
the trait impl is located and wanna use it rather than making a wrapper
trait object.
quick digression: I personally feel strongly that traits add to python
whereas trait bounds would take away from python. more specifically
trait bounds would take away python's dynamic/duck typing. as such I
don't plan on implementing trait bounds.
further, as evidence that I'm not screwing over python's dynamic/duck
typing: you can easily make any object look like a TraitObject, and
that's a deliberate design decision. it might not necessarily pass
isinstance/issubclass tho (but then, neither do existing fake ducks).
On 2020-02-14 6:33 p.m., Steven D'Aprano wrote:
On Fri, Feb 14, 2020 at 09:53:27AM -0300, Soni L. wrote:
> Nobody has implemented actual
> traits in Python yet, only mixins with extra steps
That's a bold claim, since the meaning of "traits" you gave earlier in
the thread sounded to me exactly like "mixins with extra steps".
Michele Simionato wrote what is (in my opinion) *the* definitive series
of blog posts on super, multiple inheritance, mixins and traits
https://www.artima.com/weblogs/viewpost.jsp?thread=246488
and a library claiming to implement traits:
https://pypi.org/project/strait/
Unfortunately some of the links to external resources are now dead.
However he seems to be basing his concept of traits on the paper which
introduced the term:
http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf
If this is not what you mean by "traits", you ought to describe
*precisely* what the word means to you and how they differ from Michele
Simionato's library.
_______________________________________________
Python-ideas mailing list -- python-ideas@python.org
To unsubscribe send an email to python-ideas-le...@python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at
https://mail.python.org/archives/list/python-ideas@python.org/message/LDYZRHGBGJ2TBICZIFHQOUVRUX46VN6K/
Code of Conduct: http://python.org/psf/codeofconduct/