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/

Reply via email to