3 ms·
"If something is wrong, throw an exception." That is sometimes just not an option performance wise yet. "If it's the kind of error that must be handled, throw
by gravypod 10y ago
"If something is wrong, throw an exception."
That is sometimes just not an option performance wise yet.
"If it's the kind of error that must be handled, throw a checked exception. If there's no value to return, return Optional.empty."
Again, why is Optional.empty() better then null? What makes it better? What do you get from throwing an exception? What is the benifit. You can't just say "my way is better" when we have years and years of Java development flying contrary to your statement. What has changed that makes null a non-viable practice?
"The code receiving that Optional<Foo> is now free to do what the author is suggesting: map, filter, all without worrying if the value is actually there or not. The code is cleaner, easier to read, etc."
The code being cleaner is a subjective, or at least extremely difficult to prove, statment. For instance
List<Integer> nums = getNumbers();
if (nums == null) {
S.o.p("Failed to load numbers");
return;
}
for (Integer i : nums)
System.out.println(i);
Is far better then
Optional<List<Integers>> nums = getNumbers();
if (!nums.isPresent()) {
S.o.p("Failed to load numbers");
return;
}
nums.forEach(S.o::p);
Or even better yet
for (int i : nums)
if (i < 10)
S.o.p(i);
VS
nums.filter((n) -> n < 10).forEach(S.o::p);
I don't think that's more readable. It think that's more compressed. HEre's another example. Suppose we have a magical language that I'm sure you'll pick up. It's a very compressed (or as you'd say expressive) language. This is that same code written in it
pa(i i nums < 10)
Which expands to "print all the ints `i` in nums that are less then 10" in english. That's far less readable. It is more compressed. I don't think compression is the goal of a language as much as it is a goal of a zip program. We're supposed to be writing software, not liturature to submit to the shortest story fully told contest. Readability is a function of correct verbosity.
In my opinion. Just compressing your logic doesn't make it more readable. I think some verbosity is needed to preserve simplicity.
"But no one should ever have to check for null anymore. "
I mean that just doesn't make sense. If you're suggesting that there are some times the state of a program should never contain a null value is just ridiculous. Some things are correctly modled by null and some things are also too performance dependant to not use null.
I think some things benifit from using Optional<> but the case doesn't exist to completely remove null. Even just by the creation of a new container object wrapping your already expensive return object there exists a case for null to exist.
Just saying "Don't do it it's bad" is not proof. Saying "the code is cleaner, easier to read, etc" is not proof or even an example of a design that is simpler to pickup and get going with. You'd have to write some code with the Java/OOP paradigms and write a version (that is feature complete) with the FP paradigms and see which is easier to understand for a new programmer. I'd be hard pressed to belive that the FP implementation would be simpler. Maybe to you and me but no to someone without the domain specific knowladge required to understand what's going on. Even when I use map, zip, and list comprehensions in my python code it scares off some of my coworkers.
- mark242 10y agoYour very first method has a return buried in the middle of your code. That is a gigantic red flag. Look, what you're trying to do is simple. getNumbers.fold(println("Failed to load numbers"))(nums => nums.foreach(println)) That's the Scala version, but I'm sure there's a Java version of the same code. This code assumes that getNumbers returns Option[List[Int]], which your compiler can guarantee. If you want something that's a little bit more readable, try this: getNumbers match { case Some(nums) => nums.foreach(println) case None => println("Failed to load numbers") } No null check, no loops, just very simple easy-to-read bulletproof code. This code cannot generate a NPE at all, ever.
- gravypod 10y agoThe first option ins completely unreadable to me. I cannot imagine that ever scaling well. The second option, as I have stated many times in this thread, is far preferable to null. Java does not support it but when it does I will like it. "* No null check, no loops, just very simple easy-to-read bulletproof code. This code cannot generate a NPE at all, ever.*" The NPE isn't the illness, it's the symptom. It's the symptom of a far larger problem in your program: unhandled or otherwise unexpected state. That's why I like the match example. It forces you to expect all of the states of your program. The first example does neither. It hides flow and operation in a single (ever-expanding) line. Far from ideal in any case in my book. As soon as Match is supported in Java I'll change my opinion. Until then I'm stuck. You get nothing better from the Java version in terms of readability.
- mark242 10y agoFold is incredibly important. You should learn it. https://en.wikipedia.org/wiki/Fold_(higher-order_function) https://en.wikipedia.org/wiki/Fold_(higher-order_function) In Scala, the debate between using fold on an Option or using map and getOrElse is almost as old as the language. The method signature for this is: def fold[B](ifEmpty: => B)(f: (A) => B): B That is to say, fold always returns type B, and takes two arguments. The first takes a function returning type B if the option is "empty" (None) and the second takes a function that is called with the contents of the Some. As you can see, it's syntactic sugar for map and getOrElse. def map[B](f: (A) => B): B def getOrElse[B](f: => B): B