3 ms·
Nah, that's not the issue. The way the game works is this: 1. Decide on some property you want the compiler to enforce for you. E.g. I care about only operatin
by noelwelsh 14y ago
Nah, that's not the issue. The way the game works is this:
1. Decide on some property you want the compiler to enforce for you. E.g. I care about only operating on values that exist.
2. Encode this in the type system. E.g. use the Option type to distinguish those values that may not exist (Options) from those that definitely do (everything else).
It's not about being able to distinguish valid and invalid values, it about getting the compiler to enforce it for you. This is the real power of modern type systems -- not bookkeeping to keep the optimizer happy but getting the computer to check the things you care about.
- ajross 14y agoHow is you description different from "emulating paradigms like RAII in environments that don't natively support them?". And it doesn't address things like the trivial list/cache case, where clearly you need a null(-equivalent object reference). Clearly the compiler isn't going to be able to enforce that all lists are infinitely long... I'm not saying it's a bad trick. I'm saying that thinking of it as "banning null" is an incomplete understanding of the issue.
- mseebach 14y agoWhen you need a null, you use None.
- fusiongyro 14y agoI hate to say "you should," but you really should spend a few hours going through a Haskell tutorial. You'll be surprised how different things are. The Haskell equivalent to this Scala Option fiasco is Maybe, which is defined as: data Maybe a = Just a | Nothing "Nothing" is not a null reference and "Just a" is not an object with a pointer to another object. "Just a" is a constructor with a single value parameter. "Nothing" is a constructor that takes no parameters. These are values, not references or values with references or references to references. "Nothing" always has a specific type (Maybe Integer, Maybe String, etc.) even though it has no auxiliary data of its own. This means "Nothing" can't show up anywhere you have values--it can only show up where you expect a value of type Maybe. Indeed, the whole point here is that you are forced to explicitly reckon with the possibility of null where it can happen, and you are freed from responsibility to worry about it everywhere else. Haskell does just fine without the kind of null we're talking about, in a way that I suspect is fundamentally different from what you're intuiting.
- NinetyNine 14y agoIn the specific example of the blog post, an isDefined() is still necessary. How is `isDefined()` different than `ref !== null`?
- anonymoushn 14y agoIt 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.
- noelwelsh 14y agoIf 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.
- mseebach 14y agoThe 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; }
- anonymoushn 14y ago