Edit: Just got to the bottom of the article. Looks like sealed hierarchies is exactly what they explore.
Edit: Just got to the bottom of the article. Looks like sealed hierarchies is exactly what they explore.
functionThatReturnsAnyVal match {
case i: Int if i > 2 => System.out.println("Greater than 2")
case i: Int => System.out.println("Less than or equal to 2")
case s: String => System.out.println("Hello, " + s)
case _ =>
} Object o = functionThatReturnsAnyVal();
if (o instanceof Integer) {
Integer i = (Integer) o;
if (i > 2) {
System.out.println("Greater than 2.");
} else {
System.out.println("Less than or equal to 2.");
}
} else if (o instanceof String) {
String s = (String) s;
System.out.println("Hello, " + s);
}
I get that the case syntax is kinda nice, but this particular example just doesn't seem to get there for me. Roughly half the lines, which is good. None of them hard to reason about. Which makes it a wash.Or is the comparison to something else?
I suppose it's a matter of opinion, but to me the comparison of these two snippets is nowhere near "a wash". The readability of the former is leaps and bounds ahead of the java version, and it will only be more apparent as the example grows in complexity.
And let me be clear. My gripe is only with the example. Not the idea. I happen to like pattern matching, but have never used it like those. Usually I use it to tease apart data by parts. (though, to be fair, I have found I use it less than I thought I did. Not sure why...)
val myOptionalVar: Option[String] = functionThatReturnsOption()
myOptionalVar match {
case Some(str) if str.length > 10 => System.out.println("This is a long string.")
case Some(str) => System.out.println("This is a short string.")
case None => System.out.println("This code would be fifteen lines of null checking in Java.")
} final Optional<String> myOptionalVar = functionThatReturnsOptional();
final String output = myOptionalVar
.map(str -> str.length() > 10
? "This is a long string."
: "This is a short string.")
.orElse("This code would be fifteen lines of null checking in Java.");
System.out.println(output);It's way less code and it makes the resulting code easier to reason about. The code's intent is more elegantly conveyed.
:)
Javas strength has always been to take the good parts of its competitors after they've checked out in production (and not just "wouldn't this be a great idea ..?") and implement them. It will probably never be ahead of the curve due to this, but at least it is remarkably free of "looks good in theory, useless in reality"-features.
It always amuses me to see features of ML, a language from 1973, described as "modern"; e.g. algebraic datatypes, pattern-matching, type inference, parametric polymorphism, etc.
C (from which many popular languages like C++, Java, C#, PHP, etc. are derived) came out in 1972.
I wouldn't say it's a case of being "modern", so much as paying attention to what else has been tried before, rather than sticking with what one already knows (when designing a language).
When does this misconception disappear?
You don't need to be good at math to use functional programming. It's nice that there is a correspondence between math and FP, but it's mostly irrelevant when coding. You could as well say you need a FP background when learning math. Both statements are nonsense and usually spread by people who mostly read complicated blogposts instead of writing actual code using FP.
FP just offers a nice bunch of intuitive and predictable ways of processing information.
I don't agree with this. Many programming concepts outside functional programming can be very hard to grasp, yet we expect students to pick them up, and we expect front-end Web devs to use (some of) them every day.
Some examples off the top of my head:
- Pointers (e.g. the many incompatible meanings of "" in C).
- Classes and instances.
- Implicit state.
- Mutable global state!
- Concurrency (events, continuations, actors, etc.).
- Multithreading. Yes, it's a form of concurrency, but it also offers a unique combination of being a) the default go-to strategy for implementing concurrency, and b) so fundamentally hostile to any attempts at understanding.
- `x = x + 1`. This can be completely baffling when first encountered!
In this context, functional programming doesn't really require anything particularly difficult. Maybe recursion is hard to grasp, but that's not unique to FP; FP just uses it more often, making it harder to avoid. The only thing I can think of that's pretty much a requirement in FP, that we don't already require everyone to grasp, is first-class functions; and they're already pretty widespread in scripting languages.
What about monads? What about denotational semantics? What about cartesian closed categories? What about all that other complicated math stuff? None of it is needed to do FP*! Just grab a small Scheme interpreter, ignore "call/cc" or anything ending in "!", and start coding.
Let's look at, say, the accepted papers from the last OOPSLA (Object-Oriented Programming, Systems, Languages & Applications): http://2016.splashcon.org/track/splash-2016-oopsla#event-ove...
Looking through the titles, I don't know what an "enclave" is, or "conditional future synthesis", or "first-class effect reflection". I have no idea what a "non-linearizable concurrent object" is, or what constitutes a "dependent object type". Does that mean I'm not good enough at math to learn OOP? Not at all; I can just run `python` and start hacking.
Each type has a `.Match` and `.Switch` methods, in to which you have to pass lambdas to handle each case `.Match(Func<T0, TResult, ..., Func<Tn, TResult>`.
I don't know if this would work in Java, given the generic type erasure, but it might...