4
\$\begingroup\$

In this meta post, it's decided that function literals are valid when a function is required.

What about lambda expressions in Java 8? These are similar to function literals in other languages, but aren't really the same thing. Actually, these can be used in place of an instance of a functional interface.

For example, to remove the first character of a string:

String f(String s){return s.substring(1);}        // standard method syntax

Function<String,String> f = s -> s.substring(1);  // lambda expression to define function

Object o = (Function<String,String>) s -> s.substring(1);  // works

Object o = s -> s.substring(1)      // compile-time error: Object not a functional interface

Since almost any normal expression can be assigned to an Object, this seems to show that s->s.substring(1) isn't really an instance of a function, but rather syntax that resolves to a function.

interface I {
  public static void main(String[] args) {
      System.out.println("Hello");
  }
  String foo(String s);
}
class C {
  I i = s -> s.substring(1);
}

In this code, the interface I is actually a runnable program. So when s->s.substring(1) is assigned to a variable of type I, it's not clear if this is a function.

Anyway, I'm not really sure about whether these expressions should count as functions. What do you think?

\$\endgroup\$
13
\$\begingroup\$

Speaking as an (opinionated) user, not as a moderator.

Lambda expressions are definitely equivalent to functions; the resulting objects take zero or more inputs, and generate zero or more outputs. Just because they have no inherent type (and needs to be cast to a functional interface type to be reified) doesn't change that.

\$\endgroup\$
  • 4
    \$\begingroup\$ Maybe I'm confused about what's being said here. Is this saying I can delegate my function declaration to an unseen, uncounted interface for any Java answer? For example, what is your take on this golf? (no offense, feersum, just trying to clarify) \$\endgroup\$ – Geobits Feb 4 '15 at 3:11
4
\$\begingroup\$

I'm not an active part of this community, but I'd like to offer an opinion if I may. I'd also like to discuss this from a C# perspective because I'm more familiar with that, and AFAIK C# lambdas and Java function literals are analogous.

Let's take Geobit's linked question as an example.

There is an APL answer and a CJam answer. In the CJam case, the answer is entirely self-contained - you just put it into an interpreter (?) with the input and you get the output. In the APL case, you have to supply the input as part of the program, and a little bit of boilerplate to "call" the answer code, but you'd need that for any APL solution to any problem so we don't include it in the count.

Now, in C#, it's not so simple to get a solution to run. Apparently we score just the length of the full method definition:

void t(int[]s){for(int i=s.Length,t,x;i>0;t=s[x*=new Random().NextDouble()],s[x]=s[i],s[i]=t)x=i--;}

even though in order to compile it into something we could call we need to wrap it in some boilerplate code:

namespace Code
{
    class Golf
    {
        void t(int[]s){for(int i=s.Length,t,x;i>0;t=s[x*=new Random().NextDouble()],s[x]=s[i],s[i]=t)x=i--;}
    }
}

We don't count the namespace and the class because any C# solution to any problem needs the same boilerplate.

So what's the difference with C# with lambdas? This is the C# lambda equivalent of the full method definition above:

s => {for(int i=s.Length,t,x;i>0;t=s[x*=new Random().NextDouble()],s[x]=s[i],s[i]=t)x=i--;}

Again, we can't compile this without adding some boilerplate:

namespace Code
{
    class Golf
    {
        Action<int[]> f = s => {for(int i=s.Length,t,x;i>0;t=s[x*=new Random().NextDouble()],s[x]=s[i],s[i]=t)x=i--;}
    }
}

This is different, though. The Action<int[]> part is not boilerplate because a different solution might need a different delegate definition. Some might need an Action<string[]>, or a Func<int[], int>, or a custom delegate with many or ref or out parameters. Without the delegate definition, the compiler can't compile the function. It's not part of the boilerplate.

If we don't require lambda solvers to include the Action<int[]> x = part of Action<int[]> x = y => {}, why should we expect non-lambda solvers to include the void x(int[] and ) parts of void x(int[]y){}?

\$\endgroup\$
  • 3
    \$\begingroup\$ I think you've misunderstood the situation with boilerplate. The reason that the full method definition of t can be counted without namespace etc. is because the question allows "a full program or a function". If it asked for a full program, the namespace and class definition would have to be counted, along with some code to call Console.Read, parse the result, and write the answer to stdout. Similarly, if the APL code had to be a full program it would require modification. I think you do have an interesting point, but the way you've framed it seems to obscure what that point is. \$\endgroup\$ – Peter Taylor Feb 5 '15 at 10:23
  • 1
    \$\begingroup\$ @PeterTaylor Thanks for your comment. I may well try to reword this but essentially I could TLDR it down to the last paragraph. \$\endgroup\$ – Rawling Feb 5 '15 at 11:04
  • 4
    \$\begingroup\$ A simple take might be that with the full declaration, it could be pasted into any class and work as-is. Without it, you have to paste both the function and something else. I don't see it as any different than requiring import statements to be counted if needed. Yes, they're outside the function, but you need them for the function to work in any given class. \$\endgroup\$ – Geobits Feb 5 '15 at 14:49
  • \$\begingroup\$ @Geobits That's what I was shooting for. Yes, we can see what the lambda means, but in order to actually use it you need to write more code. \$\endgroup\$ – Rawling Feb 5 '15 at 15:02
  • 6
    \$\begingroup\$ I believe that they should be required to count the Action<int[]> x = part. \$\endgroup\$ – SuperJedi224 Jun 30 '15 at 11:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .