1. 15

I used the C and Rust tags since that seemed closest to D. I hope this hasn’t misled anyone.

  1.  

  2. 1

    I recently started using D and I was loving it so far. I bought Alexandrescu’s The D Programming Language. It’s a fun book, teaches a lot about programming in general, and even if you don’t think you’ll use D, I recommend reading this book to get ideas about what programming languages can do.

    Then I ran into this:

    https://issues.dlang.org/show_bug.cgi?id=15994

    The response to this has almost completely demolished my interest in D. It is with a broken hacker heart that I think I need to step away from D. The problem is not that it’s possible to segfault in D or dereference a null pointer in D, as Rust allows this too, but that it’s so easy to do so. The worst part is that the response is to blame the learner instead of blaming the language. If I wanted to be blamed, I would go back to C++.

    I tried to suggest a language change in IRC, such as for example disallowing bare SomeClass someobject; declarations and requiring either SomeClass someobject = new SomeClass(foo, bar, baz); or SomeClass someobject = null; in order to make it explicit that the reference will be null, but everyone in IRC seemed to think that it was impossible to change the D language. This despite how the language is already constantly changing because as the blog post mentions, Phobos is rapidly changing.

    I am going to try to raise this concern again in the D mailing list/forum (it’s actually really cool these two are the same thing). There are so many good ideas in D, and I really loved everything up until I ran into this. Maybe Walter or Andrei will see the importance of making it more difficult to dereference null pointers.

    1. 7

      I find that a bit overly dramatic: The example misuses a (null) reference.

      Could a better compiler warn for this? Sure. Is it the fault of the language that it can happen? Not necessarily, since there is a value type (a struct) that doesn’t expose the uninitialized pointer.

      1. 3

        How would you write the equivalent in Rust? More importantly, would a novice easily write that in Rust? D is supposed to be safer yet it exposes a very easy way to segfault.

        The comparison with structs is even more troubling, as you might think from experience with D structs (or C++ classes) that SomeClass foo; is a valid way of declaring an object. If classes can only be references, the syntax of the language should enforce that. D should be easy to learn, not “you should have…” like C++.

        (Also, the pointer isn’t uninitialised; it’s null. The people in IRC thought it was a good thing to immediately segfault than to attempt to reach undefined address memory that was possibly within reach.)

        1. 6

          Sorry, I haven’t learned Rust yet (I know! I know! It’s on my list…).

          D is supposed to be safer yet it exposes a very easy way to segfault.

          Safer than what? C? Yeah. Than C++? Mostly.

          I come to D from a different point of view, it’s not C or C++ with all the edges filed off and points blunted instead it’s a better set of tools, most with guards, so I only handle the really sharp bits when I have to.

      2. 4

        as Rust allows this too,

        It doesn’t unless you use raw pointers and an unsafe block. Only raw pointers can refer to null or invalid memory. However, you can only dereference raw pointers in unsafe:

        https://doc.rust-lang.org/book/raw-pointers.html

        tl;dr: in normal (safe) Rust, a variable cannot reference null or invalid memory.

        1. 1

          Right, it’s possible, but not easy. It should not be impossible, because a systems language must allow you to do unsafe stuff. It’s totally reasonable to make it hard to do unsafe stuff.

          1. 3

            A null pointer dereference isn’t unsafe (absent mad pointer arithmetic). The process crashes, or in some languages you get an exception. That’s as unsafe as having a bounds-checked array access. (This is not an argument against the point that D might benefit from requiring explicit null-initialization of globals.)

        2. 2

          I’d be interested in seeing your thoughts on Swift, especially after the 3.0 release and Linux port of the Foundation expanded standard library hit this fall. The problem space Swift tries to participate in is probably closer to D’s than Rust’s.

          1. 2

            I’ll have a look. I’ll try to approach it with an open mind. I am generally allergic to Apple products, but I’ll try taking some antihistamines before I look at Swift.

          2. 2

            Do you think there are low-hanging fruit in the compiler to eliminate the most glaring bugs? Or is a borrow-checker the only true solution (or something in between)? I gave up trying to segfault a similar Rust program after too many E0381 errors. Borrow checking seems to work.

            I recently started learning D as well. I like it; it’s very easy to write for someone with a C background, like me. It compiles & runs very quickly, which is great. I still like other ‘systems’ languages better, though (Rust, Swift).

            1. 2

              The only fix without changing the language is to do flow analysis and check for null checks.

              1. 2

                This isn’t a problem for borrow-checking, it’s just explicit initialization checking, which Swift has, and which C# and other languages have had for a while as a warning.

                1. 1

                  I am just reading about borrow-checking right now. I don’t think I quite get it. Can you show me an example of your attempts to segfault in Rust and perhaps explain why they don’t compile? Were you using std::ptr::null?

                  1. 3

                    Sure. This won’t compile unless you uncomment the comment.

                    struct Foo { n: i32, }
                    impl Foo { fn bar(&self) -> i32 { self.n + 42 } }
                    
                    fn main() {
                        let n: Foo; // = Foo { n: 0 };
                        println!("{}", n.bar())
                    }
                    

                    Compiling that:

                    error: use of possibly uninitialized variable: `n` [E0381]
                    src/main.rs:6     println!("{}", n.bar())
                                                     ^
                    

                    Searching for E0381 leads to report_use_of_moved_value, check_if_path_is_moved, and each_move_of.