> The thing about "efficient code reuse" is it probably requires dynamic dispatch. Once you have dynamic dispatch, you suddenly have vtables. But who decides what those vtables look like? Where do they reside in memory? What's the layout of that? If a struct suddenly has an is-a pointer, where is that mentioned in the code? Now my struct isn't just a struct.
1. We already have vtables through trait objects (though not for structs), so this would be nothing new. It's important that we have them, because otherwise common dynamic dispatch would be very annoying to write.
2. Structure layout is already not defined. The compiler is permitted to reorder structure fields as it likes. However, you can force it to adopt your specified in-memory order with the `#[repr(C)]` annotation.
> It would be nice to have a new C, finally. But the more a language has an opinion on runtime layout, behavior, and symbol names, the less C-like it becomes.
The language already has an opinion on runtime layout and symbol names. However, you can specify the layout and symbol names manually if you like (through `#[repr(C)]` in the former case and `#[no_mangle]` in the latter case).
> Rust got this right when it decided that GC was NOT the correct default behavior for a language. The reason you see people playing with OS kernels in rust and not as much in D is, I think, mainly due to this decision. I think rust should continue carrying this torch.
GC has performance costs, while trait objects and symbol names do not, as long as they're opt-in. Garbage collection and virtual dispatch are completely different things; having one in no way moves us closer to the other.
GC has performance costs, while trait objects and symbol names do not, as long as they're opt-in.
Not exactly.
Any program even in a GC'd language can allocate non-GCd data. Even in Java, there is the Unsafe class that can do manual mallocs/frees. C# integrates it with the language. If you do a big pile of work on the non-GC heap then no GC would be triggered and GC is effectively "zero cost" for this code.
And vtable dispatch has a cost for any code that calls a virtual method. Yes, it's "opt in" but this can be misleading. You pay the cost of the virtual method call every time it's invoked. Static languages like Rust and C++ require the programmer to explicitly state which methods can be virtual to try and control this cost, but that isn't the only way.
For example the JVM is capable of eliminating the virtual method dispatch overhead in almost all cases without requiring the programmer to manually specify which methods are virtual. In fact, the JVM can eliminate the vtable overhead for calls that could be virtual, but in fact at that specific call site are not, and even for calls which are only slightly virtual (e.g. there's only really two destinations). So it's possible that in a JIT compiled program you have way more virtual dispatch in theory, but less than the equivalent C++ program would in practice once the code is warmed up.
So vtable and GC performance are very complex topics which no longer reduce neatly down to our intuitions.
>And vtable dispatch has a cost for any code that calls a virtual method. Yes, it's "opt in" but this can be misleading. You pay the cost of the virtual method call every time it's invoked.
So you're basically repeating what he said -- I don't see how the "Not really" you begin with is justified.
Of course you "pay the cost of the virtual method call every time it's invoked".
In languages like C++ or Rust you pay the cost every time the method is invoked. With other types of compiler you may not pay the cost even if the method is marked as virtual, even if it's actually used virtually in other parts of the codebase, due to call site specialisation.
> Garbage collection and virtual dispatch are completely different things; having one in no way moves us closer to the other.
Right, of course not. The comparison was philosophical rather than technical.
My point was that I believe there's a "sweet spot" for a language that is expressive and convenient and modern, but also tries hard not to stray too far from C's spartan abstract machine model (and when it does, it exposes that complexity in a composed pluggable fashion).
I'm beginning to believe rust really has a shot at replacing C and needs to court "bare metal" programmers as well as higher-level programmers to do it; I'm just preemptively registering my wish that rust continue to head down that path.
Rust will not replace c, rust is a more refined c++. If you want something to replace c have: a better type system, raii, better macros, better lifetime management, etc but keep it simple and don't layer it.
The best way to make that wish come true is to use Rust in a project where you would normally use C, and report your experience to help us discover the best ways to support that use case. :)
I think what personally got me excited about this direction were the many "OS kernel in rust" hobby projects [1, 2]. For some reason these strike me as a sort of reverse canary-in-a-coal-mine to judge whether a language is seen as a potential C replacement.
Prior to rust the hobby OS dev community was primarily C / asm with some honorable mentions for other languages. It's also something of a stand-in for the requirements of the professional embedded community.
For these use cases, it's just really cool to be able to use more and more "layers" of the language as you implement more of the underlying abstract machine model.
1. We already have vtables through trait objects (though not for structs), so this would be nothing new. It's important that we have them, because otherwise common dynamic dispatch would be very annoying to write.
2. Structure layout is already not defined. The compiler is permitted to reorder structure fields as it likes. However, you can force it to adopt your specified in-memory order with the `#[repr(C)]` annotation.
> It would be nice to have a new C, finally. But the more a language has an opinion on runtime layout, behavior, and symbol names, the less C-like it becomes.
The language already has an opinion on runtime layout and symbol names. However, you can specify the layout and symbol names manually if you like (through `#[repr(C)]` in the former case and `#[no_mangle]` in the latter case).
> Rust got this right when it decided that GC was NOT the correct default behavior for a language. The reason you see people playing with OS kernels in rust and not as much in D is, I think, mainly due to this decision. I think rust should continue carrying this torch.
GC has performance costs, while trait objects and symbol names do not, as long as they're opt-in. Garbage collection and virtual dispatch are completely different things; having one in no way moves us closer to the other.