Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to call "super" from a callback in coffeescript

class Foo
    a: ->
        x.call =>
            super

will not compile as I can't call super from anonymous class. However my intention is to call the superclass method for 'a'. Is this a missing capability in coffeescript?

Note that I change the code to

class Foo
    a: ->
        x.call =>
                return Foo.__super__.a.apply(this, arguments)

to make it work but that just ain't coffeescript right!

like image 676
bradgonesurfing Avatar asked Jun 28 '11 08:06

bradgonesurfing


2 Answers

Your proposed solution of writing out Foo.__super__.a.apply(this, arguments) is, I'm afraid, basically as good as you're going to get. CoffeeScript allows you to write things like

a = ->
  b = ->
    super

(in which case super points to b's super function), so it would be a bit confusing to have super within

a: ->
  x =>
    super

point to a's super function. You could raise an issue to ask for this to be allowed, though. It's not ambiguous from a compilation standpoint, just a bit odd-looking.

Here's something you could try to be a little more elegant:

class Foo
  constructor: ->
    @sup = Foo.__super__

  a: ->
    x =>
      @sup.a.apply this, arguments
like image 114
Trevor Burnham Avatar answered Oct 28 '22 21:10

Trevor Burnham


I've encountered the same problem and solved it like this:

ChainSuper = (classType, memberName, useFatArrow) ->
  original = classType::[memberName]
  superf  = classType.__super__.constructor.prototype[memberName]
  callSuper = (thisRef, args, superArgs) ->
    for i in [0...superArgs.length]
      args[i] = superArgs[i]
    superf.apply thisRef, args

  classType::[memberName] = if useFatArrow
    (args...) ->
      original.call @, args..., (superArgs...) =>
        callSuper @, args, superArgs
  else
    (args...) ->
      original.call @, args..., (thisRef, superArgs...) ->
        callSuper thisRef, args, superArgs

This is very non-kosher and will probably break if the Coffeescript compiler's class semantics change. While waiting for that, however, I'm able to say:

CheckSuper = (ref, message) ->
  if ref instanceof Superclass
    alert "Works with #{message}"

class Superclass
  plus: (values...) ->
    CheckSuper @, 'plus'
    @val = 0
    for i in values
      @val += i
    alert @val

  minusBase: 0
  minus: (values...) ->
    CheckSuper @, 'minus'
    @val = @minusBase
    for i in values
      @val -= i
    alert @val

class Subclass extends Superclass
  plus: (values..., Super) ->
    setTimeout (=> Super @), 0
  ChainSuper @, 'plus'

  minus: (values..., Super) =>
    @minusBase = values[0]
    setTimeout (-> Super values[1...]..., 0), 0
  ChainSuper @, 'minus', true


subInstance = new Subclass()
subInstance.plus 1, 2, 3, 4
minus = subInstance.minus
minus 100, 10, 1

Please notice, that with this solution, if you pass n arguments to a Super() when the method has been called with more than n arguments, only the first n arguments get overwritten in the call to the super method and the rest will be passed on unchanged.

like image 27
Jaakko Salomaa Avatar answered Oct 28 '22 21:10

Jaakko Salomaa