

Method Combinators in CoffeeScript - grifaton
https://github.com/raganwald/homoiconic/blob/master/2012/08/method-decorators-and-combinators-in-coffeescript.md

======
asolove
While the syntax here is CoffeeScript-specific, this is a perfectly fine
pattern to apply in any JavaScript.

The key is to remember that, in JavaScript, you aren't really "defining
instance methods" in the way you are in almost any other language. You're just
passing anonymous functions as the value tied to some key in a dictionary,
which happens to be the prototype of some set of objects. Once you get that
into your mind and let it play around for a bit, you realize that you could be
getting the anonymous function from anywhere!

From a function-factory, that takes some arguments and returns a function:

    
    
        render: renderWithTemplate("some_template")
    

From an anonymous function wrapped in something that controls its execution:

    
    
        onScroll: _.debounce(100, function(){ /* do something */ })
    

Or even by delegating to another object:

    
    
        viewInstance.onScroll = _.bind(somethingElse.render, somethingElse);
    

Thanks for the great post to help bend our minds around these possibilities.

~~~
Cushman
> Or even by delegating to another object:

> viewInstance.onScroll = somethingElse.render;

This one is a bit dangerous, because as you mention the "methods" are just
anonymous functions assigned to objects. If `render` is expecting to be called
on a `somethingElse`, this might not work right without being bound.

~~~
Xcelerate
That's why I never use "this" in Javascript. For me, dropping any pretense of
OOP allows me to write more elegant programs.

~~~
notb
I think that's a pretty poor practice. It's actually counter to central idea
of this article; that you should think with the language features. In
situations like the one above, if you dont want to lose the context of "this"
you can explicitly bind an object to be this and return the new bound
function. See underscore's bind(). Its a little more verbose and clunky but it
saves you from tossing out modular code.

~~~
Xcelerate
I'm not so sure it's poor practice. Rich Hickey makes an excellent point about
not confounding data and functions. And Javascript provides excellent
structures for avoiding mutability altogether (if one wishes to) thanks to
first-class functions. Javascript was always an amalgam of C-syntax, object-
oriented "ideas", and functional "ideas". To "think with the language
features" is to tie to together two disparate programming paradigms that in my
opinion perform better independently than in combination. So I just happen to
focus more on the functional aspects of Javascript (and CoffeeScript provides
syntactic support to make this much easier).

~~~
MatthewPhillips
Not poor practice in that Functional Programming is poor practice (it's great
practice!). Poor practice in that JS is object oriented and JS engines
optimize for OO style, see <https://developers.google.com/v8/design> for
example. So avoid `this` if you don't care how fast your code runs.

------
goblin89
A little nitpick, which may be a misconception deserving clarification:

> Our decorators work just like Python method decorators, only we don't need
> any magic syntax for them because CoffeeScript, like JavaScript, already has
> this idea that functions can return functions and there's nothing
> particularly magic about defining a method, it's just an expression that
> evaluates to a function.

Python also has this idea (called ‘higher-order functions’). The difference is
in syntax—function calls require parens in Python, and anonymous functions
aren't that well supported. Therefore the need for special syntax construct to
make decorator use convenient.

~~~
raganwald
You're speaking to the first part of my claim, but not the second, namely that
JavaScript and CoffeeScript don't separate the idea of a function and a
method, which is what allows you to use first-class functional combinators as
decorators.

~~~
masklinn
> JavaScript and CoffeeScript don't separate the idea of a function and a
> method

Neither does Python, at definition time. All the difference is in the
processing performed by the class constructor (`type`) when the class object
is created. Before that, it's a bog-standard function.

> which is what allows you to use first-class functional combinators as
> decorators.

Which is exactly like Python, the original decorators[0][1] predate the
syntactic extension by several versions, the original syntax for applying them
was:

    
    
        def some_method(cls):
            pass
        some_method = classmethod(some_method)
    

And you could use the exact same syntax to define non-method functions (though
not this decorator, of course, as it doesn't make sense for functions)

[0]
[http://docs.python.org/library/functions.html?highlight=clas...](http://docs.python.org/library/functions.html?highlight=classmethod#classmethod)

[1]
[http://docs.python.org/library/functions.html?highlight=clas...](http://docs.python.org/library/functions.html?highlight=classmethod#staticmethod)

------
raganwald
Jeremy Ashkenas provides the "tl;dr:"

 _Python decorators are a hack around the lack of proper lambda ;) Just pass
the function: decorate - > … Where "decorate" is a fn_

<https://twitter.com/jashkenas/status/235012485009248256>

~~~
jerf
That makes no sense at all. The lambda complaint is mostly a _syntax_
complaint, it is not a complaint about not having anonymous functions. It even
has the ability to invoke __call__ on instances, allowing you to create your
own "functions" that are actually objects, if you like, which is somewhat
unusual.

There's no point in having an anonymous function decorator. You'd simply
inline it into the body itself right on the spot, anything else would simply
be obfuscation for the sake of obfuscation. This _only_ makes sense if you're
using a decorator applied elsewhere, at which point all languages require you
to have named it, so there's no point complaining about lack of anonymous
functions here.

Python has first-class functions. It even has first-class methods, with
automatic instance binding. It just doesn't quite work how very functionally-
oriented people want it to work. Part of the reason I don't like the kvetching
that such people do is that it does seem to convince people that Python is
lacking function references. Nope. It just doesn't _spell_ them to everybody's
taste (for instance, "it doesn't have Ruby blocks" translates to "it doesn't
have block _syntax_ ", not "it can't do function references", and this is a
taste issue not a fundamental capability issue), and the can rarely have
moderately inconvenient scope rules if you want to write to outer scopes.

Decorators are syntax sugar, not a new feature.

~~~
raganwald
I don't know about those other complaints, I don't personally have any
complaints about Python. It doesn't have multi-line lambdas, that's a design
trade-off like an iPhone not having a slide-out keyboard. But it does have
first-class functions.

[https://en.wikipedia.org/wiki/Python_syntax_and_semantics#Fi...](https://en.wikipedia.org/wiki/Python_syntax_and_semantics#First-
class_functions)

What I was speaking to is the desire to write:

    
    
      class SomeExampleModel:
      
        def setHeavyweightProperty:
          triggers('cache:dirty')(
            lambda self, property, value:
              ...something...
    

My understanding is that Python doesn't like two different things about this.
First, the multi-line anonymous lambda being used as the target of the
decorator. Second, a function being called with another function as its
argument as an expression within an instance method definition.

I'm open to reëducation.

~~~
masklinn
> What I was speaking to is the desire to write:
    
    
        setHeavyweightProperty = triggers('cache:dirty')(
            lambda self, property, value: 'code')
    

is the same thing as

    
    
        @triggers('cache:dirty')
        def setHeavyweightProperty(self, property, value):
            # code
    

but with the limitations of lambdas (no statements allowed)

> First, the multi-line anonymous lambda being used as the target of the
> decorator.

Python has no issue with that, it's just hard to do it because Python's
lambdas can only contain expressions which can be rather limited in a
statements-heavy language.

> Second, a function being called with another function as its argument as an
> expression within an instance method definition.

That's because your "instance method definition" is not syntactically correct,
the capability itself exists. A "method definition" is nothing more than a
function defined within a class scope. In fact you can do things like that:

    
    
        >>> def method_outside(self):
        ...     return self.wedding
        ... 
        >>> class SomeType:
        ...     whose = method_outside
        ... 
        >>> s = SomeType()
        >>> s.wedding = "Amanda"
        >>> s.whose()
        'Amanda'
        >>> method_outside(s)
        'Amanda'
        >>> from collections import namedtuple
        >>> o = namedtuple('N', 'wedding')(wedding="Jim")
        >>> method_outside(o)
        'Jim'
        >>>

~~~
masklinn
Can't edit, but "a function defined within a class scope" should actually be
"a function _assigned_ within a class scope", where and how the function
object was defined does not actually matter (as the example shows), the only
thing which matters is that the object is bound to a name in the class scope.

------
quarterto
In LiveScript:
[https://github.com/quarterto/homoiconic/blob/d6b78812c00eb4d...](https://github.com/quarterto/homoiconic/blob/d6b78812c00eb4df310a9b2067a8a89519419be9/2012/08/method-
decorators-and-combinators-in-coffeescript.md)

~~~
ludicast
Interesting, do like the "implicit currying". And the decorator motivations
read better when they are expressed with the <| rather than when they are just
"escaped line breaks".

