OpenD, a D language fork that is open to your contributions
dpldocs.info
dpldocs.info
Almost everything I liked in D when Andrei Alexandrescu's book came out in 2010, have made its way to C#, Java, C++.
Yeah, maybe the implementation isn't as nice as in D, but that hardly matters when the implementation is available in some form, with much better tooling and library ecosystem.
Too many years lost chasing the golden feature that would bring people in, without stabilitizing those features.
Even Andrei is nowadays apparently mostly busy with C++ and CUDA than D.
And then there is the whole compile to native programming languages renaissance from the last decade, adding even more competition.
Which is a pity, as the community itself is full of great folks to talk with.
I am using Python every day. And there are many things from D which I miss. Not to mention the performance.
Circle does not, in fact, have working Rust style lifetimes. Sean splits the Circle documentation into features which work and "Research" features Sean is working on and lots of interesting ideas, including lifetimes, are in the second category. Maybe Circle will implement them some day, or maybe it will not.
It does decrease compilation speed, because O/B requires data flow analysis. However, this is speed slowdown only happens for the functions marked as being O/B functions.
While I wish Adam and the others success with OpenD, I hope they can take the opportunity to pick a more unique/memorable name.
FreeD
Too bad it's not focused on a windowing system, they could go with Dfenestration :)
Oh, didn't know that they are working on this.
https://github.com/coq/ceps/blob/coq-roadmap/text/069-coq-ro... and, of course, https://news.ycombinator.com/item?id=38779480
069-coq-roadmap.md? Oh, you!
So now we've got Rocq and Roc https://www.roc-lang.org/
And no, I didn't miss the joke :)
I'm sure that there are legitimate gripes and D's reliance on Walter as gatekeeper may be too strict for some but the way this fork has started out doesn't bode well for the long term. Forks succeed only if they are carried broadly, you'd need to more or less pull a majority of the folks in the D community along rather than just a handful of prolific but ultimately low in number individuals because there is a fair chance that both your fork will fail and that you further fragment the mindshare of the original to the point that it too looses any viability that it still had.
You also need to be able and willing to support it for decades.
Personally, I think it’d have been more fun if they named it ‘Died’ — you get the benefits of sweet taglines “It never Died,” a statement about it being a fork, and the permission to take the language in new directions if that makes sense in the future. OpenD implies full compatibility, etc..
(I have no skin in this game, though. Good luck!)
sounds from this like the people forking basically want a different language, for which they're willing to make a number of breaking changes.
Honestly, I've always felt really confused about what D's vision is. I've tried reading some of the docs about certain language features like better see and safe mode and lifetimes and they've been grammatically just kind of hard to read and generally poorly explained, despite going into great detail on things, and I've never really been able to get a sense for a coherent design vision or purpose for the language. The author mentions that this has been a problem, but I don't feel their vision is really any clearer. Yes they have a few concrete midterm technical goals, which is great, but it isn't clear to me what those goals are in service of. Honestly, I'm a rust programmer, so you know what I do for Greenfield personal projects, but I'd rather just use OCaml, C++, or even C# if I had to pick something else.
Yeah, for a long time the language was marketed as a better C++. That was wrong for two reasons. First, it's a C++ replacement, but it's not C++, as many C++ developers learned in frustration. Second, it's a lot more than a C++ replacement. It works for scripts, as a general programming language, and especially for C interop (ImportC, BetterC, etc.)
One of the goals of the fork is to stop apologizing for the GC. You still have reference counting, unique pointers, and whatever in the standard library. I'm sure if someone wants to contribute functions that avoid the GC, they'll be accepted. What you're not likely to see with the fork is Adam writing new functions for the standard library that go to great lengths to avoid the GC. He believes fear of the GC is overblown.
Also, this idea that fear of the GC is overblown — I buy that for servers and applications and the like for the most part (although I think our obsession with using heavier and heavier runtimes and frameworks to ease development at the cost of efficiency is unsustainable in the long term and has contributed significantly to the bloat of modern systems), but for real-time work, or embedded systems, or low level programming that needs to implement the sort of things a GC or runtime relies on, which are the only things I think most people claim GCs aren't good for, I really don't buy the argument that GCs don't matter. Yes you can do such things with languages that have them, especially if you have cutting edge GCs like Java's ZGC or turn your runtime into bare metal hardware drivers like Miranda did with OCaml, but oftentimes that's just harder to reason about and control, more work, and has costs (like ZGC needing 2x the memory and roping all pointer accesses into doing GC work to amortize processing costs), so it's like that article about using C# to do a <2KB game — why not just use things more well suited for that. This is a common sentiment I've seen in the D community though, so let me ask directly: is this argument a response to people who are claiming not to want a GC for low level / systems programming, in which case I don't think it's very reasonable, or is this a response to people who balk at GC for server and application stuff, in which case I'm not sure anyone disagrees? Or is there a third option I'm missing?
Most of the changing languages that come to mind, I realize, that they, too, had a big upset or oops related to governance.
I now think one of the key things to look for in a programming language is governance -- what they say about how they do it, what they actually do, how that's working out so far, and how you think that will work out in the future.
For example, if a language designer and implementor says upfront that they want to run it as Benevolent Dictator For Life, and also that they don't want to see feature PRs from people, because they prefer to work through all the details themself... That's their right, and great information to have upfront. That governance might tentatively work for some adopters, and others will decide it's a showstopper without needing to explore further.
Correction: "We might not be able to say".
IMHO that's the main reason why C became so popular, compilers are free to explore into different directions, language extensions that have proven their worth will eventually be picked up by other implementations, and sometimes even make it into the standard without being butchered too much by the committee agreement process.
open-D is not a 4th implementation it's a fork.
Language design is difficult. Features interact in complicated ways. Fixing mistakes is tricky - you break existing code.
Forking D sounds fine. It's easier to start with an implementation than to go from scratch. Ideas which work out well get to have a existence proof when proposing them to the original. Ideas that crash and fail don't add to the debt of the original language.
I hope the fork goes well and this proves a net gain for the original ecosystem.
D is much more closely a competitor of C# than it is C++. D has a few nice features like advanced compile time programming but the actual nuts and bolts that Staff engineering management looks isn't really solid. D's GC is a design straight out of the 80's. Dmd has good compiler throughout but code quality isn't very good. Ldc is much better but compile times are much longer.
Adopting languages at FAANG beyond a single team just yolo deploying them to production requires integrating dozens of engineering systems for everything from post mortem debugging to live profiling to authentication systems. The cost to do this is in the order of tens of millions of dollars.
D just isn't suitable as a C or C++ replacement in the places that actually require it and the cost to enable it in large companies isn't worth it for the incremental improvement it does offer in some areas.
D could have been something but most people avoided it because of the commercial nature, i.e. not being Free software.
D is a very small community , so this seem to be a big bet
It's too early to judge how much support there will be. I don't expect current users to split into camps though. My prediction is that the relationship will end up being similar to Ubuntu vs Debian. An example is string interpolation. Walter wants to stick to his own proposal, which nobody else likes, while Adam's already implemented his proposal in OpenD.
> Again, remember, I have other work and responsibilities, so I can't do a great deal of work myself, even if I wanted to.
I'm far more concerned about community development of libraries, IDE support, and the beginner experience (especially on Windows) than I am about changes to the language, which is already pretty good. As a Linux user working on top of C libraries, the experience is incredible. That's not the case for everyone.
Then there are problems for users of the language not having enough libraries and a sub-par IDE experience (again, true or not). Go and Rust built communities of programmers that aggressively used the language and made their work available to others. I don't see any reason we couldn't have more of that with the language as it currently stands. Adam certainly had no trouble knocking out hundreds of thousands of lines of nice libraries. Edit: And Ilya doing all his good work with Mir.
The first is a long-term problem. We'll see the effects ten years from now. The second makes it hard to have a reason to use the language right now (largely for anyone that doesn't want to write scripts or interact with C libraries). That's most of what concerns me.
What changes would you like to see happen?
That being said, never assume that no response from someone means someone doesn't care. I felt awful when dealing with situations like this. If this were my project, I would probably be extremely frustrated and more than a little bummed, whether or not I thought the fork was understandable.
Those are not things that are constructive to air in public, though, and I think it is a mark of leadership that Walter's dialogue remains as calm and polite through all of that thread as he usually is.
Contrariwise, I read through that forum thread and some of the linked github issues, and it wouldn't be shocking if he were happy to see some of those people walk away. It would not be politic for him to say so.
Chromium is a fork of Webkit which is a fork of KHTML. If you use a web browser, that browser is either Firefox or a fork (of a fork) of KHTML. I don't know what percentage of Chromium/Webkit users have heard of KHTML, but I'd recon it's on the order of 1%.
mplayer used to be a very popular, very good media player, mostly for linux but it was cross platform. Development sort of died. These days its fork mpv is much more common.
There used to be many different forks of GCC. In 1997, all of these developers merged their forks together into the EGCS project. This project proved to be very active and very...good. It was so good that the FSF halted development on mainline GCC, forked EGCS into the new mainline GCC, and restructured the community built around the ideas of the EGCS community. If you use GCC, this is the version you use; forked from GCC into EGCS, forked from EGCS back into GCC.
MacOS' kernel is a fork of FreeBSD. Much of its userspace is a fork from ... somewhere. If you use MacOS it's forks all the way down.
Kindle is forked from Android and/or linux and/or... well it's complicated. Amazon forked a lot of stuff.
Much of the Android ecosystem has been forked. OpenSSL was forked into Tink, for instance. Again, complicated, lots of forks.
yt-dlp was forked from youtube-dl when ... the lawyers came.
Ubuntu is a fork of Debian.
Firefox is also a fork of Mozilla (later renamed to Mozilla Suite, itself forked into Seamonkey[0] when Firefox became the main browser the Mozilla Foundation decided to stop developing the Mozilla Suite).
Now we have 3 D compilers: DMD (the de facto standard), LDC, and GDC.
I guess the OpenD project will have their own compiler, too. Well... let's see.
Anyhow, D went from a language that I remember back in 2015 was often promoted on places like reddit and here as a fresh alternative to C++ that was constantly evolving, to nowadays you rarely hear anything about it at all. I think even Andrei Alexandrescu has given up on it.
Good luck to these guys on trying to bring life back to it, but frankly I think at this point most people have given up and moved on to alternatives like Rust, Nim, Zig, etc...
1. Make class methods open to extension. This allows adding methods from other contexts, including other privacy contexts. Sure you could have dedicated syntax like C#'s extension methods, but these were added after the fact. If starting your language from scratch, while have two distinct syntaxes, when one will do?
2. Allows to add methods that only exist for some combinations of generic parameters. For example you can have a generic `Foo<T>` class, and then define a method `from_bar` that only exists for `Foo<Bar>`. Again, impl blocks may not be the only solution to this, but it is a highly cohesive one.
3. Lastly this is more philosophical, but it decouples the data definition from the method definition.
Not wanting to try Rust because its syntax is unfamiliar has to be the weakest reason, especially when the syntax has excellent reasons to be different.
Rust's own standard library gets a pass. For example the [T] (a slice of T) generic type is a built-in, and the core library defines methods on that type, but in terms of sorting it only provides sort_unstable - an unstable sort, and the associated variants of that sort.
Then Rust's alloc crate, which is optional, has a new impl block for [T] and it defines sort, a stable sort on this same type which is much faster than it might be otherwise because it uses a temporary buffer, hence it needs an allocator and can't live in core.
You are not allowed to do this for other people's types. If I make a Goose in crate A, and then you try to write an impl block for A::Goose so that you can add a fly method to it, that won't work. Rust obviously could allow this, but it would invite chaos, so they don't.
What you can do is invent a trait Flying and impl Flying for A::Goose
If Hannah is allowed to write
impl birds::Goose { fn fudge(&mut self) { self.counter += 1; } }
and Sarah is allowed to write
impl birds::Goose { fn fudge(&mut self) { self.counter -= 1; } }
... Now what happens when I call fudge on a Goose? Does it increment the counter? Or decrement the counter? If instead the program is rejected because of the ambiguity, whose fault is the ambiguity? Sarah's fault? Hannah's fault? Jim's fault?
If you import both traits you get an ambiguous function error and are asked to resolve which trait you want `<Goose as noises::Trait>::fudge(...)`.
D isn't, and neither is Rust.
> I meant that D could have been in the position of Rust today if done right.
My point was Rust is just a completely different audience. I suppose D could have sold itself as a better JavaScript.
(Sorry for several rewrites.)
We're finally (usually) allowed to use C++17. I had to use C++03 at times circa 2019 - we're finally done with that. It's _really_ slow moving.
"Someday" is on the order of decades here. By that time Rust will be a hoary legacy language with a list of warts longer than an ISO standard.
Exactly. One language died arguing about a feature (Dlang), two different languages, one without it (Rust), another with it (Golang) proved that it was not as significant.
(Note that the bar I'm establishing here is not merely to have a self-hosted compiler (see many toy compilers). I'm talking about a hypothetical future milestone where the software world's core infrastructure comprising LLVM/Clang and* GCC is written in the "replacement language", i.e. the compilers for a bunch of other (non-PLₓ) languages—including C and C++—are written in PLₓ as well. The backends, at least.)
* "or"?
Right.
> it is an unreasonably high bar
It's not an unreasonable standard. We're talking about replacement. If isn't replacing C++ for this use case, then it's not a replacement by definition.
Not everyone is of course, but hardly "just (Rust) advocates" like you suggest.
Do you have an opinion on how the GC schism within D affected it competitively with regards to C/C++?
Maybe you wanted me to answer about some magical sauce that can conveniently avoid such issues, but I want to make a point that there is no such thing. In fact, Rust is praised for its strictness about memory safety, but that owes much to the existence of `panic`, and you know what? What I've described earlier equally applies to the `panic` behavior in Rust. You can not avoid panicking in Rust, though you can avoid panicking as much as possible and make `panic` immediately fail to avoid any further overhead, so you are liable for any panicking in your code. In the same way, if you really don't want to touch GC you are in the minority and should be served well with a placeholder GC that always fails. Anything beyond that is not something you can't expect from mainstream programming in the near future.
Yes, you'll be (re)writing a lot more code than if panics are acceptable.
While I’m not yet out to rewrite all the things in Rust, I understand the appeal of rebooting archaeological projects with a modern approach.
I can have a proper type system like an ML, and touch the metal like C? Yes please.
Rust saved some of us from a lifetime of exactly the problems you have with Rust, maybe let us have this one :)
I never saw the need for it, really. I just stuck with the language constructs in C++ that makes it basically impossible for memory leaks/use after free/use outside of bounds to occur or if they do occur, explode loudly in debug environments. I haven't used new/delete in a personal project in like a decade; longer than Rust has been around.
Now I'm working on a project where the main developer is...a cowboy. Everything is insane. Not only is new/delete everywhere, but so is malloc/free. In C++ code. You have to navigate to where the thing is allocated to figure out whether to use free or delete. Everything leaks, everything crashes, everything races, everything deadlocks.
Oh and the guy is my boss.
So on the one hand, rust might fix these problems, on the other hand, rust is a non-starter.
So now what. I still don't need rust because I don't code like a crazy person. And the people who do code like crazy people will never use it anyway because it doesn't let them...express themselves.
One positive aspect I see about "rewrite it in Rust" is that you can to some degree expect a random Rust project to not leak and crash and expose vulnerabilities quite as much as a random C++ project. It's silly, but "written in Rust" acts somewhat as a badge of safety and performance, whereas "written in Java" and "written in C++" each only carry one of the two.
Of course, developer skill is also huge. You can write slow Rust code or fast Java code, yadda yadda.
How do you want to play this boss? I can see you’re focussing more on the bigger picture and the code is just a means to an end, given that, how about you delegate technical leadership on the codebase to me to let you focus on the product & commercial aspects?
If no - maybe words come back to the effect of “it’s my pet/child, how very dare you” yadda yadda - then I can’t see a happy path beyond “thanks for the opportunity, all the best for the future” but there’s certainly room for many mediocre outcomes short of parting ways if that’s preferred.
If yes - “hey, we don’t have infinite money and we prob can’t afford to hire the help to do this to a gold standard so how about we agree these commercial milestones (once change delivery falls below X days on average, or once feature Y that you always wanted lands in prod, or once the defect rate drops below Z per week etc etc) - I get bonus $$$”
Rewrite it in C#. It’s safer than Rust, because VM. Both standard and third party libraries are often way better. With modern versions of the language, GC allocations are avoidable if that’s what needed for performance reasons. C interop is equally simple.
You can also enable the warnings/errors that complain about missing using declarations for class and structs with the Dispose pattern.
This reduces the expressive power of the language, for example LINQ from the standard library is probably out because based on the delegates which require memory allocations.
Still, the language is very usable even without GC allocations. For example, that library re-implements a subset of ffmpeg for Raspberry Pi4 running 32-bit Linux, with no memory allocations in runtime: https://github.com/Const-me/Vrmac/tree/master/VrmacVideo
By design, Rust requires unsafe code to implement any non-trivial data structures (except trivial POD types). This applies to both Rust standard library, and third-party crates.
The issue is not a theory, security bugs actually happened in reality. Here’s an example about the Rust standard library: https://shnatsel.medium.com/how-rusts-standard-library-was-v...
By contrast, thanks to the VM and the GC, C# allows to implement very complicated data structures without any unsafe code or unmanaged interop. The standard library is also implemented in idiomatic memory-safe subset of the language. For example, here’s the hash map: https://source.dot.net/#System.Private.CoreLib/src/libraries...
> falls to prevent null pointer exceptions and modified collection exceptions
Yes indeed, but these exceptions are very unlikely to cause security bugs in the software.
According to bing.com chat, https://github.com/dotnet/runtime has 3.5M LOC, and https://github.com/rust-lang/rust has 6M LOC. The right panel of https://github.com/dotnet/runtime says 80% of the .NET runtime is written in C#.
This makes me wonder, do you happen to have a link for your “vastly outweighs” statement?
Now if we remove in tree tests from the totals, we arrive at 1.5M lines of C++ (most tests are written in C# as you would expect) and 1.7M lines of Rust.
However, this does not exclude safe Rust code. I don't have a tool off hand that can provide a precise count of lines of unsafe code but we can get some general estimates. There are 1958 instances of "unsafe fn" out of 103,205 instances of "fn ". Further there are 11,545 instances of "unsafe " in the Rust repo while there are 10,768 instances of "unsafe " in the runtime repo.
Given that unsafe functions comprise less than 2% of all functions in the Rust repo, I think my claims are reasonable.
Also plenty of crates are bindings to C and C++ libraries with nice unsafe blocks.
Then was that Axium drama.
The point is the "look at what I say, not what I do", when talking about safe languages and dependencies into C and C++ libraries and compiler toolchains.
When Rust gets fully bootstrapped in self hosted toolchain you'll have a point.
That seems like a gross overstatement.
https://github.com/rust-lang/rust/blob/master/library/std/sr...
CTRL-F: unsafe
Only one result, an optional utility function: "pub unsafe fn get_many_unchecked_mut"
There's far more unsafe there: https://github.com/rust-lang/hashbrown/blob/f2e62124cd947b5e...
Regarding "rewrite in Rust", I believe that it's a smaller part of the appeal of Rust than it appears based on the amount of code actually written: the main excitement is from people who never really ventured from heap+gc languages into manual memory management but who love the idea of being able to write gc-less native code. And many of them would rather write it slowly, one borrow-check at a time, than with all the memory bugs they created dipping their feet in naive C/++. Those people rarely write much Rust, but their excitement infects some in malloc/free land and for them a rewrite is super attractive because it skips the entire explorative part of software development that is really not the strong point of Rust.
(yes, this is pure projection, not only was I describing what draws me to Rust, I also failed to pick up on the codebase of my previous boss, too much "how can we make this entire thing less slow and error prone" and too little "cram in requirement X, even if it might turn out to become requirement Z because it pushed the codebase over the edge to terminal unmaintainability")
This is what keeps me orbiting but never quite landing on Rust. Things I'm pretty damn sure are safe come back red-stamped, and once I've painted things the way Rust deigns, I find I've lost my appetite. When desire finally returns, I find the fixes I've made to enable compilation also disallow the changes I wanted in the first place.
For all its faults and runtime bloat, I find myself going for Go on new things I would've attempted in Rust before. Though, I've never tried Zig; I wonder how that is...
But if it's not software that needs to go fast, then Rust is not adding anything for you. And if you considered Java to begin with you probably don't need top tier performance.
On the other hand I would forbid an average developer the use of c/c++ and similar. It is just not worth it.
i'd recommend embracing hungarian naming (if you call it apps-hungarian you've not embraced it fully enough, read older documentation) and be as rigid as rust about using it. i-, c-, p-, and Max are your best friends, don't declare one of those without declaring all the others that you will need.
using hungarian, adopt naming conventions about Open/Close, Init/Finish, Alloc/Free, Start/End, Alpha/Omega, or whatever, and apply them rigidly to any class/struct (with indentation that's obvious). When you put in an Open, you go and put the Close in at that moment, just as you would close any paren you opened. don't return from all over the place in a function, goto endblock and free what needs freeing, you need to work on autopilot not thinking through the twists and turns to play monte carlo with getting it right. If you are going to return an allocation, your name needs to be Open, Init, etc. Use whatever words you want, but it's got to be something that makes you as the caller think "this is an open paren, i need to close it"
using ifdef debug type mechanisms, hook malloc and free and put guard word asserts at the beginning and end of every allocation, and magic number ids and reference counts in all structs, and hook main() and exit() so you check those for leaks. all. the. time.
work in a systematic way that avoids problems and make that your priority, everything else like functionality is slaved to that.
How do you "hook' a function, like you said about malloc,free, main and exit?
I guess it means intercept calls to it and do something additional to what it already does, something like Python decorators, but how do you do it in C or C++? I used C a lot (but not C++), but much earlier, and don't remember any method of hooking. atexit(), or something like it?
for normal/average operating environments, I prefer to just indirect through an extra procedure call, gives you a place to put a breakpoint, and then if you need streamlined performant code you can #define it all away. But, if you plan to #define it all away, make sure that is a regular part of your work flow beforehand. you can have a procedure version, a heavyweight define and a lightweight define (and use your defines inside your procedure to test them there). On a regular basis you need to make sure your infrastructure is all doing what you think it is.
Same is true for main(), use it for setting up infrastructure, have it call Main() which is "your main".
if you are on a large enough project you can budget time for tools, the actual "__main.asm" code that calls C main() is also accessible and you can hook away in there too. Have to do it for all compilers, and track compilers, but on the scale of a large project, that's not the end of the world.
Zero memory safety mistakes is a tall order. But the overwhelming majority of memory errors we see in the wild can be easily prevented by good practices. And for the memory errors that do happen stack protection flags make a big difference (https://developers.redhat.com/articles/2022/06/02/use-compil...).
At my day job, I work on a project that's 75% C++ and 25% C#. In the code that we've shipped, when there's a crash in code that I've written, (as opposed to business logic bugs) it's usually a memory safety mistake in C#. There was an interesting architectural choice written a decade before I joined the company where most classes have a synchronous constructor, then an asynchronous initializer, then an asynchronous uninitializer, then a destructor that gets run by the GC. There's no end to bugs relating to crashes because the initializer hasn't been run yet or the uninitializer has already been run.
When I get C++ bugs put across my desk in code that we've shipped to customers, it's usually a bug somewhere else. For instance, the last crash dump that we've gotten from customers in C++ is because a we called a Windows UTF-8/16 conversion function. The Windows function itself is all raw pointer nonsense, so we put a pretty wrapper around it so you put a std::string_view in and get a std::wstring out, or you put a std::wstring_view in and get a std::string out. Well, it turns out Windows is a fucking dogshit operating system. If you initialize a thread "wrong", ie, by calling the C11 function thrd_create, and your locale is set to a CJK language, it will ignore you when you tell it the code page of the multibyte string is UTF-8 and will assume it's the system locale's code page, and will call abort() when it hits a UTF-8 sequence. (instead of perhaps returning an error or null pointer) Those are the sorts of C++ crash bugs that I deal with.
My 'secret' to dealing with memory in C++ is to not deal with it. Make the STL do everything. Make RAII do everything. Can this object be POD with constexpr accessors? Do that. Can these methods be const? Do that. Can these objects live in a STL/boost container? Do that. Do they need to live in a unique_ptr/shared_ptr instead? Fine I guess but it would really be better off as a value instead. Does this class need to have a special destructor/copy constructor/move constructor? Find some other way to do it. If you must, try to find some other way to do it anyway. If you must, spend like 10x as much time scrutinizing it, the way a Rust programmer would do with unsafe. If thing must have special destructor/copy/move constructors, factor out all of the things that need special consideration into a class with the barest minimum. If it must have a special destructor, explicitly delete the copy/move constructors/operators if you can. Avoid indexing into arrays; use range based for loops, or <algorithm> stuffs like transform, reduce, or transform_reduce. The solution isn't to use vector::at() (which does bounds checks) instead of vector::operator[] (which doesn't) the solution is to not use indexes at all.
You become the boss or responsible for some product. If you decide at the beginning to start off using Rust or rewrite some ancient, unmaintained library using Rust, then you prevent people like your cowboy developer to mess stuff up with this category of faults.
Either you would not hire him in the first place because he never came to grips with Rust so you only end up with developers on your team that understand and actively chose the tradeoffs that Rust offers.
Some rather "questionable" C/C++ code can, and are missed during code review sessions. One could put the blame on code reviewers, but let's be honest, code reviewing is a mindnumbing task for many of us.
This is not a foolproof argument because safety problems can easily result from unforeseen interactions among parts of the code that all seem to be OK and not "crazy" locally. A significant benefit of something like the borrow checker is that it can suss out these problematic interactions in a comprehensive way, even at the cost of forbidding some code patterns that would be perceived as safe in most cases. (Idiomatic use of Rust then requires you to either rewrite such code or stick it in an unsafe block and figure out what the preconditions are for it to be used safely.)
use std::sync::Arc;
use std::thread;
use std::time::Duration;
fn main() {
let shared_data = Arc::new(42); // Create an Arc
let weak_ref = Arc::downgrade(&shared_data); // Create a Weak reference
let thread_handle = thread::spawn(move || {
// Simulate some work
println!("Thread Data: {}", shared_data);
thread::sleep(Duration::from_millis(10));
// The Arc is dropped at the end of this thread
});
// Give the other thread a little time to start up (this is part of the race condition)
thread::sleep(Duration::from_millis(10));
// Try to upgrade the Weak reference and unwrap directly in the print statement
println!("Weak Data: {}", weak_ref.upgrade().unwrap());
// Wait for the other thread to finish
thread_handle.join().unwrap();
}The fix is trivial: just use an Arc instead of a Weak. In addition, `upgrade().unwrap()` should be a sizable red flag (like any unwrap, really) since fallibility is kind of the entire thing of Weak.
But Weak can be needed in case you have self-referential structures, right?
I was wondering about this in the context of the C++ programmer in post above who likes to use both new/delete and malloc/free in his code.
Sure, Rust will give him far fewer ways to screw up. But if he can't be asked to at least not use malloc/free in C++, he probably won't be too careful about unwrap() either?
My point here is mainly that a good programming language won't make good programmers out of bad ones.
Well, technically, no, you can just use Arc and leak memory all over the place :^) but that's not very useful either. Most self-referential structures need some kind of "owning" thing too though. For example, a graph could use Weak for the edges, but in order to keep vertices alive you need e.g. a Vec<Arc<Node>>. Then, if upgrading fails, you know that your edge leads to a deleted vertex (and as such should be considered nothing, hence Option).
> Sure, Rust will give him far fewer ways to screw up. But if he can't be asked to at least not use malloc/free in C++, he probably won't be too careful about unwrap() either?
There's one big advantage of messing up with unwrap vs malloc/free: unwrap 'only' crashes your program (and can even be caught in some scenarios), whereas use-after-free can do literally anything. Unwrap is also much easier to debug because you usually get a clear stack-trace, and the program semantics have been well-defined at all points.
> My point here is mainly that a good programming language won't make good programmers out of bad ones.
Very true! But I think the point of Rust advocates tends to be more along the lines of "a bad programming language makes a bad programmer out of a decent one". It is very easy to misuse C++, so mistakes are made with it way more often. 'Dangerous' constructs do exist in Rust, but are generally far less pervasive, making it easier for the programmer to understand what they are doing.
Saying Rust has no benefits over C++ because you can mess up in both is like saying that anti-lock brakes are useless because you can still understeer by pressing the accelerator too hard (sorry for the car analogy, I had to). Preventing entire classes of mistakes is valuable, even if other classes are still possible. (If it's worth the cost is of course another question. My personal opinion is yes, although that's especially for memory safety and a bit less for race safety.)
Sorry, that wasn't my intent. It was more to point out that bad programmers are surprisingly inventive when it comes to write bad code. New languages are an improvement, but not a panacea.
I don't want rust for memory safety. I want it for things like proc macros, a sane module system, a good and accepted error handling system, destructive move, constrained generics, unified static and dynamic polymorphism, language level customization points, and many more things.
I've found that data structures with _lots of helper methods_ (thinking about things like `Result` in particular) tend to be nice. You do have to learn about Rust-specific things to figure out how to nicely structure your code for everything to work. But the payoff is less pain.
There are still a lot of futzy ownership questions, and even when you write out your supposedly performant and cool system, easy outs like cloning end up hiding in your system leading to some awkward performance questions. Fortunately the systems are merely slow, and it tends to show up in profiling.
For me there are three reasons why Rust is suitable for many usecases:
- performance
- safety
- static binary compilation with targeting different cpu architecture
After spending majority of my time with Python and Java in the last 10 years these are things i really learned to appreciate.
The only reason left to really use Rust is safety.
Speaking as someone who is learning Rust and really liking it, I just want to note that this comment is sort of emblematic of what is wrong with the Rust community. It comes off as pretty condescending—"Rust is for the people who are smart and don't give up easily, if you're less smart or give up easily you should really go find a language for wimps".
I ended up jumping over to Zig and have been really enjoying it. I ported the same hobby 2D game engine project from C++ to Rust, and then over to Zig. A simple tile map loader and renderer took me about a week to implement in Rust and 3 hours in Zig. The difference was a single memory bug that took 15 minutes to figure out.
> One of the guiding principles of this fork is to embrace the GC as a successful design rather than to shun and avoid it. [...] I have harshly criticized @nogc in the past as putting a disproportionate burden on library authors while being the wrong answer to what can be a perfectly fair question.
[0] https://dpldocs.info/this-week-in-d/Blog.Posted_2024_01_08.h...
I'd love to use it for embedded work instead of C and C++, even in the current state. Embeded meaning 32bit MCUs running some kind of RTOS, not ARM SBCs powerful enough to run Linux. If not D, then maybe Zig. For this it needs to be able to link against and build upon existing C/C++ libraries.
Sure, but this was in a response about D substituting C++.
D's GC problem is being a very old approach on how to design one.
PTC, Aicas, microEJ, Astrobe, Meadow,...
The problem isn't having a GC, is its poor implementation.
OTOH Java and .Net exist and have large investment (D is younger than C#), so for people who are fine with GC, there are already plenty of "C++ alternatives". What's left is people who can't or won't use a GC, and for them a GC'd language can not be an alternative.
While it hasn’t really taken off yet, I’ll point to nim, specifically with its very recently stable arc GC, as a very compelling local (at least) maximum in this space.
If that argument were solid, Golang would not be more successful than Dlang, but reality is, Golang numbers are just so much bigger.
I never said anything about being "successful". I said something about substituting for C++. Go isn't any closer to that than D.
Not quite. The problem with D is that it was a better C++ than C++98.
In the meantime the C++ world woke up from it's freeze and the standardization process started addressing the requests from the C++ community. Consequently once C++11 was out and work picked up on following standard versions, D ceased to have a selling point.
It's hard to say whether I is available, or un-googleable.
J through W are also taken.
X++ is taken, but X seems to be available.
Y and Z are taken.
A would be an excellent choice were it not completely un-googleable.
Finally, B is a famous precursor to C.
APL is named after the book A Programming Language
Even better if it only worked with tuples.
which is extra clever because the "boot" button on early IBM mainframes was labelled IPL "initial program load".
OpenD is not that awesome.
And back in 2015, folks were saying the same thing, but with different alternative languages. I remember twenty years ago when C++ was dead. Oh, and remember the good old days when Java was dead?
I'm not sure why programming language discussions always turn into quantitative statements that have no data, but fully support the commenter's position.
I don't think many people thought C++ was dead 20 years ago; that seems like revisionism. Same with Java.
People looking for a C++ replacement have definitely moved on to Rust, Zig and maybe Go & Nim. Not D. I don't see how you could seriously argue otherwise.
Some languages are pretty easy to predict, e.g. Ruby is going to decline quite quickly. C++ is going to stick around for a long time because of its current enormous usage. PHP will probably stick around for a while but slowly decline like Visual Basic and Perl. Rust is going to gain in popularity for a long time and probably stick around for a very long time.
Some are more difficult to predict. I'm not sure what will happen to Go or Nim for example.
Sure they did. Bjarne was in that camp. That's why C++11 came out, and the C++ of 20 years ago is dead.
> Same with Java.
It was very common to hear comments like "The JVM is great, but Java is terrible. Use Scala, Clojure, [language of the month]."
> People looking for a C++ replacement have definitely moved on to Rust, Zig and maybe Go & Nim. Not D. I don't see how you could seriously argue otherwise.
Do you have some numbers on how many moved to Zig and Nim? I'm not looking for "I've seen comments on the internet" but actual numbers. I'd expect it to be rounding error relative to the population of C++ users. And I seriously doubt the numbers would be very high for Go.
But the point still stands that people have been saying this about D for a gazillion years. It might be more credible if they'd at least change the story up a bit when they say it.
I remember 25 years ago when StarCraft was dead and Age of Empires was it. It happened at the same moment my university switched from C++ to Java. I hated that change.
And I remember 15 years ago when the biggest e-sports events in the world were done using StarCraft.
Today I am back in university, and we are using C++. =)
Not welcoming for everyone apparently. I don't know much about D, beyond seeing a post from some dev rage quiting D every few months, due some people in the community being terrible and the leadership not stepping in to limit that.
dom96 eventually had a falling out with the Nim BDFL too (which I'm surprised did not happen earlier: the BDFL is... brusque, charitably) and so has been inactive in either Nim community because, well, obviously. But: in all my years involved with Nim, I have seen the nimskull developers to be pretty consistently great to work with? I think they handle things professionally, are not rude, and treat other's work with care (you will maybe notice they have a code of conduct exposing an explicit intent to do so). Which makes what happened between them and dom96 all the stranger in my eyes, but I was less active back then, and there is certainly context I am missing.
tl;dr meh
My many years of involvement with Nim is what I believe qualifies me to speak on the individuals in the forked project. That being said, I am no longer involved with Nim. I don't want to get reinvolved. I just want to warn people about individuals who were abusive to me (and others) for many years.
I banned very few people during my time in the Nim community, and never without good reason. I don't know who you could be referring to here. I'm sure you left this comment with the best of intentions, but you say it yourself, you were less active back then and have had minimal interactions with me on the subject.
It is perhaps notable that the nimskull project has a Code of Conduct (and a rather good one at that). I think it is indicative of serious intention to make a welcoming community, and I don't think that contributing members having had in the past what really struck me as personal grievances turning into open-air malice undermines that: particularly, such behavior would fall under the Code of Conduct itself. But again, I have not seen such behavior - quite the opposite! - outside of what happened between you two.
I'm glad that their community has a code of conduct. It is unfortunate that members there have never applied those rules to their interactions with and about me, nor with many others they targeted in the Nim community.
For your clarity going forward: I did not ban him, though I was one of the people who advised and agreed with that course of action. All decisions on whether to ban someone or not were taken by Araq (at the time at least).
It surprises me to hear you say you have never seen him engage that way with anybody else, given that you acknowledge that his banning was deserved. If I recall he was banned for aggressive behaviour towards _multiple_ members of the community.
The thing that moved me away from it was a lack of purpose, which isn't exactly how I would have put it at the time, but in hindsight seems obvious.
The way in which I'm certain that this is true is that if you had the leads try to create a Venn diagram of what the project does and what is central to it vs periphery, they would fail to agree. And if they fail to do that, they will fail to coordinate on the features. And that creates the stagnation and difficulty with contributions.
As well, the reason why that failure leads to a retreat into technical digression - which I know happens out of personal experience - is because that deflects questions by adding scope. It promises an escape from the confrontation: "if I just accumulate more work, it will all come together someday". The problem is that adding scope doesn't solve the contradictions that made you retreat in the first place, it can actually deepen them by creating sunk costs. It's a bad adaptation to the challenge.
If we compare it with, for example, the Niklaus Wirth approach, he would have the Venn diagram completely clear in his mind before committing to any real implementation. And therefore the language would do exactly what he wanted it to do, and it wouldn't need to be scoped into a 20-year project. Thus, he made many languages during his life, mostly of a similar flavor, but with a clear intent of adding something specific that he hadn't covered before.
That's not the case. The job of language designers is to say "no" all the time and Walter is certainly a model with how to speak with users.
I don't think it's intentional but the argument always begins with explaining some detail as if you didn't know it existed even though you'd have to do be able to bring it up in the first place.
This is not just me, I've had this discussion with a few people. One of a short list of complaints of this kind it must be said.
There also has to be an escape hatch to make this work.
E.g., Linus can say that the __is_constexpr preprocessor hack is the product of a demented mind, and he'll merge that absolute monstrosity thanking the contributor.
As a leader you get the contributor community that you get. You can either make the development process workable for them, or you can risk the project languishing/forking.
Put another way: if a leader's concept of what their project ought to be/become veers too far from what the community is actively coding up to be merged, it's not going to go well.
No idea if this applies to D. But I'm absolutely certain Python's dev process has had plenty of escape hatches for resolving development issues. (And I'd guess there are also projects that have too many escape hatches, but I'm guessing that probably doesn't apply to D.)
Heck, even .NET is pushing NativeAOT (their brand name for native code compilation) hard these days. Still with sizable gaps but closing for every new release, and you can now develop full fledged desktop apps or a web service and have it be self-contained with native code.
I think .NET in particular is a harbinger for D. When even a "managed language" platform at its core goes native code, and with Microsoft's industry backing giving an entirely different angle of attack than D's minimal defense, you just know it's over. D will live on but in the way Amiga, SNES, ZX Spectrum lives on among enthusiasts.
NGEN, only usable for fast startup, using dynamic linking.
Singularity and Midori respective C# dialects.
MDIL in Windows 8.x based on Singularity Bartok compiler toolchain.
.NET Native on UWP, taken from Project N, inspired by Midori's System C#.
Mono AOT used by Xamarin for iOS and Android.
Homebrew OS like CosmOS.
Unity's IL2CPP toolchain.
I wrote a blog post in 2012 about D [1]. In my personal experience, the high point of D was around 2008-2009. It was already declining in popularity in 2012, IMHO, due to intense clashes within the D community and the rise of Go, Rust and C++11 outside the community. D remains one of my favorite languages but I agree with you that Rust, Nim or Zig is the better choice for most programmers today.
[1] https://attractivechaos.wordpress.com/2012/02/28/timeline-of...
D is a native strongly typed language
You don't make game engines in Python, and certainty not drivers, python devs fall back to C when they need performance, this should give you a hint
[1]Numeric age for D: Mir GLAS is faster than OpenBLAS and Eigen:
http://blog.mir.dlang.io/glas/benchmark/openblas/2016/09/23/...
And Python's selling point isn't the fact that it has a GC, it's its interpreted/dynamic nature
D is pragmatic about memory allocation strategy, this fork won't be
Better than a pragmatic approach to memory allocation is to not have to think about it at all. For many applications, you can use the GC and not even know anything about memory allocation.
If you embrace the GC, you make a lot more progress, since you can add things to the standard library and the language quickly and easily. Users not wanting a GC should use something else. Catering to users that don't want a GC imposes a big tax on everything and everyone.
Embracing the GC doesn't mean they're going to strip out the reference counting and unique pointers already in the standard library.
The fact that most of today's programmer or in the future will be just fine and better off with GC based languages compiled or interpreted, as modern drivers are better off with auto transmission than the manual. Heck, even F1 drivers now compete in auto transmission (DCT).
The fact that D is embracing GC as a default is not a disadvantage but it is advantage for majority of the programmers [1]. Imagine a world in the near future where D is as popular as Python due to its intuitive syntax thus more library will be written for D and thus the library eco-system is flourishing regardless you are using enabled the GC or not with D [2]. Imagine a world where you don't need to write in Python and interface in a wrapper for library in foreign language that only selected few can understand because most of original library authors have passed away since the core are using language originated from the 50s and the library was developed in the 70s [3]. Imagine a world where only programming language with GC can be JIT to wasm [4].
[1]Go: What we got right, what we got wrong:
https://news.ycombinator.com/item?id=38874952
[2]Stop Designing Languages. Write Libraries Instead:
https://lbstanza.org/purpose_of_programming_languages.html
[3]Programming in Modern Fortran:
https://cyber.dabamos.de/programming/modernfortran/blas.html
[4] WebAssembly Garbage Collection (WasmGC) now enabled by default in Chrome:
It seems a lot of the other languages:
- don't have an easy compilation story (interpreted, VM, compilers as secondary implementations)
- lean more on the functional side (Ocaml, Haskell)
- otherwise clash with the common BCPL-family mindset (Oberon, arguably Go)
There definitely seems room for an "easier C++". Heck, given how popular Rust is due to backing and support from the functional crowd, leaning into ease of use and imperative programming might be a sufficiently large niche.
D doesn't have state of the art GC, it perhaps should focus on its strengths, being a better C/C++ and embrace the concept of allocators
https://dlang.org/phobos/std_experimental_allocator.html
To me D shine with its -betterC mode, it completely strip the runtime, giving you a great low level language to work with, a great better C/C++, I would have quit D a long time ago if it didn't have this compiler flag
Removal of the GC makes for CTFE code becoming much klunkier.
One can see this in betterC mode - the GC is allowed for CTFE code.
"Pythonic" hasn't been "intuitive" for 15 years now. Even old-school Perl is more cohesive and coherent than modern Python.