4 ms·
It is worth noting that in Haskell you don't have something like NullPointerException (the type system won't allow for that), and using Maybe actually is a bit
by rednum 14y ago
It is worth noting that in Haskell you don't have something like NullPointerException (the type system won't allow for that), and using Maybe actually is a bit different than writing 'if (obj != null)' everywhere, if you are into stuff like monads or functors. Besides, in Java null pointer can pop up pretty much everywhere, but in Haskell you probably shouldn't store all your data in Maybe.
- irahul 14y ago> It is worth noting that in Haskell you don't have something like NullPointerException, the type system doesn't allow for that - so while you're point is relevant to Java it doesn't hold here. The closest you can get to something like null pointer is using 'maybe' type, but when you do so, you have to everywhere explicitly handle what happens if variable has no value (or the value of 'nothing' more precisely). Which, as I mentioned, isn't any different from checking from nulls everywhere. Or if you are so inclined, write an Option class with the desired interface and use it everywhere where the value in nullable. My point is using Maybe is the same as manually checking for null. case maybeValue of Just value -> ... Nothing -> ... is the same as if (val != null) { .... } else { ... } If you see the compiler forcing you to always use Maybe for nullable types as an advantage, good for you. Personally, I don't see it as a big deal.
- rednum 14y agoThat's right, I've changed my comment to be more relevant reply, sorry for confusion. > If you see the compiler forcing you to always use Maybe as an advantage, good for you. Personally, I don't see it as a big deal. One of reasons I like Maybe is I can accidentally put null somewhere I know I should not; Haskell's type system will prevent me from that. I wouldn't use Maybe unless I really need to - whereas in languages with less strict type systems, almost everything is a 'Maybe'. Besides, it seems it's easier to build some layer on abstraction on it, which you can reuse and save some time (for example, you have monad instance for it - however I don't think I've ever used it).
- irahul 14y ago> whereas in languages with less strict type systems, almost everything is a 'Maybe' I don't know Haskell(I do know F#), so help me with this: How is everything not a Maybe in Haskell? In the languages I know, when you return an object from a method, (it can throw an Exception or return null) or return a valid val. When it throws an Exception, there is no Maybe, or else it's a Maybe. How is it any different in Haskell.
- CookWithMe 14y ago> isn't any different from checking from nulls everywhere You would only check for nulls "everywhere" if all functions could potentially return null. Then, indeed, there is no difference. But (hopefully) not all functions will return null, so you'll probably have at most a single-digit percentage of functions that do. The point is that by using Option, you are explicitly stating "This function can return null", making it impossible for the caller to ignore. If you write it somewhere into the docs, it is indeed easy to overlook. This may not be as relevant when you are only working with your own code, but I find this (and static typing in general) most helpful when dealing with code from someone else, including the libraries one uses.
- irahul 14y ago> But (hopefully) not all functions will return null, so you'll probably have at most a single-digit percentage of functions that do. In a real world API, almost everything that returns an object can return null or throw an exception. > The point is that by using Option, you are explicitly stating "This function can return null", making it impossible for the caller to ignore. Throw an exception if impossible to ignore is the motive. > If you write it somewhere into the docs, it is indeed easy to overlook. It might be overlooked. But is it too much to assume that someone making a call will check the parameters and the return type?
- CookWithMe 14y agoThere is a fundamental difference between throwing an exception and returning null. From http://en.wikipedia.org/wiki/Exception_handling http://en.wikipedia.org/wiki/Exception_handling: "Exception handling is the process of responding to the occurrence, during computation, of exceptions – anomalous or exceptional situations requiring special processing – often changing the normal flow of program execution." One should throw an exception when an anomalous situation appears, e.g. I can not connect to the database. Whereas returning null / returning an Option means that this case needs to be treated in the normal flow of execution, e.g. asking a Person-object for it's spouse. It is perfectly reasonable that a random person isn't married (so throwing an exception is wrong) but at the same time it should be impossible for the caller to ignore. > It might be overlooked. But is it too much to assume that someone making a call will check the parameters and the return type? http://news.ycombinator.com/item?id=4695587 http://news.ycombinator.com/item?id=4695587 Apparently it is too much to ask, even if the program is performing something super-important for security like SSL.
- eklerks 14y agoYou don't have to handle it everywhere explicitly. This is where Functor, Applicative, Alternative, Monoid and Monad are for. They will do the plumbing for you. Eventually you will unpack the values, but this is only necessary if you change environment. Say we have a failing computation: failComp = Nothing and a couple of succeeding computations: sucComp = Just 1 sucComp2 = Just 2 We can use the typeclasses to avoid explicit unpacking: -- Monad result: Just 3 add = do x <- sucComp2 y <- sucComp return $ x + y Applicative result: Just 3 -- the <#> should be the applicative operator. addapp = (+) <$> sucComp <#> sucComp2 Alternative: result (Just 1) val = failComp <|> sucComp Monoid: result (Just 2) mon = failComp <> sucComp2 Functor result (Just 6) -- # should be multiply operator func = fmap (#3) sucComp2
- dbaupp 14y ago(It's a little late now, but if you indent a line by 2 or more spaces, HN will format the text as code, so you don't lose the formatting.)
- jefffoster 14y agoIn Java, the compiler won't tell you that a variable may be null. In Haskell (at least when you compile with -Wall, strange this particular warning isn't the default) you'll get an error if you've failed to handle all the variations of data that you've provided. There's a good presentation my Yaron Minsky about OCaml in the real world where he cites this as a major advantage (in OCaml, failing to match all patterns is an error by default).
- irahul 14y ago> In Java, the compiler won't tell you that a variable may be null. In Haskell (at least when you compile with -Wall, strange this particular warning isn't the default) you'll get an error if you've failed to handle all the variations of data that you've provided. Connection con = DriverManager.getConnection( "jdbc:myDriver:myDatabase", username, password); Statement stmt = con.createStatement(); ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM Table1"); while (rs.next()) { int x = rs.getInt("a"); String s = rs.getString("b"); float f = rs.getFloat("c"); } It's not that bad. In the above example, you either get an SQLException or a ResultSet. ResultSet is your option type here. It wont' be null - it might or might not contain values. There might be a lot of good things about Haskell(I am not that familiar to make a call), but seriously, Maybe doesn't look that great.
- tmhedberg 14y agoMaybe is a monad, which means Maybe computations can be chained together with `>>=` (or using `do` notation) without checking for `Nothing`. You can easily produce a large composition of potentially-failing computations while completely ignoring the possibility of failure. The case analysis you give as an example is only required at the point when you want to extract the final result into a different monadic context, and even then you would typically use the `maybe` or `fromMaybe` functions to make it more concise. Only a novice Haskell user would write: case comp1 of Nothing -> handleFailure Just r1 -> case comp2 r1 of Nothing -> handleFailure Just r2 -> case comp3 r2 of Nothing -> handleFailure Just r2 -> handleResult r3 which is indeed, just as bad as explicit null checking in C or Java, with runaway indentation to boot. But anyone who understands Haskell's rich abstractions would instead write: maybe handleFailure handleResult $ comp1 >>= comp2 >>= comp3 The fact that you can't forget the "null check" without the compiler telling you about it is a nice convenience afforded by the strong type system, but it's far from the only benefit.
- irahul 14y ago> Maybe is a monad, which means Maybe computations can be chained together with `>>=` (or using `do` notation) without checking for `Nothing`. You can easily produce a large composition of potentially-failing computations while completely ignoring the possibility of failure. Like val = foo.bar.blah.boo rescue nil Or try { val = foo.bar().blah().boo() } catch(NullPointerException ex) { } Or try: val = foo.bar().blah().boo() except AttributeError: pass Yes, I know Maybe is a monad, but that doesn't make a difference to me. A series of computation where a step depends on the results of the previous step and the previous step can return null is hardly an issue in any language. > The case analysis you give as an example is only required at the point when you want to extract the final result into a different monadic context, and even then you would typically use the `maybe` or `fromMaybe` functions to make it more concise. The case analysis I give is an example where either there is a value or null and I need the value. I don't really care how Haskell defines monadic context.