> maybeT.map(t -> ...).orElse(...)
The author does make a good point that 'get' is unsafe. I think it was a necessary concession to team members who are learning how to program in this manner.
91–100 of 197 posts
> maybeT.map(t -> ...).orElse(...)
The author does make a good point that 'get' is unsafe. I think it was a necessary concession to team members who are learning how to program in this manner.
The author is missing the point. The fact that Optional can result in a nullpointer doesn't mean you should use in the same manner as null-checks. You shouldn't replace: if(x == null) { y = x.doSomething(); } with if(optionalX.isPresent()) { y = x.doSomething(); } You should replace it with: y = Optional.ofNullable(x) .map(ClassX::doSomething) .orElse(null);
The author is missing the point. Is he? The point is that in Java you are still able to treat x unsafely, while languages with stronger typing do not. E.g. in Haskell, if a function returns a Maybe a , it will always be a Just a or Nothing value. Moreover, such languages allow you to make non-exhaustive matching against all constructors a compiler error. tl;dr: Haskell, Rust, et al. put the burden on the compiler. Ja…
Earlier quoted context omitted.
Just to clarify since `unsafe` is a special term in Rust: `unwrap` still checks for None and panics, it doesn't blindly assume it's valid. That said, I think you're too dismissive of "can never fail" assumptions. There's tons of places where something is optional in general, but based on various invariants you know it won't be. For instance, if you successfully acquire the first element in an array, you know you can…
>Gonna have your function return an Err if an internal invariant is broken? Absolutely you should return an error. Whether the caller wants to panic or handle it or print unicorns should be left up to the caller, not your function. Functions should not be expected to tear down the thread in case of an error. Nothing that panics should belong anywhere in exported code
* Index out of bounds on every array op
* Integer overflow on every arithmetic op
* OOM on every allocating op
Maybe if you're writing an ironclad RTOS for a critical system without any good redundancy? Otherwise these are such pervasive operations that most have accepted that they're not worth handling everywhere they happen. Requiring that really dilutes the value/meaning of errors.
Given this signature:
fn do_thing() -> Result
There's a clear signal that there's legitimate error conditions that you probably want to think about today. If every function that accessed arrays, worked with integers, or allocated memory returned a Result, it would border on meaningless. It would be like if there was no Throwable/Exception distinction in Java. Everything would `throw Exception`, eliminating the value of even noting that something can fail.
I think the only way such a system could be tolerable is if the language in question had really good dependent type support (but that wouldn't handle the OOM issue -- which you can't even reliably handle on some systems).
Unwinding/crashing is valuable in a truly robust system, because it needs to handle crashes anyway. Might as well punt obscure problems to that level of the reliability system. (This is basically the basis of Erlang's task system, AFAIK)
Earlier quoted context omitted.
Allowing unsafe unwraps defeats a core purpose of rust, Definitely, but you can also still do this in Haskell ( fromJust ). But it's better than nullable types since you explicitly have call an unsafe method. (Assuming that you have set non-exhaustive pattern matching to be a warning/error.)
unwrap() is not unsafe in Rust, and I don't think Haskell has anything similar?
Earlier quoted context omitted.
unwrap() is not unsafe in Rust, and I don't think Haskell has anything similar?
Sorry for the confusion! I meant 'unsafe' as in partial (not safe for all inputs). Not as in Rust's unsafe keyword.
Earlier quoted context omitted.
>Gonna have your function return an Err if an internal invariant is broken? Absolutely you should return an error. Whether the caller wants to panic or handle it or print unicorns should be left up to the caller, not your function. Functions should not be expected to tear down the thread in case of an error. Nothing that panics should belong anywhere in exported code
The idea is that Err is good if it's a recoverable error, but if it's not recoverable, you should panic!. Most errors are recoverable. panic! is an antipattern in a library. Or at least, provide both a panic-ing and a non-panic-ing variant.
We're actually in the midst of arguing whether to violate this convention and do it for RefCell: https://github.com/rust-lang/rust/issues/27733
import Control.Monad
ex1 = Just 1 :: Maybe Int
ex2 = undefined :: Maybe Int
inc = liftM (+1)
main = do
putStrLn . show $ inc ex1
putStrLn . show $ inc ex2
Yes, you should never use `undefined`. Now replace `undefined` with `null` and it becomes apparent that Maybe and Optional have exactly the same amount of power.Earlier quoted context omitted.
The idea is that Err is good if it's a recoverable error, but if it's not recoverable, you should panic!. Most errors are recoverable. panic! is an antipattern in a library. Or at least, provide both a panic-ing and a non-panic-ing variant.
We specifically recommend against providing panicing and non-panicking. This causes horrible combinatoric explosions. There's very few exceptions to this (array indexing being the major exception). We do of course recommend non-panicking, but there's a few cases where the burden of checking for errors is too high (indexing, refcell). We're actually in the midst of arguing whether to violate this convention and do it…
Earlier quoted context omitted.
Exactly, it forces the programmer to think about whether something can be null or not and actually had a behavioural change in my java coding.
Wouldn't it be better to have a non-nullable type, akin to C++'s return by value? That way, instead of forcing the programmer to think, you are removing the problem that they would need to think about.
Option has other advantages, like its compositional qualities (thanks to Option being a monad). So imagine the following code
def foo(x:Option[String]) = x.filter(_.lengthIf the function returns None if it receives either None or a string longer than 10 characters, and if we got Some("short "), foo will return Some("short More data"). The alternatives without an option type, involve at least a couple of branching statements, even if you have a non nullable type, to convert from nullable to not nullable, while Option does it all for us.
The author is missing the point. The fact that Optional can result in a nullpointer doesn't mean you should use in the same manner as null-checks. You shouldn't replace: if(x == null) { y = x.doSomething(); } with if(optionalX.isPresent()) { y = x.doSomething(); } You should replace it with: y = Optional.ofNullable(x) .map(ClassX::doSomething) .orElse(null);
The author is missing the point. Is he? The point is that in Java you are still able to treat x unsafely, while languages with stronger typing do not. E.g. in Haskell, if a function returns a Maybe a , it will always be a Just a or Nothing value. Moreover, such languages allow you to make non-exhaustive matching against all constructors a compiler error. tl;dr: Haskell, Rust, et al. put the burden on the compiler. Ja…
head []