-
Notifications
You must be signed in to change notification settings - Fork 12
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
mixin pattern? #700
Comments
@samreid said:
|
Accessibility is using numerous properties on Node and its supertype. That seems very wrong. Similar to a supertype using features of a subtype. |
@zepumph said:
|
AccessiblePeer has a similar problem. Not only does it mix itself into Poolable, but it requires Poolable. This is not mixin, this is subtyping. |
@zepumph said:
|
I’m not questioning the fact that this pulled code out of Node. I’m questioning how the mixin pattern is being applied. Happy to have someone point me to a version of mixin that matches what is being done here. https://en.wikipedia.org/wiki/Mixin “Mixin programming is a style of software development, in which units of functionality are created in a class and then mixed in with other classes. A mixin class acts as the parent class, containing the desired functionality. A subclass can then inherit or simply reuse this functionality, but not as a means of specialization. Typically, the mixin will export the desired functionality to a child class, without creating a rigid, single “is a” relationship. Here lies the important difference between the concepts of mixins and inheritance, in that the child class can still inherit all the features of the parent class, but, the semantics about the child “being a kind of” the parent need not be necessarily applied.” I have yet to find a definition of mixin where it functions as a subtype - that is, can use features of the thing that it’s being mixed into. |
@jonathanolson said:
|
Atypical usage is putting it nicely. Correct me if I’m wrong. But it looks like we’re just pulling some functionality out into a file2, so that file1 doesn’t get too big. While still allowing file2 to reach over into file1 and use whatever it wants. And it looks like this pattern is not exclusive to Accessibility. I see that other mixins (Paintable, RectangleStatefulDrawable,…) access properties of the subtype that they will be mixed into. This is not mixin. What’s currently being done is closer to the Decorator pattern — though that pattern typically applies to instances, not types. |
@jonathanolson said:
|
@jessegreenberg said:
|
@samreid said:
|
@jessegreenberg said:
|
@samreid said:
|
@jonathanolson said:
|
Traits would be closer, but would still require some changes. From one of the seminal papers on traits (http://scg.unibe.ch/archive/papers/Scha03aTraits.pdf, p2): • A trait provides a set of methods that implement behavior. In the case of Accessibility, this means that it can require the presence of Node methods, but cannot access Node state variables. E.g. Accessibility cannot access We’d probably punt on enforcing the presence of the required methods - or perhaps provide a list of types that a Trait is allowed to be composed with. We’d probably also disallow naming conflicts, rather than try to implement a way to explicitly resolve conflicts. So my current inclination (which I’m still ruminating on) is to: |
Btw… “Programming in Scala” (p 230, “To trait, or not to trait?“) recommends:
I am not aware of any current PhET “mixin” that is being used (or is intended to be usable) in more than 1 place - so not in the typical situation where a mixin or trait would be used. |
(Slack discussion included all of the above, non-Slack discussion continues below.) |
@pixelzoom it wasn't clear whether you had acknowledged @jonathanolson's comment #700 (comment) He is referring to https://en.wikipedia.org/wiki/Mixin#In_JavaScript which has: // This example may be contrived.
// It's an attempt to clean up the previous, broken example.
var Halfling = function (fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
var NameMixin = {
fullName: function () {
return this.firstName + ' ' + this.lastName;
},
rename: function(first, last) {
this.firstName = first;
this.lastName = last;
return this;
}
};
var sam = new Halfling('Sam', 'Lowry');
var frodo = new Halfling('Freeda', 'Baggs');
// Mixin the other methods
_.extend(Halfling.prototype, NameMixin);
// Now the Halfling objects have access to the NameMixin methods
sam.rename('Samwise', 'Gamgee');
frodo.rename('Frodo', 'Baggins'); As @jonathanolson said, "[it] assumes the existence of fields that the type it is mixed into has" in the same way that our Accessibility mixin assumes the existence of Node methods and properties. |
I believe that example is incorrect. |
I also didn't reply to this... @samreid said:
Mixins function as base classes (superclasses) not subclasses. |
True, but sometimes parent classes have abstract methods which must be implemented in the child class. |
I fail to see any relation to what is being done here. PhET's "mixins" are using things that are both declared and defined in the subclass. |
An abstract class explicitly defines methods which must be implemented in the subclass. A mixin implicitly defines methods which must be implemented in the mixee. |
Where are you getting this information? And how do you rationalize multiple mixins all "implicitly defining" Node |
A trait (not a mixin) declares methods that must be implemented by things (classes and other traits) that the trait may be composed with. |
It mixes Poolable into itself. And actual subtyping does not seem like an option here, since Poolable truly is used (a) on types with very different supertypes, and (b) does not have any type-specific information, i.e. it can be mixed into basically anything.
For an example:
Of those, everything except ImageWebGLDrawable have some concept of being "paintable" (fill/stroke). TextCanvasDrawable doesn't need to save the state of the current paint, so it uses PaintableStatelessDrawable, but the other two do, using PaintableStatefulDrawable. This isn't something that can be solved with subtyping, as it's a clear "multiple inheritance" issue, where we need to mix-and-match render type (Canvas/SVG/WebGL/DOM), node type (Circle/Line/Rectangle/Text/Image/etc.), and at a higher level paintability and style (PaintableStatelessDrawable/PaintableStatefulDrawable). Note that these all expect things to be SelfDrawables, and there is a lot of typing constraints. In addition, it could use some cleanup (some of it is somewhat unintuitive), but there's clearly a need for handling "multiple inheritance" style issues here. Notably, of the other cases:
I'm fine with whatever name we choose. The pattern Assertion checks to ensure it's a proper expected type sound good to me (might need to use Additionally, I'd like to note that JavaScript itself (with prototype/type modification) allows a lot of flexibility to implement behavior that can't be done in some other languages (like Poolable placing the pool object on the type itself, which can significantly ease debugging). Type modification (like mixins/traits) has so far been most helpful sharing behavior between types that all have a shared supertype, so I don't want to exclude that in the future. |
I stand corrected - there are indeed many PhET "mixins" that are reused extensively. So you can ignore #700 (comment). With the exception of @jonathanolson said:
I'm not suggesting that we shouldn't think outside the box. But JavaScript also gives you the "flexibility" to break encapsulation, access things you shouldn't, violate proper application of patterns, and generally create maintenance problems. So I think we should exercise restraint when extending/adapting existing design patterns - it's confusing to developers who are familiar with those patterns, and does a disservice to new developers who are still expanding their knowledge of design patterns. |
Task for 10/26/17 developer meeting is to decide whether to (a) leave as is, or (b) rename things that are not following the Mixin pattern. If (b), decide on a name. |
10/26/2017 dev meeting notes: |
Implemented renamings and type-check assertions. Aqua tests passing. |
I'm creating this issue in scenery, since it appears to be the sole place where the "mixin" pattern is being used. This discussion started in Slack developer channel on 10/21/2017, and I transferred the discussion to this issue.
#696 (Accessibility mixin uses features of Node) prompted me to ask:
The text was updated successfully, but these errors were encountered: