Problems understading the translation of thenBy.js from JavaScript to CoffeeScript

mattmc3

I need to do some advanced array sorting in CoffeeScript and I came across the thenBy.js micro-library which perfectly fit my needs. It's written in JavaScript, so I translated it to CoffeeScript so that I could use it inline in my .coffee file, and I ran into some problems with the translation. This doesn't work:

firstBy = ->

  # mixin for the `thenBy` property
  extend = (f) ->
    f.thenBy = tb
    return f

  # adds a secondary compare function to the target function (`this` context)
  #which is applied in case the first one returns 0 (equal)
  #returns a new compare function, which has a `thenBy` method as well
  tb = (y) ->
    x = this
    return extend((a, b) ->
      return x(a, b) or y(a, b)
    )
  return extend

However, if I wrap with parens and put on trailing parens, it does work:

### Notice the starting paren
firstBy = (->

  # mixin for the `thenBy` property
  extend = (f) ->
    f.thenBy = tb
    return f

  # adds a secondary compare function to the target function (`this` context)
  #which is applied in case the first one returns 0 (equal)
  #returns a new compare function, which has a `thenBy` method as well
  tb = (y) ->
    x = this
    return extend((a, b) ->
      return x(a, b) or y(a, b)
    )
  return extend
)() ### <- Notice the ending parens

I'm having a no luck understanding why putting those trailing parens on the thing causes it to work. I understand that I have an anonymous function, and I'm then calling it with those parens (see this answer), but why does that work?

mtoor

The trailing parens are calling the function larger function (the one defined as firstBy in your first example), effectively setting the variable to the function's return value: the extend function. In other words:

# Let firstBy1 be equivalent to your first definition, and
# firstBy2 equivalent to your second. Then
# firstBy1() is functionally equivalent to firstBy2

console.log firstBy2
### logs:
#   function (f) {
#     f.thenBy = tb
#     return f
### }

# So:
func = (x, y) ->
  # ... some comparison of x and y...

foo = firstBy2(func) # or `foo = firstBy1()(func)`
console.log foo.thenBy
### logs:
#   function (y) {
#     x = this
#     return extend(function (a, b) {
#       return x(a, b) or y(a, b)
#     })
### }

This is probably best illustrated with an example:

# For brevity/clarity...
firstBy = firstBy2

randomNums =
  { attr1: 1, attr2: 2 },
  { attr1: 2, attr2: 8 },
  { attr1: 4, attr2: 2 },
  { attr1: 5, attr2: 2 },
  { attr1: 5, attr2: 3 },
  { attr1: 6, attr2: 1 },
  { attr1: 3, attr2: 1 },
  { attr1: 2, attr2: 4 }

func1 = (x, y) ->
  if x.attr1 == y.attr1
    return 0
  if x.attr1 > y.attr1 then 1 else -1

func2 = (x, y) ->
  if x.attr2 == y.attr2
    return 0
  if x.attr2 > y.attr2 then 1 else -1

When we call...

randomNums.sort(firstBy(func1).thenBy(func2))

...firstBy(func1) is evaluated first. It returns func1 with a thenBy attribute:

func1 = (x, y) -> 
  if x.attr1 == y.attr1
    return 0
  if x.attr1 > y.attr1 then 1 else -1

func1.thenBy = (y) ->
  x = this
  return extend((a, b) ->
    return x(a, b) or y(a, b)
  )

So then, calling firstBy(func1).thenBy(func2) calls the newly added thenBy parameter attached to func1, yielding:

func1.thenBy(func2) =
  extend((a, b) ->
    func1(a, b) or func2(a, b)
  )

The extend function then applies another (uncalled) thenBy attribute to this anonymous function, yielding the final function that sort uses to order randomNums. It's basically calling func1 on each pair of numbers in the array, and in the event that func1 returns 0 (when the attr1's of each object are equal), then func2 is evaluated on the same pair. This can be extrapolated endlessly with more calls to thenBy. In the end, our function call returns:

[
  { attr1: 1, attr2: 2 },
  { attr1: 2, attr2: 4 },
  { attr1: 2, attr2: 8 },
  { attr1: 3, attr2: 1 },
  { attr1: 4, attr2: 2 },
  { attr1: 5, attr2: 2 },
  { attr1: 5, attr2: 3 },
  { attr1: 6, attr2: 1 }
]

Hope that helps!

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

Understading this perfect forwarding example

From Dev

CoffeeScript comments in JavaScript output

From Dev

javascript - Coffeescript & Backbone.js - TypeError: this._ensureElement is not a function

From Dev

CoffeeScript translating to jQuery in JS

From Dev

Understading permutations

From Dev

Load a javascript/coffeescript file only for one view in Sails.js

From Dev

Understading the Recall function in R

From Dev

Coffeescript/Javascript loop not executing

From Dev

'Translation from jQuery to JavaScript'

From Dev

How to pass variables from gulp to javascript or coffeescript assets

From Dev

My translation from Ruby to JavaScript gives different results

From Dev

View CoffeeScript as Compiled JavaScript

From Dev

Convert coffeescript function to javascript

From Dev

Big O notation and not understading from class lecture

From Dev

Translate d3.js JavaScript function to CoffeeScript

From Dev

CoffeeScript function compilation problems

From Dev

_.extend is undefined in js code generated from coffeescript

From Dev

JS convert to Coffeescript

From Dev

CoffeeScript is converted into wrong javascript

From Dev

Formatting Javascript into CoffeeScript

From Dev

Load a javascript/coffeescript file only for one view in Sails.js

From Dev

Coffeescript/Javascript loop not executing

From Dev

Reveal.js html5 video and javascript - restarting video playback from beginning on slide change problems

From Dev

Converting Javascript to Coffeescript

From Dev

Keeping indent after compiling from coffeescript to javascript?

From Dev

Javascript compiled from coffeescript browser compatibility

From Dev

Idiomatic Scala.js translation of JavaScript short circuit evaluation

From Dev

Converting application JS to CoffeeScript

From Dev

Translation from JS to Java

Related Related

  1. 1

    Understading this perfect forwarding example

  2. 2

    CoffeeScript comments in JavaScript output

  3. 3

    javascript - Coffeescript & Backbone.js - TypeError: this._ensureElement is not a function

  4. 4

    CoffeeScript translating to jQuery in JS

  5. 5

    Understading permutations

  6. 6

    Load a javascript/coffeescript file only for one view in Sails.js

  7. 7

    Understading the Recall function in R

  8. 8

    Coffeescript/Javascript loop not executing

  9. 9

    'Translation from jQuery to JavaScript'

  10. 10

    How to pass variables from gulp to javascript or coffeescript assets

  11. 11

    My translation from Ruby to JavaScript gives different results

  12. 12

    View CoffeeScript as Compiled JavaScript

  13. 13

    Convert coffeescript function to javascript

  14. 14

    Big O notation and not understading from class lecture

  15. 15

    Translate d3.js JavaScript function to CoffeeScript

  16. 16

    CoffeeScript function compilation problems

  17. 17

    _.extend is undefined in js code generated from coffeescript

  18. 18

    JS convert to Coffeescript

  19. 19

    CoffeeScript is converted into wrong javascript

  20. 20

    Formatting Javascript into CoffeeScript

  21. 21

    Load a javascript/coffeescript file only for one view in Sails.js

  22. 22

    Coffeescript/Javascript loop not executing

  23. 23

    Reveal.js html5 video and javascript - restarting video playback from beginning on slide change problems

  24. 24

    Converting Javascript to Coffeescript

  25. 25

    Keeping indent after compiling from coffeescript to javascript?

  26. 26

    Javascript compiled from coffeescript browser compatibility

  27. 27

    Idiomatic Scala.js translation of JavaScript short circuit evaluation

  28. 28

    Converting application JS to CoffeeScript

  29. 29

    Translation from JS to Java

HotTag

Archive