#1627 recursive closures

jessevdam Sun 28 Aug 2011

I would like to create recursive closure, I think it would be nice to have a "field" me which references to the current closure. This would allow me to create recursive closures, which would be really nice to have.

closure := |Pod pod| 
{ 
  if(processed[pod.name] != null)
    return
  processed[pod.name] = pod
  if(File("fan://${pod.name}/${pod.name}.js").exists)
    out.includeJs(`/pod/${pod.name}/${pod.name}.js`)
  pod.depends.each(closure) //closure not defined yet 
  //pod.depends.each(me) 
}

go4 Sun 28 Aug 2011

this is current closure in java. Maybe fantom need a new keyword. :-)

KevinKelley Sun 28 Aug 2011

it has similar uses in Fantom, and I've wished for it here sometimes, but I kind of think it gets confusing too quick.

The workaround for this is

|Pod pod|? closure
closure = |Pod pod| {...

and now you can recurse on it. Simple enough; a tiny bit verbose, but you're in control of what the names mean, so it works with nested closures or whatever.

brian Mon 29 Aug 2011

I think it might be nice, but accessing yourself in a closure is sort of an obscure functional feature. If we could do it easily, it might be nice - but I don't think it is worth complicating the language. In our case we have already reserved this to access the outer class instance. As Kevin pointed out there is a fairly easily work around.

dobesv Sun 18 Mar 2012

I wished for this too, recently. My use case was that I was calling an asynchronous function and I wanted to call it again, with the same callback, inside the callback. Basically (not real code):

socket.read {
  try
  {
    parseBytes(it())
    read(this) // Read again
  }
  catch(Err e)
  {
    e.trace
  }
}

I've since added a method readContinuously that calls read again for me so I can still use a it-block for my handler without trying to recurse. I'm an it-block addict now, hopefully I won't regret it too much.

In javascript land you do this by giving your closure a name when you define it, like:

function foo(x) { if(x > 0) foo(x-1) }

In Fantom I'm not sure how best to tackle it. Adding a keyword seems a bit much for a rare use case. Perhaps an expression like Func.current would be quite suitable, where the implementation of Func.current is compiler-assisted.

kaushik Sat 24 Mar 2012

I've also been always using kevin's approach too. One slight drawback is that since we are reassigning the closure, which is being called within itself, the closure does not stay immutable anymore(which would otherwise be). Maybe if we can just fix that..

dobesv Sun 25 Mar 2012

Maybe you could use bind instead.

So something like

closure := |Func me, Pod pod| 
{ 
  if(processed[pod.name] != null)
    return
  processed[pod.name] = pod
  if(File("fan://${pod.name}/${pod.name}.js").exists)
    out.includeJs(`/pod/${pod.name}/${pod.name}.js`)
  pod.depends.each(me.bind(me)) //closure not defined yet 
}
list.each(closure.bind(closure))

Should still be const in this case.

Login or Signup to reply.