what is the equivalent to arguments.callee

66 views
Skip to first unread message

chandra sekhar kode

unread,
Dec 2, 2014, 12:43:33 AM12/2/14
to scal...@googlegroups.com
Hi 
    I am porting this  javascript function to scala.js

 once: function (el, type, callback) {
    var typeArray = type.split(' ');
    for (var i = typeArray.length - 1; i >= 0; i--) {
      el.addEventListener(typeArray[i], function(e) {
        e.target.removeEventListener(e.type, arguments.callee);
        return callback(e);
      });
    };
  },

my scala code : 

def once(element : TopNode , tpe : String, callback : Function1[Event,Any]) = {
tpe.split(" ").foreach(item => element.addEventListener(item,(e : Event) => {
e.target.removeEventListener(e.`type`,?)
callback(e)
}))
}


how can reference my lambda in that place holder ? 

Thank You
Chandra



Sébastien Doeraene

unread,
Dec 2, 2014, 3:25:19 AM12/2/14
to chandra sekhar kode, scal...@googlegroups.com
Hi,

This is a fun question ^^ Actually, since it's a how-to kind of question, the best place to ask it is on StackOverflow, under the scala.js tag. [1] Would you mind to repost it there, and then I'll copy-paste my answer below.

Scala.js does not have an equivalent to the `arguments.callee` of JavaScript. More generally, it does not have an equivalent to `arguments`. So a lambda cannot read a reference to itself, unless it is given to it via its captured environment. This can be achieved by storing the lambda in a `val` in the `once` method. Ideally, one would like to write this:

  def once(element: TopNode, tpe: String, callback: Function1[Event,Any]): Unit = {
    val cb: js.Function1[Event, Any] = { (e: Event) =>
      e.target.removeEventListener(e.`type`, cb) // using cb here
      callback(e)
    }
    tpe.split(" ").foreach(item => element.addEventListener(item, cb))
  }


However, this won't compile, because you cannot use a val (here cb) in the right-hand-side of its definition, even if that happens to be inside a lambda. Trying to do so results in the following compile error:

Main.scala:17: error: forward reference extends over definition of value cb
      e.target.removeEventListener(e.`type`, cb) // using cb here


There is a simple solution, though: use a `lazy val` instead:

  def once(element: TopNode, tpe: String, callback: Function1[Event,Any]): Unit = {
    lazy val cb: js.Function1[Event, Any] = { (e: Event) =>
      e.target.removeEventListener(e.`type`, cb) // using cb here
      callback(e)
    }
    tpe.split(" ").foreach(item => element.addEventListener(item, cb))
  }


Make sure to declare `cb` as a `js.Function1`, not a `Function1`. Otherwise `cb` itself would refer to the Scala function, but not the JS function resulting from the automatic conversion (which have different identities). You have to make sure `cb` refers to the JS function.

Fiddle: http://www.scala-js-fiddle.com/gist/2b848e2f01e7af522dc1

--
You received this message because you are subscribed to the Google Groups "Scala.js" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-js+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/scala-js/bd9de9ad-6eb5-4b36-89e8-082f714bffec%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply all
Reply to author
Forward
0 new messages