Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

Classes should inherit from mixins

#77

In Prototype and the current FuseJS API, mixins are statically added (via Object.extend) as class methods, instead of inherited and added to the prototype chain. This introduces a particularly nasty gotcha: classes that include a mixin won't reflect any changes or updates to it:

var mixin = {
  "myAwesomeMethod": function(){
    console.log("Howdy!");
  }
};

var Greeter = fuse.Class({
  "greet": function(){
    this.myAwesomeMethod();
  }
}, mixin);

var greeter = new Greeter();
greeter.greet(); //=> "Howdy!"

mixin.myAwesomeMethod = function(){
  console.log("Privet!");
};

//Class doesn't inherit the redefined method!
greeter.greet(); //=> "Howdy!"

Although we may not want to change this behavior due to backward-compatibility issues, I think it's rather unintuitive. It's also interesting to note that Prototype (which emulates a Ruby-like API for JavaScript) deviates from Ruby's behavior:

#Define our mixin (Ruby modules are roughly analogous to JS namespaces)
module Mixin
  #Mixin method
  def my_awesome_method
    puts "Howdy!"
  end
end

#Define our class
class Greeter
  #Include the mixin with our awesome method
  include Mixin
  #Class/instance method
  def greet
    my_awesome_method
  end
end

#Instantiate a `Greeter`
greeter = Greeter.new
greeter.greet # => "Howdy!"

module Mixin
  #Redefine our mixin method
  def my_awesome_method
    puts "Privet!"
  end
end

#Class inherits the redefined method
greeter.greet # => "Privet!"

What do you guys think? Should we update the class API so that all classes automatically inherit from mixins as well?

Reported by Kit Goncharov · June 28th, 2010 @ 01:19 PM

State: invalid
Milestone: none
Assigned to: Kit Goncharov Kit Goncharov

Activity

  1. Kit Goncharov
    Kit Goncharov

    A possible disadvantage of doing this is that we could easily end up with a long prototype chain, especially with multiple mixins and a superclass...

    June 28th, 2010 @ 01:34 PM

  2. Radoslav Stankov
    Radoslav Stankov

    This could be useful (At least in Ruby is useful). The way ruby handles it is adding "something" like ghost classes which point to the mixin. In js we could use the same strategy.

    I'm not sure if this could be done in performance wise ( I could be wrong ). I think I have seen something build whit inherit mixis here - http://jsclass.jcoglan.com, but for every mixin object is actually a class.

    June 29th, 2010 @ 03:57 AM

  3. John-David Dalton
    John-David Dalton

    I didn't think of mixins like that. In fact I made them so they couldn't be used in a way to work with inheritance, (I have checks that stop it).

    September 2nd, 2010 @ 05:50 PM

  4. John-David Dalton
    John-David Dalton

    FuseJS Class API

    var SomeClass = fuse.Class(superclass, plugins, mixins, statics);
    
    SomeClass.addMixins({ ... });
    

    September 2nd, 2010 @ 05:53 PM

  5. John-David Dalton
    John-David Dalton

    Making them update when changed would require some kind of wrapper around the source method that then checks the real method:

    
    //...
     'someMethod': function() {
       return mixin.someMethod.apply(mixin, arguments);
      }
    //...
    

    September 2nd, 2010 @ 05:57 PM

  6. John-David Dalton
    John-David Dalton
    • Milestone cleared.
    • Tag set to enhancement

    September 12th, 2010 @ 01:12 AM

  7. Kit Goncharov
    Kit Goncharov
    • State changed from new to invalid
    • Milestone order changed from 5 to 0

    The general consensus seems to be in favor of keeping the existing Class API due to performance concerns and compatibility with the Prototype API. Closing as invalid.

    February 28th, 2011 @ 10:15 PM

Please Sign in or create a free account to add a new ticket.

With your very own profile, you can contribute to projects, track your activity, watch tickets, receive and update tickets through your email and much more.