- They may be named by variables.
Yes, clearly:
Runnable r = () -> System.out.println("Hello");
Runnable r2 = System.out::println;
I have functions / method references, and I can have named variables that refer to them.
AMBIGUITY:
These variables could also point at actual objects instead:
r = new Runnable() {
public void run() {
System.out.println("Goodbye!");
}
};
Unlike the function syntax example, the above means r
really is pointing at a definite object with defined object-like characteristics. There is a real object in memory and the java lang spec guarantees this.
However, that doesn't matter. In a language like, say, javascript or python, I can assign anything to a variable (variables are untyped in these languages). That doesn't 'make all variables booleans' just because I can assign true
and false
to any variable.
Similarly, in java, to invoke the function, e.g. to actually print Hello
given: Runnable r = () -> System.out.println("Hello");
, I'd have to write r.run()
and not r()
.
That's a debate on syntax, it's not something fundamental. In python, r()
will take the variable r
, will dereference it (follow the pointer), try to interpret what it finds there as a function, and execute it, passing no arguments. If it can't be coerced to a function, an error occurs.
Java is no different. r.run()
will take the variable r
, will dereference it (follow the pointer), try to interpret what it finds there as a function of type Runnable, and executes it, passing no arguments. If what it finds there is not a Runnable (for example, it is null
), an error occurs.
See? identical. Trying to define things in terms of how other languages do things would incorrectly lead one to say that somehow the above is 'syntax sugar' that 'does not count', which is an incorrect conclusion.
- They may be passed as arguments to procedures.
Yes, unambiguously so.
public void runTwice(Runnable r) {
r.run();
r.run();
}
Runnable r = () -> System.out.println("Hello");
runTwice(r);
runTwice(System.out::println);
runTwice(() -> System.out.println("Goodbye!"));
I am passing these functions to java.
- They may be returned as the results of procedures.
Yes, unambiguously so:
public Runnable printMeTwice(String text) {
return () -> {
System.out.println(text);
System.out.println(text);
};
}
Runnable r = printMeTwice();
r.run();
- They may be included in data structures
Yes, unambiguously so:
class Animal {
String name;
Function<Food, Excrement> eat;
}
Animal animal = new Animal();
animal.eat = food -> return food.extractNutrients();
If there's any ambiguity.
Using the specific wording as you pasted it, there is no ambiguity at all, which is somewhat interesting, considering that this question already has answers that either misunderstood or use particularly bizarre interpretations of these words.
One 'weirdness' where java is a little different compared to most other languages is that in most languages, if variable r
holds a function, to do the job of 'dereference the pointer and then execute the function you find when you do so', you'd write r()
. In java you don't do that; instead in java you do r.run()
or r.apply(t)
; in java, functions have named types whereas in most languages they don't. For example, in java I can have the concept of an 'integers-only calculator operation':
IntCalcOp plusButton = (a, b) -> a + b;
and I can have the concept of a 'integer comparing function':
IntComparator highestIsEarlier = (a, b) -> b - a;
and these two things are just fundamentally different. I can't pass a variable of type IntCalcOp
to a method that requires an IntComparator, even though the signatures are functionally entirely identical - both take 2 ints and return an int.
Note that this isn't inherently inferior; in fact, it is probably inherently superior. It's a difference of opinion in language design. To show the benefits of nominal typing and complete lack of implicit conversion, here are 2 very simple object definitions that are functionally identical:
interface Camera {
void shoot(Person p);
}
interface Gun {
void shoot(Person p);
}
In some languages like python and javascript, if I give you a gun and you expected a camera, you kill somebody. In java, that can't happen.
No amount of blathering on about 'but it is syntax sugar' changes any of the 4 snippets above that clearly show that Java's functions are first class elements as per the definition of Structure and Interpretation of Computer Programs.
I don't think that book has a little *
with a footnote that states: "Syntax sugar does not count". If you care to operate with that caveat in place, we'd first need a definition of what syntax sugar even means.
For example, the java language spec does not say that these are turned into anonymous inner class literals. Implementations don't even do that anymore (other answers mention this, and are incorrect in that regard).
A C compiler may work by first emitting assembler code and then running that through an assembler to produce an executable. Does that make all of the C code just 'syntax sugar'? If that's true, C doesn't even have loops.
That kind of reasoning is interesting but for the purposes of determining what a language can do, completely pointless, I think. Essentially, all programming languages are 100% syntax sugar if you dig deep enough.