Telling someone you are trying to convince to do something to go learn something else to "get on your level" as the youth would put it... is not how you get people to agree with you. To summarize this thread, as I see it so far * you asked about adding a feature with the name "traits" to the language. * it was pointed out that "traits", in context, has a meaning on computer science * Rust's implementation of traits is some order of magnitude different from the plutonic ideal of traits * Rust, not being python, has to have its concepts translated. Your version of the translation of the rust concept is further from the plutonic ideal of a trait than other users on this list. * You were asked to nail down a definition of what you are talking about I think I have the order of events here. I still haven't seen a clear definition of what you actually want to propose. I'm not convinced of what traits are, let alone there are worthwhile, and then that they would warrant changing the syntax of the language.
-----Original Message----- From: Soni L.
On Behalf Of Soni L. Sent: Saturday, February 15, 2020 6:38 AM To: Stephen J. Turnbull Cc: python-ideas@python.org Subject: [Python-ideas] Re: Traits you don't want me to be rude but when I literally explain rust traits you throw me an "that's not traits and fuck you for being rude/trying to get me to think".
I'm just gonna say learn rust since you actively refuse to accept my explanation of rust traits. don't reply again until you've learned rust.
On 2020-02-15 5:38 a.m., Stephen J. Turnbull wrote:
Soni L. writes:
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:
I do suggest learning Rust, at least for the traits.
That's inappropriate because it's placing responsibility on us to puzzle out what you mean, rather than on you to explain it.
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:
That's how mixins-with-extra-steps are defined.
I just read Schärli et al. I won't say "usual" definition as Steven did (I don't know other languages' implementations), but clearly that paper's definition is an *important* definition.
Schärli et al. clearly envisioned an equality relation on method implementations in traits. The obvious trivial implementation is identity. Using the dictionary of methods implementation for simplicity of exposition:
Trait = dict
def foo(self): pass
def bar(self): pass
A = Trait(x = foo)
B = Trait(x = foo)
C = Trait(x = bar)
With Python's definition of equality of functions, you cannot add A and B to the same class without raising, but you can add A and C (under Schärli et al's definition). If Simionato's strait doesn't account for equality of implementations in this sense, I suppose it would be easy enough to add. Presumably we could "improve" the idea of "equality" (eg by comparing ASTs) if we really want to. But you seem to ignore this aspect of the original definition of "trait."
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.
This is rude, unless you have registered a trademark in the name "trait". Quite clearly the folks in this thread know that much, and have some concept of the differences. What you need to do is to figure out and explain where your definition conflicts with others', and explain why yours is more faithful to the abstract idea of "trait."
I think that last part is going to be a very heavy lift, because the Schärli, et al paper is very well reasoned, and they make very good points about why each of the features in their design for "traits" is appropriate in the context of comprehension and maintenance of code using traits. But that's what you need to do, since I greatly doubt you own that trademark.
They're namespaced interfaces. The namespace is the interface itself.
This is quite incompatible with Schärli et al's design. They clearly require a way to determine equality of *implementations* of a method, because they envision automatically detecting changes to those implementations during maintenance. The interface alone is insufficient.
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.
I'd call that "incomprehensible", and even "impossible." Your words indicate that you think that trait = "interface that just works [= never conflicts? but you don't say] by pure fscking magic", but surely you don't mean that. What do you mean here?
In any case, all of the concepts discussed here "just work when you pass types around" for values of "working" where errors are raised appropriately for that design. The problems are elsewhere, in whether they do what we expect, whether they are easy to understand, and whether the errors that are raised when we would find them most useful. You need to specify how traits succeed in those aspects where others fail.
Here's a table for you:
This discussion is poorly served by such a table. It would be much more useful if your table indicated whether various features are shared or unique in the different concepts.
- Traits: - Traits define an interface.
Of course.
They don't inject anything anywhere, and don't get added anywhere either.
Nicely solipsistic, but incomprehensible, unless you mean "trait == interface" (and even then, doesn't the interface get added to the class somehow?)
- An object can implement a trait, but your object is yours and the trait won't interfere with it.
Obviously if the object does the implementation, the trait won't affect it. But the main point of "composition" (by any definition, except where purely restricted to interface; I will continue to use scare quotes below since you provide your own definition of the word) is efficient code reuse: if you fix the component, you fix all objects using it too. Do you mean such maintenance is "interference"? I can't believe you do, but that's what your words seem to mean. :-(
- Generally, implementations of traits will provide some convenience where non-conflicting names will resolve to a given trait.
This is true of all language support for "composition," however: it abbreviates access to an object component's attribute to access to the object's attribute with the same name. This has a unique definition exactly when only one component (including the object itself) provides the attribute. The differences among different designs for "composition" are all in conflict resolution.
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.
Rude, and toward someone not even present in the discussion.
Again you seem to identify the idea of "trait" with that of "interface", and exclude code reuse. But in Schärli et al's discussion, code reuse is an explicit goal of their design for traits. Simionato's blog is also implicitly aware of the code reuse motivation, though he doesn't emphasize it at all.
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!
Isn't that what "conflict resolution" means here?
The point of traits as defined by *Schärli et al* is more or less that the language support for traits obeys[1]
- Flat is better than nested. - Readability counts. - In the face of ambiguity, refuse the temptation to guess. - If the implementation is hard to explain, it's a bad idea. - Namespaces are one honking great idea -- let's do more of those!
while recognizing that in the case of composition of components
- There should be one-- and preferably only one --obvious way to do it.
is impossible to obey in general, where "in general" means "you're gonna run into special cases every day or so", thus the importance of "don't guess."
What you seem to want is nested namespaces where attributes are resolved in the following order
1. a binding in the object's own namespace (including an explicit resolution of conflicting bindings in component namespaces) 2. a binding in a component namespace, unique among all component namespaces 3. (optionally) some default binding.
plus
4. an attribute in a nested namespace can be explicitly accessed by "external" code.
But then I'm not sure why you complain that TOSWidget doesn't behave like a Place when the definition explicitly states that it always behaves like a Pack when there's a conflict (which is #1 in the order of resolution I suggested above). One of the advantages of traits as advocated by Schärli et al is precisely that you can discover this by reading the definition of TOSWidget (even if you don't understand traits!) You don't need to compute MRO, you don't even need to examine the parents. That's why they require explicit resolution of conflicts. (Of course where trait methods are acquired implicitly, you'd have to examine parents to find out what they provide. But not here.)
Regards,
Footnotes: [1] These five koan are not at all independent when discussing traits.
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-leave@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/TVEEF5TIMTNZ2KERJEYZPZITLRXUGIBY/ Code of Conduct: http://python.org/psf/codeofconduct/