Object.mixin() reacher proposal

Andrea Giammarchi andrea.giammarchi at gmail.com
Sun Apr 14 22:23:17 PDT 2013


not sure changing name is a thing to promote, it makes method name clashing
easier but it can be achieved simply attaching properties to a specific
object and then pass that as mixin ...

Object.mixin(target, {
  on: source.addEventListener,
  off: source.removeEventListener,
  has: source.hasEventListener,
  trigger: source.dispatchEvent
});

As you see there's no need to make the signature more complex with aliases,
it's straight forward to do the same, of course if those descriptor are
meant to be (enumer|configur|writ)able: true)

Agreed on Trait naming convention, but these can be represented only via
Functions in JS.

However, describing them as "not exactly common function" would result in a
better understanding.

So here the API, and the name I am afraid has always been abused in JS but
is known as "mixin"

// basic signature
Object.mixin(
  target:Object,
  source:Object
):target

// one overload
Object.mixin(
  target:Object,
  source:Trait
  [,args:Array|Arguments]
):target

This is probably even better than needed/horrible slice call and
arguments.length check per each mixin invocation with Traits ... so, what
do you think ?






On Sun, Apr 14, 2013 at 8:56 PM, Peter Seliger <peter.seliger at googlemail.com
> wrote:

> Hi, maybe one should discuss terminology first.
>
> What has been rediscovered within the last decade every now and again by
> JavaScript programming individuals, this languages capability for
> "functional or function based mixins", might deserve a closer look, before
> running into what I would call a meta programming temptation trap.
>
> We already have everything we need in order to create modular collections
> of behavior and also in order to provide and apply them to objects.
>
> "Mixin" might be a Ruby influenced term and does not completely cover what
> can be achieved by functions/closures [call] and [apply]. I'd rather tend
> to use Perl 6 "Roles" as a generic term.
>
> The smallest thinkable Role was a function body that implements a single
> method in a stateless way. Thus being a "Trait" if one follows the findings
> of the "Software Composition Group" at Bern University [
> http://scg.unibe.ch/research/traits]. Any implementation that gets
> injected mutable state or does create mutable state on its own in oder to
> solve its task(s) then, from my point of view, should be referred to as
> "Mixin".
>
> > It seems that Mixins Are Awesome and this can take most advantages from
> being a function and not only an object:
> > http://webreflection.blogspot.ie/2013/04/flight-mixins-are-awesome.html
> >
> > AFAIK, all interfaces described in W3C such EventTarget and others could
> be also covered by this proposal ... so ... what do you think ?
>
> Andrea, you are right, but all it needs in my opinion are a module
> pattern, a module library of your choice, a naming convention for your
> Trait/Mixin-module Implementation (adjectives/adverbes, no nouns, first
> uppercase letter?) and again [call] or [apply].
>
> For your given example of W3C interfaces, [EventTarget] should be
> implemented and internally referred to as [EventTargetMixin], but the
> module should expose [EventTargetMixin] as [Observable].
>
> - example gist for Observable [https://gist.github.com/petsel/5385218].
> - example gist for a Trait [https://gist.github.com/petsel/5385163].
>
> There is another point that makes pure straightforward functional
> Trait/Mixin composition unique in JavaScript - passing additional data at
> apply time. One could write e.g. implementations that at apply time can
> adapt the naming of their functional API without changing the underlying
> implementation itself. [Observable] from the above provided  gist example
> enables configuration of the default API method names by an optionally
> passed config object making it
> possible to serve all those weird observable API dialects.
>
> var obj_01 = {};
> var obj_02 = {};
>
> Observable.call(obj_01); /* does add the default api methods
> [addEventListener], [removeEventListener], [hasEventListener] and
> [dispatchEvent] */
>
> Observable.call(obj_02, {
>   addEventListener: "on",
>   removeEventListener: "off",
>   hasEventListener: "hasObserver",
>   dispatchEvent: "trigger"
> }); /* obj_02 does feature the custom api names [on], [off], [hasObserver]
> and [trigger] - the underlying methods are the same as of obj_01 */
>
> With meta programming approaches this advantage, one gets for free now,
> might get lost or if implemented less understandable.
>
> I discarded every single approach I made within the last 5 years for
> Trait/Mixin libraries, that tried to be smarter than what the languages
> core already provides except the last one that just sticks to a module
> library.
>
>
>
>
> On Sun, Apr 14, 2013 at 11:48 PM, Andrea Giammarchi <
> andrea.giammarchi at gmail.com> wrote:
>
>> somebody already raised the concern "what if I want to mixin the function
>> as object, not as callable"
>>
>> I think being [[Call]] not possible to mixin as object functionality, and
>> being functions all by default having ownProperties such ["arguments",
>> "name", "length", "caller"] .. that would simply clash so function as
>> argument, for this purpose, is never ambiguous, but of course a function
>> could be the target object, if needed
>>
>> var withMoar = Object.mixin(function(){}, mixinFunction);
>> // same as mixinFunction.call(function(){});
>>
>>
>>
>>
>>
>>
>>
>> On Sun, Apr 14, 2013 at 2:24 PM, Angus Croll <anguscroll at gmail.com>wrote:
>>
>>> yeah that's better - I was having a senior moment - most constructor
>>> functions will normally reside in the prototype of course
>>>
>>>
>>> On Sun, Apr 14, 2013 at 1:59 PM, Andrea Giammarchi <
>>> andrea.giammarchi at gmail.com> wrote:
>>>
>>>> My previous version was doing that in a probably too smart way so I've
>>>> simplified the proposal simply accepting, in that example
>>>>
>>>> Object.mixin(Thung.prototype, Thing.proottype);
>>>> Object.mixin(Thung.prototype, Thang.proottype);
>>>>
>>>> It does not look so black magic anymore but it's way less ambiguous
>>>> than the first proposal (I guess)
>>>>
>>>> Thanks
>>>>
>>>>
>>>>
>>>>
>>>> On Sun, Apr 14, 2013 at 1:34 PM, Angus Croll <anguscroll at gmail.com>wrote:
>>>>
>>>>> Lending my support to Object.mixin accepting a function as the
>>>>> argument—but no surprise there I guess :)
>>>>>
>>>>> Note: since functional mixins and constructors are syntactically
>>>>> identical we can now get gorgeously expressive—and make type inheritance
>>>>> way simpler (for the first time allowing multiple type inheritance)
>>>>>
>>>>> //make a new thing and a new thang
>>>>> var thing = new Thing;
>>>>> var thang = new Thang;
>>>>>
>>>>> //OR have Thung inherit from Thing and Thang
>>>>> Object.mixin(Thung.prototype, Thing);
>>>>> Object.mixin(Thung.prototype, Thang);
>>>>>
>>>>>
>>>>> On Sun, Apr 14, 2013 at 12:59 PM, Andrea Giammarchi <
>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>
>>>>>> right, I've simplified a lot and tested cross platform:
>>>>>>
>>>>>> https://github.com/WebReflection/object-mixin#object-mixin
>>>>>>
>>>>>> thoughts?
>>>>>>
>>>>>>
>>>>>> On Sun, Apr 14, 2013 at 10:07 AM, Andrea Giammarchi <
>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>
>>>>>>> OK, maybe just code was a non-sense ...
>>>>>>>
>>>>>>> So, the idea behind is mark a function explicitly as mixin ... how ?
>>>>>>>
>>>>>>> Any function that is passed and has an empty prototype (then is user
>>>>>>> defined or native) could be considered invocable as mixin.
>>>>>>>
>>>>>>> function addFunctionality() {
>>>>>>>   this.method = function () {
>>>>>>>     // now the outer context has a method
>>>>>>>   };
>>>>>>> }
>>>>>>>
>>>>>>> // mark the prototype as empty in ES5
>>>>>>> delete addFunctionality.prototype.constructor;
>>>>>>>
>>>>>>> function MyClass() {}
>>>>>>>
>>>>>>> Object.mixin(MyClass.prototype, addFunctionality);
>>>>>>>
>>>>>>> rather than only
>>>>>>>
>>>>>>> Object.mixin(MyClass.prototype, {method: function () {}});
>>>>>>>
>>>>>>> If the prototype has at least one own property in its prototype it
>>>>>>> will be considered a constructor so that:
>>>>>>>
>>>>>>> Object.mixin(MyClass.prototype, MySuperClass);
>>>>>>>
>>>>>>> can easily be transformed implicitly into:
>>>>>>> Object.mixin(MyClass.prototype, MySuperClass.prototype);
>>>>>>>
>>>>>>>
>>>>>>> This case is, however, less important, the fact Object.mixin should
>>>>>>> be able to accept a function and invoke it with target as context with
>>>>>>> optional arguments would be really a **great idea**, IMHO
>>>>>>>
>>>>>>> Thanks
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> On Sun, Apr 14, 2013 at 2:45 AM, Andrea Giammarchi <
>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>
>>>>>>>> also, in case you are guessing the typo .. reacher because it could
>>>>>>>> reach more (older) engines, doing a joke with richer .... got it? .. too
>>>>>>>> damn fun, I know!
>>>>>>>>
>>>>>>>>
>>>>>>>> On Sun, Apr 14, 2013 at 2:04 AM, Andrea Giammarchi <
>>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>>
>>>>>>>>> apologies
>>>>>>>>> getOwnPropertyDescriptor(
>>>>>>>>>     source,
>>>>>>>>>     key
>>>>>>>>> )
>>>>>>>>>
>>>>>>>>> should have been
>>>>>>>>> getOwnPropertyDescriptor(
>>>>>>>>>     enricher,
>>>>>>>>>     key
>>>>>>>>> )
>>>>>>>>>
>>>>>>>>>
>>>>>>>>> On Sun, Apr 14, 2013 at 1:58 AM, Andrea Giammarchi <
>>>>>>>>> andrea.giammarchi at gmail.com> wrote:
>>>>>>>>>
>>>>>>>>>> what I've written here:
>>>>>>>>>>
>>>>>>>>>> https://github.com/WebReflection/object-mixin/blob/master/src/object-mixin.js
>>>>>>>>>>
>>>>>>>>>> is a better proposal for the potential `Object.mixin()` in
>>>>>>>>>> current ES6 specs.
>>>>>>>>>>
>>>>>>>>>> It seems that Mixins Are Awesome and this can take most
>>>>>>>>>> advantages from being a function and not only an object:
>>>>>>>>>>
>>>>>>>>>> http://webreflection.blogspot.ie/2013/04/flight-mixins-are-awesome.html
>>>>>>>>>>
>>>>>>>>>> AFAIK, all interfaces described in W3C such EventTarget and
>>>>>>>>>> others could be also covered by this proposal ... so ... what do you think ?
>>>>>>>>>>
>>>>>>>>>> /*jslint browser: true, forin: true, plusplus: true, indent: 4 */
>>>>>>>>>> (function(Object, mixin) {
>>>>>>>>>>     "use strict"; // happy linter ^_____^
>>>>>>>>>>
>>>>>>>>>>     /* <droppable>
>>>>>>>>>>      * adhoc polyfill section for this purpose only
>>>>>>>>>>      * never use these functions outside this closure ... like ...
>>>>>>>>>> ne*/var
>>>>>>>>>>     /*
>>>>>>>>>> ^ ... you see that? only reason I chose 4 spaces indentations
>>>>>>>>>> here :D
>>>>>>>>>>       also this comment ... pure quality, right ?!?! ... anyway
>>>>>>>>>> ... */
>>>>>>>>>>
>>>>>>>>>>         // for IE < 9 Desktop browsers
>>>>>>>>>>         defineProperty = Object.defineProperty ||
>>>>>>>>>>         function (o, k, d) {
>>>>>>>>>>             o[k] = d.value;
>>>>>>>>>>         },
>>>>>>>>>>         // same as above
>>>>>>>>>>         getOwnPropertyNames = Object.getOwnPropertyNames ||
>>>>>>>>>>         function (o) {
>>>>>>>>>>             var
>>>>>>>>>>                 // in case the guy does not inherit from
>>>>>>>>>> Object.prototype
>>>>>>>>>>                 has = Object.prototype.hasOwnProperty,
>>>>>>>>>>                 result = [],
>>>>>>>>>>                 key;
>>>>>>>>>>             for (key in o) {
>>>>>>>>>>                 // in non ES5 compliant browsers
>>>>>>>>>>                 // there's no way to define properties
>>>>>>>>>>                 // as non enumerable unless these are
>>>>>>>>>>                 // there by default, like "constructor" is
>>>>>>>>>>                 // for functions.prototype
>>>>>>>>>>                 if (has.call(o, key)) {
>>>>>>>>>>                     result.push(key);
>>>>>>>>>>                 }
>>>>>>>>>>             }
>>>>>>>>>>             return result;
>>>>>>>>>>         },
>>>>>>>>>>         // again ... IE < 8
>>>>>>>>>>         getOwnPropertyDescriptor =
>>>>>>>>>> Object.getOwnPropertyDescriptor ||
>>>>>>>>>>         function (o, k) {
>>>>>>>>>>             return {
>>>>>>>>>>                 enumerable: true,
>>>>>>>>>>                 writable: true,
>>>>>>>>>>                 configurable: true,
>>>>>>>>>>                 value: o[k]
>>>>>>>>>>             };
>>>>>>>>>>         };
>>>>>>>>>>     // </droppable>
>>>>>>>>>>
>>>>>>>>>>     // if already defined get out of here
>>>>>>>>>>     // this should be
>>>>>>>>>>     // if (mixin in Object) return;
>>>>>>>>>>     // but for some reason I went for JSLint ...
>>>>>>>>>>     if (Object[mixin]) {
>>>>>>>>>>         return;
>>>>>>>>>>     }
>>>>>>>>>>     // same descriptor as other spec'd methods
>>>>>>>>>>     defineProperty(
>>>>>>>>>>         Object,
>>>>>>>>>>         mixin,
>>>>>>>>>>         {
>>>>>>>>>>             enumerable: false,
>>>>>>>>>>             writable: true,
>>>>>>>>>>             configurable: true,
>>>>>>>>>>             value: function mixin(
>>>>>>>>>>                 target, // object to enrich with
>>>>>>>>>>                 source    // mixin object/function
>>>>>>>>>>             ) {
>>>>>>>>>>                 var
>>>>>>>>>>                     // check if source is a function
>>>>>>>>>>                     enricher = typeof source === 'function' ?
>>>>>>>>>> source.prototype : source,
>>>>>>>>>>                     // per each own property name
>>>>>>>>>>                     keys = getOwnPropertyNames(enricher),
>>>>>>>>>>                     length = keys.length,
>>>>>>>>>>                     i = 0,
>>>>>>>>>>                     key;
>>>>>>>>>>                 while (i < length) {
>>>>>>>>>>                     // define it ...
>>>>>>>>>>                     defineProperty(
>>>>>>>>>>                         target,
>>>>>>>>>>                         key = keys[i++],
>>>>>>>>>>                         // ... via same property descriptor
>>>>>>>>>>                         getOwnPropertyDescriptor(
>>>>>>>>>>                             source,
>>>>>>>>>>                             key
>>>>>>>>>>                         )
>>>>>>>>>>                     );
>>>>>>>>>>                 }
>>>>>>>>>>                 // if the object had no own names
>>>>>>>>>>                 // it's quite clear the intention of the user
>>>>>>>>>>                 // so that if a function without properties
>>>>>>>>>>                 // is passed through this method ...
>>>>>>>>>>                 if (!length && typeof source === 'function') {
>>>>>>>>>>                     // this function is invoked with the target
>>>>>>>>>>                     // as its own context
>>>>>>>>>>                     source.apply(
>>>>>>>>>>                         target,
>>>>>>>>>>                         // optional arguments to initialize
>>>>>>>>>> defaults
>>>>>>>>>>                         // for this mixin might be accepted too
>>>>>>>>>>                         keys.slice.call(arguments, 2)
>>>>>>>>>>                     );
>>>>>>>>>>                 }
>>>>>>>>>>                 // always return the initial target
>>>>>>>>>>                 // ignoring a possible different return
>>>>>>>>>>                 // in latter case: consistency with this method
>>>>>>>>>>                 return target;
>>>>>>>>>>             }
>>>>>>>>>>         }
>>>>>>>>>>     );
>>>>>>>>>> }(Object, 'mixin'));
>>>>>>>>>>
>>>>>>>>>
>>>>>>>>>
>>>>>>>>
>>>>>>>
>>>>>>
>>>>>> _______________________________________________
>>>>>> es-discuss mailing list
>>>>>> es-discuss at mozilla.org
>>>>>> https://mail.mozilla.org/listinfo/es-discuss
>>>>>>
>>>>>>
>>>>>
>>>>
>>>
>>
>> _______________________________________________
>> es-discuss mailing list
>> es-discuss at mozilla.org
>> https://mail.mozilla.org/listinfo/es-discuss
>>
>>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20130414/05159a24/attachment-0001.html>


More information about the es-discuss mailing list