Turns out Rust's Option type already has all this behavior, so I think
we're all on to something :)
Option is a little more powerful than nullable pointers because you can
have Options of non-pointer values. IIRC, Option<~T> is actually compressed
to be a nullable pointer. I actually really like the ?T syntax, but I'm not
sure it's worth special-casing Options. I think it's something macros could
handle (convert ?T into Option<T>).
Like your Hack type system, Rust's type system stops you from using an
Option<T> in place of a T (they are different types after all). The basic
way to convert is a match expression, which is equivalent to:
if($maybe_car) { /* Some / non-null case here */ }
else { /* None / null case here */ }
Leaving the else branch off, i.e. leaving None as None, actually
corresponds to either functorial map (Option.map) or monadic bind
(Option.and_then) depending on the return type of Some branch. So your
example could become:
fn demo(maybe_car: Option<&mut Car>, car: &mut Car) {
car.start();
maybe_car.map(|car| car.start()); // ignore the resulting option
}
Rust's Option has it's own version of your invariant function:
Option.expect.
If the Option is Some, then it returns the value therein. If the Option is
None, then it fails and displays a message. Option.unwrap is the same, but
with a default message.
fn demo(car: Option<&mut Car>) {
let car = car.expect("Expected non-null car for the demo");
car.start();
}
Your edge case presents an interesting difference between Hack and Rust.
In Hack, you know $car is non-null inside the if's consequent, but $car is
*still* a nullable pointer ?Car. In Rust, you know car is non-null in the
Some branch of a match, but it's not an Option<Car> anymore! It's just a
Car, so a smashCar method either isn't applicable (it's a method on
Option<Car>s) or it creates a new Option<Car> for us and sets it to None
(an example of a monadic function for Option). In the later case, we'd use
.and_then() to call smashCar and then chain the start call with .map(). The
.map() call would safely evaluate to None.
Thanks for the input!
On Tue, Feb 25, 2014 at 7:24 PM, Aran Donohue <[email protected]> wrote:
> Hey,
>
> I'm not sure how people feel about Option types but there seem to be a
> few hundred uses in the rust codebase. Wanted to share an idea we use in
> our custom type system ("Hack") at Facebook to make it a bit nicer to
> safely deal with null references. We don't use Option types directly. I
> don't think this adds any theoretical power or new possible efficiency
> gains, it's mostly for making the code a bit simpler.
>
> Type declarations prefixed with a question mark represent references
> which might be null. So '?Foo' is somewhat like a shorthand for
> 'Option<Foo>'.
>
> function demo(?Car $maybe_car, Car $car) {...}
>
> We use these like possibly-null pointers. Usually you write an if
> statement prior to using a value.
>
> function demo(?Car $maybe_car, Car $car) {
> $car->start();
> if($maybe_car) { $maybe_car->start(); }
> }
>
> Sometimes we use these in combination with a special function
> "invariant", an assertion function that throws an exception if a condition
> is not met:
>
> function demo(?Car $car) {
> invariant($car, 'Expected non-null car for the demo');
> $car->start();
> }
>
> If you forget to check for null one way or the other, the type-checker
> complains. This is a static, ahead-of-time check.
>
> function demo(?Car $car) {
> $car->start(); // error
> }
>
> There are some natural annoying edge cases to be covered.
>
> class Smash {
> private ?Car $car;
>
> function demo() {
> if ($this->car) {
> $this->smashCar();
> $this->car->start(); // error
> }
> }
> }
>
> A downside of this approach vs. Option is that code written using
> pattern matching over Option is more easily upgraded to code using pattern
> matching over Result (or something else).
>
> Anyway, we like this feature and I'd be happy to see it adopted
> elsewhere. Tossing it out there as I don't know anything about the Rust
> compiler or how language design decisions get made for it :)
>
> -Aran
>
> _______________________________________________
> Rust-dev mailing list
> [email protected]
> https://mail.mozilla.org/listinfo/rust-dev
>
>
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev