On 2020-02-14 11:42 p.m., Steven D'Aprano wrote:
On Fri, Feb 14, 2020 at 07:24:48PM -0300, Soni L. wrote:
> In Rust, you can have:
That's great for people who understand both Rust styntax and Rust
semantics, but this is a Python discussion group, not Rust. We aren't
all Rust experts.
I do suggest learning Rust, at least for the traits.
> 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,
That's how traits are (usually) defined: if there is an ambiguity due to
conflicting methods, you have to explicitly resolve the ambiguity, or
else it's an error.
If the compiler just picks one for you, you don't have traits, you have
multiple inheritence.
(Above, I say "usually", because there are many subtle or not-so-subtle
differences between the way traits are defined in different languages.)
That's how mixins-with-extra-steps are defined.
> at which point it behaves like mixins,
Well, yes. Mixins with no conflicting methods is just the same as
traits. The difference is that traits make you resolve conflicts
explicitly, rather than just using some default rule.
No, it isn't.
> 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.
Right. And that's what the strait module allows too. See the example:
https://pypi.org/project/strait/
I think that if this discussion is going to become productive, you need
to start by defining what "traits" mean to you, in detail. What do they
do? What are their semantics? Focus on how they differ from multiple
inheritence and mixins in Python, and what problems you would solve by
using them.
Entities and features going by the name "trait" occur in many languages,
but have different meanings. Unless we agree on a meaning, we are just
talking past each other.
You should give *short*, *simple* but *concrete* examples, in pseudocode
that demonstrates the principle, not the mechanical details of some
specific interface. Interfaces can be changed. The semantics of the
feature is what is important for understanding.
Using abstract metasyntactic variables like spam, eggs, foo, bar, x, y
that do nothing and mean nothing is not going to be helpful. Use a
concrete, actual example, but simplifed.
Thank you.
Okay. To put it simple: traits and composition aren't the same thing. If
they were, we'd call them composition rather than invent a new name.
They aren't mixins either.
They're namespaced interfaces. The namespace is the interface itself.
You can apply multiple such interfaces to the same type, each having all
the same names, and when you pass the type around, stuff just works.
That's the *WHOLE* point of traits.
Here's a table for you:
- Composition:
- Components can be added to an object
- Components provide an interface and an implementation of that interface
- Components don't conflict
- This is how so-called "ECS" works
- Mixins:
- Mixins can have their names injected into an object
- Name resolution order is generally automatically decided by the
compiler/runtime, but there's nothing that prevents you from having
mixins with explicit resolution (or error on conflicts).
- Mixins may conflict. This is a pain.
- Mixins don't inherently provide an interface, just an
implementation of one.
- Nobody likes mixins. They're just multiple inheritance with extra
steps.
- Traits:
- Traits define an interface. They don't inject anything anywhere,
and don't get added anywhere either.
- An object can implement a trait, but your object is yours and the
trait won't interfere with it.
- There is no such thing as name resolution order. (* some languages
have default methods/etc, which is arguably a form of name resolution
order.)
- Generally, implementations of traits will provide some convenience
where non-conflicting names will resolve to a given trait. these may or
may not be considered part of your public API. Implementations that do
this will generally distinguish "inherent" methods, defined directly on
a type, from... "non-inherent" (? idk the name for this) methods,
defined on a trait.
- It's not mixins with extra steps. It's not even composition with
extra steps, altho it comes a lot closer to composition than to mixins.
It's more like an attempt to combine the best of mixins with the best of
composition, if anything.
Now, let's take an example from strait:
class TOSWidget(BaseWidget):
__metaclass__ = include(Pack, Place, Grid)
info = Pack.info.im_func
config = Pack.config.im_func
configure = Pack.configure.im_func
slaves = Pack.slaves.im_func
forget = Pack.forget.im_func
propagate = Pack.propagate.im_func
Where does TOSWidget implement Pack.info? Place.info? Pack.config?
Place.config? etc? Oh, yeah, it doesn't, because strait is just mixins.
It calls itself "trait" just to create unnecessary confusion. If you
tried to pass this TOSWidget to something trying to interact with a
Place (assuming Place and Pack use the same names for different things),
it just wouldn't work, as it's using the Pack methods where Place
methods are expected!
_______________________________________________
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/7FQRBC5HAQZQYQI7U2AQK3UGSBC3CTBA/
Code of Conduct: http://python.org/psf/codeofconduct/