Memory Safety in a Modern System Programming Language Pt. 1
dlang.org
dlang.org
A lot of languages are going this direction too:
* Cone is putting a full borrow checker on top of GC, RC, and single ownership: https://cone.jondgoodwin.com/
* Vale is putting opt-in "region borrow checking" on top of single ownership with generational references: https://verdagon.dev/blog/zero-cost-refs-regions
* Lobster is employing an automatic-borrow-checker-esque algorithm on top of RC for some brilliant speedups: https://www.strlen.com/lobster/
* Ante has some designs for lifetime inference, which I think will work really well: https://antelang.org/
* HVM is a runtime for Haskell that uses borrow checker semantics and falls back to clone. It's not shared mutability, but Haskell without GC is pretty cool! https://github.com/Kindelia/HVM
I particularly like D's approach because it's opt-in; we can use it in the areas of the program where we need performance the most, and prioritize flexibility and development velocity everywhere else, which I think is the right balance for most programs developed today.
It also means one can gradually ease into learning how to use static analysis and their more complex constructs (like return scope, mentioned in the article). One can be proficient in the basic language quickly, and then improve their craft gradually. In modern software engineering, this is a big win, in my opinion. Props to D for going this direction!
But I can’t help but feel a bit overwhelmed with options, and I know very few will ever catch on.
At least D seems to have some momentum, but I have fallen into the trap before of learning new languages that die.
I want to learn one of these, but I want it to last!
I would be very interested in any advances in the Rust realms that could address the added complexity! I haven't heard much coming from that direction. Polonius sounded like it would remove some edge cases from borrow checking, but it didn't seem like it would really help with the fundamental complexities from borrow checking.
Side note, D has source code tools, this being probably the most famous one: https://github.com/dlang-community/D-Scanner . It's just that I don't use them myself.
Linting in a way that requires semantic analysis is not well trodden ground in D tooling.
deadalnix and myself are aiming to rectify this somewhat by ramping up work on sdc, which is basically a D frontend done right.
https://news.ycombinator.com/item?id=7692230
(25 points, 16 comments)
But since you asked, I think I should make my guess. I think people tend to use what life brings them to. Most will not voluntarily go hunting for the best language the Internet has to offer for them. So the languages become popular by forcing people to learn them, by having them to use them at their jobs or implementing important APIs in them. This means that what the project managers of big organisations have enthusiasm or business reasons to push tends to end up popular, not what is preferred by the common programmer. D is largely a free-time volunteer effort AFAIK so it does not get as much corporate influence than it would get if it were an academic or commercial effort. But again, that is just a gut guess, no research to back this up.
I also think there is a cost to using a non-mainstream technology that is often overlooked or under-estimated. I also think the benefits of non-mainstream languages are often over-stated. In other words, when you really look at the details the cool/niche languages do often have notable drawbacks. I suspect that for most organizations the pro/con or cost/benefit comparisons of C++ vs. D don't often come out in D's favor and never did.
In the early days D chose to use GC which today, and for the past 30 years I have done C++ work professionally, has always been a dis-qualifier (mainly because of the extra memory overhead involved as well as the GC pauses). I have always looked at D with some interest, but never come close to formulating an argument that I could take to my company and suggest we start using D where we currently use C++. C++ almost uncompromisingly holds true to its backwards compatibility goals with C and the early versions of itself. C++ also almost always holds true to its "zero overhead abstraction" goals. D chose GC and replaced its standard library at one point. It is an interesting language for sure, but I think there are some things C++ has done better, from a practical use point of view, at least for the use cases where its use is still justified today, by being a more conservatively designed language.
C++ likes to prattle on about zero cost abstractions but the cost is nearly always to the programmer - and even then D does a lot of the zero cost concepts like templates objectively better than C++: Write a struct with N members in C++ (e.g. for autodiff), you're looking at a page full of recursive templates and SFINAE. With D it's orders of magnitude less code because it was specifically designed to avoid this kind of nonsense that C++ has conditioned people to think is worthwhile.
GC makes it look like you won't do low-level things (e.g. pointer tagging or very-hand-optimized hot loops which might need to temporarily discard any and all safety), and being called a "systems language" makes it look like not very high-level either. Emphasis on "looks like" - not many will get to the point of actually looking for the options (especially when in a more opinionated language you don't even need to, as there either is an obvious way, or there's none).
Rust managed to stay distant enough from Java-likes (mostly due to manual memory management), and Go is pretty distant from C all things considered (but I'm not too sure why it's so popular. Probably more just being backed by Google?)
Maybe this is true, I don't know, but to be clear other than the C runtime the language can be entirely implemented in D. You can do all these tricks and patterns easily and D and even have the compiler generate them for you (e.g. build your own loop unroller using metaprogramming if needs be), but I think people don't believe it to be true because of aesthetics.
The GCC static analyzer is actually clever enough to spot these types of bugs (memory ones anyway, not database handles) but this doesn't scale.
EDIT: Even slices do not mandate using the GC. The GC will only collect arrays registered to it in the first place. If the slice was malloced, it is not registered and thus won't be collected. The built-in ~ operator allocates the new array with the GC though, so you have do something custom to concatenate slices in GC-free code.
This is the most cursed definition of "memory safe" I have ever seen. I think the article would benefit from a link to https://dlang.org/spec/memory-safe-d.html explaining explicitly that this is actually what you intended to write, because it made me do a double-take and a Google when I read it.
I'm familiar with a few arguments w.r.t. large structs and arrays running past the protected pages, but they seem pretty trivially solvable. Would love to hear why it's a cursed definition.
Now, detecting such errors statically at compile time is still valuable where it is practical. But it's common knowledge that no language guarantees no bugs. It follows that a complete "no crashing" guarantee is not even desirable, let alone part of a memory safety guarantee.
Those protections are there as last ditch safety measures. You shouldn't rely on them .
Who on Earth wrote this? This is not at all true.
Example?