Skip to content
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

CS2 Discussion: Features: mixin #4974

Closed
coffeescriptbot opened this issue Feb 19, 2018 · 5 comments
Closed

CS2 Discussion: Features: mixin #4974

coffeescriptbot opened this issue Feb 19, 2018 · 5 comments

Comments

@coffeescriptbot
Copy link
Collaborator

From @mikeyhew on 2017-04-21 21:50

The new ECMAScript classes lend themselves to a neat pattern for mixins. The idea is described pretty well here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes#Mix-ins.

A mixin is a function that takes a base class as a parameter, and returns a new class that extends it. Here is an example:

let MyMixin = Base => class MyMixin extends Base {
  constructor() {
    super()
    // do some initialization
  }

  foo() {
  }
}

You can include MyMixin in your classes like so:

class MyBase {}
class MyClass extends MyMixin(MyBase) {
  // overrides MyMixin.foo
  foo() {
    super.foo()
    // do some extra stuff
  }
}

This can be done in CoffeeScript too. What would be better, though, is if CoffeeScript supported it natively:

mixin MyMixin
  constructor: ->
    # do some initialization

class Foo extends MyBase includes MyMixin
  foo: ->
    super()
    # do some extra stuff

This could be extended to allow mixins to include each other:

mixin MyOtherMixin includes MyMixin
  ...

would compile to

let MyOtherMixin = Base => class extends MyMixin(Base) {
   ...
}

Unfortunately, this breaks backward compatibility by introducing two new keywords. includes could be replaced with with, which is already a reserved word, but that still leaves mixin, which is probably a commonly used word. I'm not sure if there's any good alternatives, and I like mixin because it's very clear about what it means.

@coffeescriptbot
Copy link
Collaborator Author

From @GeoffreyBooth on 2017-04-22 01:15

I like the syntax you mentioned in the other thread:

class Bar extends SomeBaseClass with Foo, Baz

Why do we need a mixin keyword to declare a mixin? Couldn’t we declare it with class like in the MDN example you link to?

@coffeescriptbot
Copy link
Collaborator Author

From @mrmowgli on 2017-04-22 02:05

Indeed, I like the basic version only using the 'with' clause :)

Keep it concise, and I would extend this to objects as well as classes
perhaps?

On Apr 21, 2017 6:15 PM, "Geoffrey Booth" notifications@github.com wrote:

I like the syntax you mentioned in the other thread:

class Bar extends SomeBaseClass with Foo, Baz

Why do we need a mixin keyword to declare a mixin? Couldn’t we declare it
with class like in the MDN example you link to?


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
coffeescript6/discuss#81 (comment),
or mute the thread
https://github.com/notifications/unsubscribe-auth/ABy6xzGH_Z8NxxRbsGFrBFLIqVoCiXjAks5ryVSggaJpZM4NE08I
.

@coffeescriptbot
Copy link
Collaborator Author

From @mikeyhew on 2017-04-22 02:08

Couldn't we declare it with class like in the MDN example you linked to?

Yes. mixin Foo is just syntactic sugar for

Foo = (Base) -> class Foo extends Base

Which you can already do in CoffeeScript.

Why is mixin Foo better? Because it looks cleaner, and it promotes using this pattern, making it look just declaring a class but with a different keyword.

The benefit of mixin would be similar to the way class improved things when there was no class in vanilla JavaScript. There was a recipe for doing object-oriented programming in JavaScript, but it was complicated and error-prone, and CoffeeScript abstracted away the details and let you just write class Foo extends Bar.

Of course, you could argue that Foo = (Base) -> class Foo extends Base is less complicated and less error-prone, and you'd be right; but I think its benefits would still outweigh the cost of a new keyword - especially because any existing code that uses the word mixin would probably benefit from this addition to the language. Others may disagree.

You make a good point that class Foo extends Bar with Baz1, Baz2 could be added to the language without breaking backward compatibility 👍

@coffeescriptbot
Copy link
Collaborator Author

From @objectkit on 2017-04-22 10:46

Mixins would be a great addition IMO... and I really like the use of the word 'with'. Once upon a time, because of collision with the ECMAScript keyword with I had thought that mimics would have been a better idea, but as with is not used and is a reserved word in CofffeeScript... well, apart from making so much (hypothetical) semantic sense...

class HttpRequest with EventDispatcher

or

class HttpService extends WebService with EventHandler, Component

a new use of the word 'with' in CoffeeScript just seems natural to my eyes. I have to admit, I'd really, really like it.

I could only assume that the mixin would be applied to the class prototype first, which would permit overrides, but it raises the question of what rules apply to overriding a mixin method?

class HttpService extends WebService with EventHandler

    # @override of the EventHandler method by HttpService here
    handleEvent: (event) ->
        if not event instanceof Thing
              # how would one delegate the mixin implementation? 
              super.handleEvent(event)
              # what about execution context?
              EventHandler::handleEvent.call @ event 
              # this magic is messy, but could be achieved 
              super.EventHandler.handleEvent event

Or would the rule be that mixin methods always override class methods?

Or would static methods be ignored or added too?

Or would another rule be that mixin methods are added in the order they are declared? That is, if two or more mixins had the same method, that each would override the others until the end of the mixin chain was reached (i.e. the last method implementation wins and is added to class prototype?

What if instantiation was required by a mixin target and used its own variables?

class X extends Y with Z

    constructor: () ->
        #invoke Y constructor
        super()
        # what about Z?
        Z.call @
        # more messy magic
        super.Z()

Don't get me wrong, I think the path proposed before this comment is a good idea and I'd like to see it happen. I think the caveat would have to be that care would have to be taken by choice and use of mixin implementations. That is, its not really a problem of the CoffeeScript language, but a language feature that can be utilised by developers with a little forethought.

@coffeescriptbot
Copy link
Collaborator Author

From @GeoffreyBooth on 2017-11-26 02:28

Closing as there doesn’t appear to be much interest.

Also, classes seem to be one of the most in-flux features in ECMAScript right now. I think we should avoid introducing new sugars on top of classes for the time being, because ECMA might introduce their own versions. Some future version of ECMAScript could very well introduce an equivalent of class mixins, and if we’ve already released our own sugar for it, and the two are incompatible? Then we’d have a repeat of the mess we went through with classes and CoffeeScript 2, when we had to rework CoffeeScript 1’s classes to be output using the class keyword, and minor breaking changes resulted. We want to avoid reruns of that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant