#920 What is wrong with this closure?

fury Sat 16 Jan 2010

Suppose I have this code:

static Void main()
{
  m := |Obj->Void| { echo(it)}
}

This dies with the error Invalid use of "it" outside of it-block . What am I doing wrong? Since I didn't specify a name for the parameter, shouldn't it have worked?

kaushik Sat 16 Jan 2010

IDK if I am qualified to answer this but .. here goes...

it blocks are basicaly used in conjuction with method invocation. It's a convinient(and less-noisy) way to invoke a function that takes a closure with one parameter ..

For eg., In you code if you had a function like this..

Void func(|Obj| code){
   //body        
}

You can invoke it in a regular way like this

func |Obj obj|{
 echo(obj)
}

.. or you can use it blocks to do it more elegantly like this..

func{
  echo(it) //it is just obj
}

..but you cannot use both these as..

func|Obj obj|{
  echo(it) //this won't compile.. since you already gave the parameter a name 'obj'
}

Hope that answers your question

fury Sat 16 Jan 2010

Yeah, but I didn't name the parameter in the example above.Even if I change the code to:

static Void main()
{
  m := |Obj| { 
    echo(it)
  }
  m(20)
}

it still gives the same error. Is it unusable with closures?

alexlamsl Sat 16 Jan 2010

From the docs

They omit a function signature and are declared only with curly braces

So I don't think your example is a valid (supported) closure declaration.

fury Sat 16 Jan 2010

I noticed that. However, this doesn't seem like valid syntax either:

m := { echo(it) }

alexlamsl Sat 16 Jan 2010

I don't have the compiler with me right now, but how about:

|Obj| m := { echo(it) }

OT - the last bullet point in that section of the docs:

...outside of its constructor

Is that intentional formatting around its? :-O

fury Sat 16 Jan 2010

Doesn't work. It says: Expected expression, not "{"

alexlamsl Sat 16 Jan 2010

I'm afraid this is out of my hands then :-/

Let's wait for the masters to wake up and enlighten us both.

kaushik Sat 16 Jan 2010

m := |Obj| { echo(it) } m(20) it still gives the same error. Is it unusable with closures?

As far as I know, it blocks can be used only with method invocations. Why would you want to have "it", when you have already named it. why not just use

m := |Obj o|{
 echo(o)
}

I believe that it blocks were introduced to simplify "invocation" of certain kinds of methods rather than simplifying the closures declaration itself.. But yeah.. Lets wait for the masters to enlighten all 3 of us

brian Sat 16 Jan 2010

Closures use the |...| {...} syntax.

It-blocks have special restrictions:

  • they cannot use the |...| syntax
  • they must be appended to a method which takes a function of 1 or more params
  • they cannot use the return statement
  • they have the implicit it parameter

alexlamsl Sun 17 Jan 2010

they must be appended to a method which takes a function of 1 or more params

Would it be a good idea to add that point to the docs as well?

msl Sun 17 Jan 2010

they must be appended to a method which takes a function of 1 or more params

What happens with a method that takes 2 (or more) args if you cannot use the |...| syntax to specify them?

DanielFath Sun 17 Jan 2010

I think it tries to take the leftmost argument.

brian Sun 17 Jan 2010

Functions can accept fewer args than the declaration - see Func Arity

DanielFath Sun 17 Jan 2010

So, I was right. When you try to use it-block on a function that takes multiple parameters (like map.each |Obj value, Obj key|) it will take the leftmost argument (in this case value).

brian Sun 17 Jan 2010

So, I was right. When you try to use it-block on a function that takes multiple parameters (like map.each |Obj value, Obj key|) it will take the leftmost argument (in this case value).

Exactly, in many cases the Fantom API will provide more arguments then you need but you can still use an it-block to use just the first value:

fansh> ["a", "b", "c"].each { echo(it) }
a
b
c
fansh> ["a", "b", "c"].findAll { it <= "b" }
[a, b]
fansh>

Login or Signup to reply.