A often recurring C idiom is passing a pointer to a struct as function argument where passing the plain struct by copy would do. A big reason is the good old 'passing by pointer is faster', which I thought to be no longer relevant with modern optimizing compilers. Of course I found out the hard way that even on modern compilers object copies are not elided on call. I had performance sensitive parts of my (non-x86) code that were dominated by the compiler's builtin memcpy, due to my struct-happy coding style (e.g. rolling my own range struct and passing it by value everywhere).
I understand mostly why eliding argument copy is so much harder than eliding a return object copy, there are so many ways to observe its effect, and you have to obey the calling convention. Another aspect is the lack of programmer-communicated immutability in C, which you have addressed with D.
Does the D compiler help in this situation? Can it guarantee that (immutable) argument copies will be elided in certain circumstances? (e.g. in file-scope static functions)
> Can it guarantee that (immutable) argument copies will be elided in certain circumstances?
No, but it's an interesting idea I never thought of. By the way, passing by 'ref' works handily and avoids icky pointer passing, while being efficient. I recommend as a "best practices" coding style using 'ref' parameters instead of pointers where possible.
> A big reason is the good old 'passing by pointer is faster'
Not even with old compilers, necessarily, this is more about the CPU architecture. If you've got an architecture with no cache (eg 386 and below for Intel) you'll not care about cache miss vs cache hit, but once you have cache you'll often find that the pointer dereference will hit main memory, and thus be slower than just passing by value. Not always, of course, but sometimes, so since 1989 (for Intel) you've needed to profile that to be sure.
The proposed NUBI ABI[1] for MIPS was interesting here in that for call by value if a struct was register sized, it would be passed in a register, but if larger it would be implicitly passed by reference. See section 3.4, Arguments.
It was then up to the callee to make a copy if necessary, say if it modified the struct contents.
Hence it would have been possible to elide the copies, on a per function basis, depending upon how the function used the structure.
I was also thinking in the direction of the compiler transforming the call-by-value struct object argument into a call-by-ref one at specific call sites. e.g. when the object is clearly on the caller's stack, is not mutated by the function and the function is not taking its address.
As Walter pointed out, you can use refs in BetterC (and of course C++) directly, but I don't see why it cannot be automatically applied to C in general.
Another complication to the normal "pass structs by pointer" is that small structs are actually split up and passed in registers depending on the platform ABI, which can be more efficient in certain cases.
1. Why do functions need to be annotated with @safe and nothrow in betterC? Why not make them default? I understand making it default for non-betterC might break some code.
2. string type was uniform and awesome until it was treated as Unicode. Any plans to fix this and remove auto decoding? That would be awesome.
Edit: three questions to two. I had another question about using threads in betterC. But looks like we can't use D threads as they are runtime dependent.
1. Making the defaults different between D and betterC would result in an impedance mismatch that would cause more trouble than it is worth.
2. I think you're referring to autodecode. There is an effort ongoing to extricate us from that, but it's difficult while maintaining backwards compatibility.
Would you be open to being interviewed for the Computer History Museum? I suggested this in the CHM feedback form, but I'm not sure if it disappeared into the void or if the form actually even works. I know that sometimes even their search chokes.
We've got a paper on the history of D accepted into this year's History Of Programming Languages (HOPL), which makes us very proud. Andrei, Mike and myself spent a lot of time combing through old emails and n.g. postings to develop an accurate timeline of when and how things came about and from whom.
I was really looking forward to the HOPL conference in London in June to present the paper, but CV scuttled that.
It's done for the time being. I'm sure we'll find ways to improve it, though! We try pretty hard to provide easy ways for existing code to adapt to future D. We're not quite ready to be craven to every past mistake yet!
Hi Walter, I am a bit late to the thread but thank you for all your work and for joining this thread.
What is your vision for D/betterC/SafeD?
Is the intention at the moment to stay as a systems programming language only, or is your vision that D or betterC or SafeD gain traction as an embedded target language?
I definitely think the focus on correctness and the ease of unit testing would be great in the embedded development space.
You can mix and match C and D code easily in the same program, and to a lesser extent C++ code. This means a larger project can be incrementally converted to D while keeping it running and shipping.
I know several people like it and use it very much, but I haven't followed their projects. Many were skeptical of the BetterC project, but it has proven its worth.
I've used it myself to easily convert some of my older C programs to D and make them easier to maintain.
BetterC is interesting because it allows you to compile D to WASM. Unfortunately D runtime and GC haven't been ported to WASM yet so they are not fully supported.
We have 100kLOC of not -betterC but D without its runtime.
If you write a -betterC library normally you can use it with normal D, but the reverse isn't true.
* Regarding the syntax of 'lazy'. It seems to me that it would make for better readability if the lazy keyword were required at the callsite, along the lines of doStuff(lazy getValueUsingExpensiveComputation()); rather than the current syntax where it's not clear at the callsite which, if any, of the arguments are lazy. C# does something similar with ref. What's the thinking behind D's syntax?
* What's the state, and future, of precise garbage collection in D?
Mainly that it be easy and quick for those familiar with C and C++ to get up to speed. With C, C++, and D, you cannot really know what will happen with the argument without looking at the corresponding parameter declaration.
Would it make sense to spin "Better C" off into a separate language? It would for example help to create an ecosystem of 3rd party libraries not dependent on gc.
Seconding the question. More to the point, a language that only needs libc and not a separate runtime.
It's a big boon that existing C projects can migrate one object file at a time to betterC, without needing to pull in extra dependencies. Moreover, embedded dev is where C is still the most entrenched due to its runtime simplicity (simple ctr0, linker script, and you're off).
You can certainly treat it that way. It specifically does not need its own libraries, all it needs are the usual C libraries. Libraries created with it are also directly accessible from C.
No. D already has image problems with D1 and D2 (as in people crop up on the forum asking about it a decade after the switch), making D better C a separate language probably wouldn't be a great idea
You should definitely check Zig out. It's a relatively simple (compared to D, Rust, C++) language with C-level semantics but more modern syntax. It is designed to be extremely easy to interface with existing C source code, enabling one to convert a program from C to Zig incrementally and with minimal headaches