2
\$\begingroup\$

Are we allowed to have multiple functions without the verbose Func-parts which are calling each other as submission?

For example, in Java 8+ this is an allowed answer based on the current meta:

n->doSomethingWithInput

// Which is short for this (Integer parameter & String return-type):
Function<Integer,String>f=n->doSomethingWithInput;

But what if we call one method inside another (1):

n->f(n)+doSomethingMore
f=n->doSomethingWithInput

Are we allowed to post this above, or should we post this instead (2):

n->f.apply(n)+doSomethingMore
Function<Integer,String>f=n->doSomethingWithInput;

Or shorter using a regular method instead of lambda (3):

n->f(n)+doSomethingMore
void f(int n){return doSomethingWithInput;}

Or should it be this instead perhaps (4):

n->f.g(n)+doSomethingMore
F f=n->doSomethingWithInput;

// Where F is an interface like this:
interface F{String g(int n);}

Or should it be this instead (thanks @MartinEnder) (5):

f=n->g(n)+doSomethingMore
g=n->doSomethingWithInput

Personally I'd say (1) should be allowed, or perhaps (4). (For now I've used (3) in some recent Java 8 answer.)
My vote goes to (5), because you clearly see there are two methods (f and g), and function f is calling g).

\$\endgroup\$
  • 1
    \$\begingroup\$ I've always gone with (1), most of the time these answers aren't going to win with any of the options so the shortest is fine IMO at least. (Not at all biased from a C# user...) \$\endgroup\$ – TheLethalCoder Jun 1 '17 at 14:45
  • \$\begingroup\$ Iff f=n->doSomethingWithInput is valid and complete syntax to cause a named function f to be defined in your language then this is fine. Otherwise, it's not. \$\endgroup\$ – Martin Ender Jun 1 '17 at 14:49
  • \$\begingroup\$ @MartinEnder In C# I usually answer with an anonymous functions such as s=>s.Length; which compiles down to a Func<string, int>. Are you saying that s=>.. is fine on its own or I should be writing Func...s=>...? \$\endgroup\$ – TheLethalCoder Jun 1 '17 at 14:52
  • \$\begingroup\$ @TheLethalCoder If you just need a single unnamed function, then s=>s.Length is fine (I don't think you'd need the semicolon, because it's not even part of the expression). The problem only arises when your function needs a name, so that it can be called by itself or another function. \$\endgroup\$ – Martin Ender Jun 1 '17 at 14:53
  • \$\begingroup\$ @MartinEnder Ah good that's how I've been doing it anyway then. Regards to the semicolon I prefer to have it for C# makes it look more correct. Might remove it from now on though... \$\endgroup\$ – TheLethalCoder Jun 1 '17 at 14:56
  • \$\begingroup\$ @MartinEnder "The problem only arises when your function needs a name, so that it can be called by itself or another function." I indeed know we should name our functions if we call it by another method, which is where the f= is for (and which is also required for recursive calls). But does this mean we can leave out the Function<...> part for both methods like in (1) or (4), or should we add it like in (2) or (3)? (Also my bad for both calling them anonymous, when the second obviously is not..) \$\endgroup\$ – Kevin Cruijssen Jun 1 '17 at 15:00
  • 1
    \$\begingroup\$ I don't really know Java well enough to answer that in detail. Mixing named functions and unnamed functions is weird unless we're in a language like Mathematica, where I can write a single expression that both defines a function and evaluates to another. e.g. f@n_:=3n;f@#+1& is a single expression which leaves f defined and then evaluates to an unnamed function which computes 3n+1. However, in Java, a construct like this would not be a single expression but a combination of a full statement and an unnamed expression. \$\endgroup\$ – Martin Ender Jun 1 '17 at 15:05
  • \$\begingroup\$ @MartinEnder Ah ok. So it should be something like g=n->f(n)+doSomethingMore and f=n->doSomethingWithInput instead. A function g which calls function f. I'll add this option to the question, because it indeed seems like the one that is the best to understand. \$\endgroup\$ – Kevin Cruijssen Jun 1 '17 at 15:10
  • \$\begingroup\$ With one anonymous method you'd do s=>DoSomething with two you'd do f=s=>g()+DoSomething, in the second case would you have to include the trailing semicolon as f=s=>g()+DoSomething;? \$\endgroup\$ – TheLethalCoder Jun 1 '17 at 15:18
  • \$\begingroup\$ I shall respectfully disagree with Martin. As I have previously explained in miserable detail s=>s.Length is not fine (at least in my book) because it has no meaning in C# out of context, and (crucially) the meaning depends on the context, and the context is not trivially determinable (i.e. you can't write two more strings which you plaster on either side of an 'untyped lambda expression' to give it meaning). \$\endgroup\$ – VisualMelon Jul 7 '17 at 14:23
1
\$\begingroup\$

This answer assumes C#, I do not believe (explained below) that this can be answered in a way that applies to numerous languages.

As we have discovered, this is not an easy question to answer... This answer is based on my miserable commentary from another question about C# and Lambdas. The reason I do all this talking to start with is because we have half a dozen questions about statically typed languages, and they have achieved almost nothing, so I'm stating (and assuming) some general (language specific) rules that we could use before trying to answer this questions which should be answerable by understanding the general rules about the language (though we can add more specific rules if we wanted). I shall probably write a meta question up about these 'general rules' in due course.

Your code should be self-contained and well defined

We can define 'well defined' on a per language basis. If we want enforcable rules, we have to do this, because it is well recognise that we don't require code that compiles on it's own, so we need per-language rules to decide what is or is not well defined. For example, taking C# as an example (widly applicable to Java): we define 'well defined' code as code which compiles under one of the trivially identifiable and applicable situations below:

As a complete program

That is, something you can stuff in a file, called csc mycode.cs on it and get csc mycode.exe out.

As a member of a class

Example E

Stuff your code into the boilerplate below. You may not define your own boilerplate in your answer, that would be silly.

/*usings here perhaps?*/

class LONGCLASSNAMETHATWONTCLASH
{
    /*submission here*/

    /*calling code (in a method or w/e)*/
}

As a locally defined function

Example F

More C&Ping...

class ANOTHERLONGCLASSNAMETHATWONTCLASH
{
    void LONGMETHODNAMETHATWONTCLASH()
    {
        /*submission code*/

        /* calling code */
    }
}

As an anonymous well-typed method

Example H

And from Martin's prompting, maybe we can even stretch to not requiring you to put brackets around your well typed lambdas:

// taken to be in a method
var result = (/*submission here*/)(/*arguments*/);

Now to answer the question at hand...

.... Assuming all of the above (which we have no consensus on at this time), we have to find a way to fit 2 named function definitions into one of these boilerplates above. This makes everything very simple, your best option is member functions (or local functions (C# 7)):

typename f(typename n)=>g(n)+doSomethingMore;
typename g(typename n)=>doSomethingWithInput;

I'm not sure what the shortest Java code would be under similar rules.

If we agreed to add a surprise semi-colon in the (example) boilerplates, we could often spare ourselves a byte, but would invalidate many answers also. Alternatively, we could be generous and allow either with or without a semi-colon (they should't change the meaning ,but C# can be picky about these things (and given the small space or allowed boilerplate, you could argue it doesn't matter)).

Counter Discussion

Indeed, one could argue that writing one method has a much lower overhead than writing two (and this is what the question is saying). That could be a separate decision, but until we have general rules for languages, it is just going to add to the confusion and misery that is ruling (in particular) on statically typed languages (that is, if you are of a similar miserable school of thought to that I am).

Some sort of delimiter would absolutely be necessary (i.e. you can't just say it is two functions, the code needs to make this clear, and the code that does so must be included in the byte count).

\$\endgroup\$
-3
\$\begingroup\$

Your code needs to compile

Some minor tweaks:

n->doSomethingWithInput

This actually isn't allowed. You are in a manifestly-typed language. You have to declare the type of the input. So, this looks like: (int n)->doSomethingWithInput

// Which is short for this (Integer parameter & String return-type):
Function<Integer,String>f=n->doSomethingWithInput;

It isn't shorthand, the two statements mean different things. The former is a literal function. The latter is an assignment of a function into a variable.

As for the rest of your examples, none of them are valid Java code, so none of them are acceptable.

Some valid submissions:

(int n)->n   
// Function literal.  If you paste this anywhere that wants a function literal, it'll work.


Function<Integer,Integer>f=n->n; 
// Assigning function to a variable.  If you use this variable, it'll just work

Function<Integer,Integer>f=n->n
Function<Integer,Integer>g=n->f(n);
// Two functions, and the second uses the first.
// You'll need to indicate which variable to use in the post


F f=n->doSomethingWithInput;
Function<Integer, String> n->f.g(n)+doSomethingMore
interface F{String g(int n);}
// Because Java only allow 1 interface/class per file, I think we allow them to be inline. 
// I may be wrong, and I can't find a meta post on it

Some invalid submissions:

Function<Integer,Integer>f=n->n
n->f(n)
// This code doesn't compile, no matter where you put it.  
// You can't put it where a function literal is required, 
// You can't put it where statements are required

The above example basically covers all of your examples. If you are able to copy/paste it, and have it compile, it's valid. (Excepting for inline classes/interfaces)

\$\endgroup\$
  • \$\begingroup\$ Ok, I can indeed see your point about the linked meta-post. In java 7 it was for example String f(int n){return doSomethingWithN;} which will now be (int n)->doSomethingWithN in Java 8+, instead of n->doSomethingWithN. "Because Java only allow 1 interface/class per file" This isn't true. You can only have 1 public interface/class per file, but you can have any number of inner non-public classes/interfaces. class M{interface N{String g(int x);}N n=x->"something"+x;public static void main(String[]a){System.out.println(new M().n.g(10));}} is valid. \$\endgroup\$ – Kevin Cruijssen Jun 2 '17 at 22:36
  • \$\begingroup\$ So the consensus is: (1) you must define the parameter types (i.e. (int n)-> instead of n->). And (2) the code must compile if you copy-paste your entire snippet into your program. So (int n)->n+1 is valid. And recursive should be G g=(int n)->n*2;F f=(int n)->g.g(n)+1;. \$\endgroup\$ – Kevin Cruijssen Jun 2 '17 at 22:47
  • \$\begingroup\$ Hmm.. btw, why do we need to define the parameters ((int n)->), but we can still leave out the return-types? Shouldn't we also include the interfaces and/or entire Functions in that case.. Which means i could just go back to Java 7's entire methods instead of lambdas, since it's overall shorter.. >.> \$\endgroup\$ – Kevin Cruijssen Jun 2 '17 at 22:49
  • \$\begingroup\$ The reason you need to define the parameters is because they cannot be inferred. See, in normal Java code, the parameters for a lambda can usually be inferred, based on the surrounding code. However, because we require submissions to be standalone, we have no idea what types are being inferred, which is why we require them. However, return types can be inferred, so no need to declare them. Read the linked post (and the commments) for more detail. \$\endgroup\$ – Nathan Merrill Jun 3 '17 at 3:30

You must log in to answer this question.

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