The difference is that you can distinguish at the type level between values that could be "null" (Optionals) and values that are never null, and the two look different from each other. Otherwise you tend to have one of two problems:
a) Every function checks all its parameters for null, and you do null checks before calling a method on any object, wasting time.
b) It's down to the programmer to figure out where a null check is necessary and where it isn't, and they sometimes get it wrong.
(Of course, better code will avoid calling isDefined or get, but even if you just use it as a like-for-like replacement, using optionals in place of null can improve your program)
Null checks in java are quite cheap, from what I've read.
If your code doesn't check for a null, JIT adds in an implicit check in case it needs to throw a NullPointerException. When you put a check in your code, it knows to eliminate the implicit check.
Putting null checks everywhere does lead to ugly, complicated-looking code though; it'd be nice if there were a simple syntax for non-null parameters.
It's not really about computational expense. It's about making reliable, maintainable software.
The problem with null is that it's a semantic gremlin. Depending on context it could mean all sorts of things including but not limited to, "the value has not yet been set", "the value is undefined", "the value is nothing" or "the software is broken". Which one of those is the correct interpretation at any given time is a question that can only really be answered by a programmer with a good knowledge of the codebase.
Worse yet, even in cases where null isn't a desired behavior it's still inescapable. If your procedure accepts reference types as parameters, it doesn't matter if it has no interest in taking null as an argument, or that it doesn't even make any sense (semantically) for null to be passed as an argument. It still has to be prepared to be handed null as an argument. At a language level, there's simply no support for the concept of, "Guys, I really do need something to go here." Which is simply insane, considering how simple a concept it is.
In languages that don't have null references, it's not that the various semantic meanings of null have been thrown out. All that's been removed is the ambiguity: For each possible (desirable) meaning, a construct is provided to represent specifically that meaning. Meaning that you've gotten rid of the problem of programmers having to magically know what null means in that case, and the worse problem of programmers introducing bugs resulting from them failing to understand null's meaning in a particular context.
It isn't. The difference is that in all the places where you don't use Option[T], you no longer have to have a null check because you have "banned null."
This doesn't seem like a particularly good idea if any of your code needs to run reasonably quickly. Even relatively tame uses of Option[T] in the collections that ship with scala can have a terrible impact if you want to run the code rather than just typecheck it. For instance, if you have some loop in which you want to perform I/O and call getOrElseUpdate on your scala.mutable.HashMap[T, Long], your code will probably spend a majority of its time creating millions of java.lang.Longs, stuffing each one into its own newly-minted Some[Long], and GCing these two things.
If you changed reasonably quickly to extremely quickly I would agree. There is some overhead involved but it is very small. In a copying collector, like the 1st generation of Hotspot's generational GC, the GC cost is proportional to the amount of non-garbage you allocate. Creating lots of very short-lived objects is almost free (allocation is very fast in all GCs). The cost is in memory consumption -- a classic tradeoff of time for space.
Of course if this is an issue you can always fall back to Java's collections or a collection class specialised to Longs. I think the Scala implementors made the right tradeoff for a general purpose library.
The idea is that you don't want to call isDefined at all - you'll want to call getOr(T default) or pass it through a chain of methods that are overloaded doFoo(Some<T> x) { .. stuff .. return Some<U> }/doFoo(None x) { return None; }
a) Every function checks all its parameters for null, and you do null checks before calling a method on any object, wasting time.
b) It's down to the programmer to figure out where a null check is necessary and where it isn't, and they sometimes get it wrong.
(Of course, better code will avoid calling isDefined or get, but even if you just use it as a like-for-like replacement, using optionals in place of null can improve your program)