Live data from Hacker News

C constructs that still don't work in C++

lospino.so

151–160 of 182 posts

Re: C constructs that still don't work in C++

#151

Earlier quoted context omitted.

> but then most C++ seems to use a C-style cast If C++ programmers do not use modern safety features, that's really their fault. C-style pointer casts should be flagged in code review. > but that it becomes even less safe by adding a C-style cast. At least in C++ there is a safer option. If you really want to be on the safe side, you can even to a dynamic_cast (assuming your code base allows RTTI). > It is also not c…

Lack of ergonomics around static_cast is language problem. The "most safe" of the casts should not be this verbose.

I see your point. It would be nice if a C-style cast behaved like a static_cast in C++, but that's not possible because of backwards compatibility. At least with GCC/Clang you can disable C-style casts altogether with '-Werror=old-style-cast'. (Maybe there is a similar option for MSVC.)

Re: C constructs that still don't work in C++

#152
post #147

Earlier quoted context omitted.

The inherent overhead of type-erasure is the vtable. Which is funny, because you said you prefer one over the other at the end, when they are basically synonymous. The compiler may choose to devirtualize and specialize, but that isn't guaranteed. If you want this behavior, &dyn does the exact same thing. Specialization provides more opportunities for optimizations, whereas proper type-erasure (which bars specializati…

The vtable can be removed in all cases where you specialize by monomorphization, so the overhead compared to it is not really inherent. Type-erasure can be undone by specialization. In contrast, monomorphization specializes the code first, at which point it becomes much more difficult to unify it again. Sorry, my comment about preference was badly phrased: What I meant is that I prefer to make macros better, than hav…

As I stated in my follow up, vtables can only be removed when the type information is still available, which, generally, aligns with specialization, except when dealing with libraries (even with LTO). You say the "vtable can be removed in all cases of monorphization", but that isn't guaranteed and often requires double guessing the compiler to ensure it still knows the type, where as monorphization makes it explicit when the compiler doesn't know the type anymore and that specialization must occur.

The problem with your suggestion about macros is that it misunderstands the reason why different techniques exist. While they may overlap, they have different primary niches: Rust macros provide codegen and inline DSL, Rust generics/C++ templates provide monomorphism, C++ constexpr/Rust const fn evaluate expressions in compile time, etc.

Extending preprocessor macros, aside from requiring integration into the C language proper, would likely create something much more complex and with poor DX. Specially so if it tries to fulfill all niches, as each of them often operate at different abstraction levels, with different ergonomic requirements that are often at odds with each other.

Re: C constructs that still don't work in C++

#153
post #149

Earlier quoted context omitted.

I just noticed you said "The compiler can always specialize". That's indisputably false. That only happens if the compiler has enough information to infer the concrete type at the call point. Conditionals, collections, or anything that may throw doubt about original type info and their function implementations can (and normally will) disable specialization.

It can always specialize where you could do monomorphization.

Not necessarily. In pure theory, yes. But in pure theory, monomorphized code can be deduplicated too.

Monomorphization often forces types information to flow, whereas type-erasure considers that a bonus. As such, a compiler may accidentally introduce opaque boundaries that hide type information. Even in cases where this is the programmer's fault and the type info is truly lost, in monomorphisation, that becomes an explicit error, while, for devirtualization, since it's just an optimization, the call is silently revirtualized (until someone notices it while profiling/decompiling). One has explicit intent, the other doesn't.

Re: C constructs that still don't work in C++

#154

Earlier quoted context omitted.

> implicit casts between unrelated pointer types is only a warning in C A warning in C has the meaning of a "stern warning" aka. "That very much won't work, I warned you!". An error means, "I literally, don't what you mean". Also as far as I know, the C standard only talks about diagnostics.

You are right that the C standard only talks about diagnostics, but this doesn't change the fact that implicit casts between unrelated pointer types are not treated as hard errors.

That's what I addressed in the first paragraph, a warning in C is a serious thing, not just some random nuisance.

Re: C constructs that still don't work in C++

#155
post #76

Earlier quoted context omitted.

They make sense but reduce type safety, because once you add the cast the case might hide some real typing issue. I sympathize with the idea that the down-cast should be explicit though.

> They make sense but reduce type safety Yes, downcasting can be unsafe and should be used carefully, but what's the alternative? At least in C++ you can't cast between unrelated types without an explicit reinterpret_cast (or C-style cast).

The point is that, there is nothing else to be done with a void pointer, other then downcasting it, and it needs to be downcasted to be used. There is no other check that somehow validates the cast, so there is no upside to requiring the cast, while it does potentially silence accidental casts once the type changed.

Re: C constructs that still don't work in C++

#156

Earlier quoted context omitted.

You are right that the C standard only talks about diagnostics, but this doesn't change the fact that implicit casts between unrelated pointer types are not treated as hard errors.

That's what I addressed in the first paragraph, a warning in C is a serious thing, not just some random nuisance.

Ok, but then compilers should really throw errors for these diagnostics by default. Why lump serious issues like incompatible pointer casts together with benign things like uninitialized variables?

(Another pet peeve of mine is that missing returns in functions is not considered a hard error. GCC 16 does not even issue a warning by default when compiling C code, which is just crazy. "-Werror=return-type" is the first thing I do in every new C or C++ project. I don't understand how this is still not the default...)

Re: C constructs that still don't work in C++

#158
post #157

C++ the good parts is essentially C. If C had the concept of traits and generics or something like them like Rust there’d be no need for C++ and its ideas of mediocre inheritance and macros (templates).

Tbf, I'd say Rust's concepts of Trait Objects and Generics are better implementations (in general) of C++'s inheritance and templates, respectively, rather than entirely different things. I'd also add constexpr/const blocks to good ideas to add, or else generics/templates will be abused (yet again).

Re: C constructs that still don't work in C++

#159
post #125

Earlier quoted context omitted.

> its syntax I haven’t used rust, but having gotten used to C and C++ at a time, I expect that would happen with rust, too, if I started using it. Because of that, I think this is just a matter of familiarity. > polymorphism based on monomorphization Implementation detail (yes, there is only one implementation at the moment, but this means it can be changed without changing the language) > the requirement for many de…

Some of Rust's problems may be fixable, but they are not being fixed at the moment and with something as complex as Rust, this is unlikely. I do not think monomorphization is an implementation detail, rather than a fundamental language design mistake that is difficult to correct.

Beg to differ. After musing for while, I realized Rust could only have chosen monomorphism for its goals, thus it's not a fundamental design mistake, but a necessary choice. One of the overall philosophies is zero-cost abstractions, and only designing a polymorphic system with monomorphism in mind may provide that, because the alternative requires pointers (different type sizes, vtable, etc.).

While, as discussed previously, devirtualization + inlining is a thing, it is not assured and relatively easy to disable. Writing a program relying on these optimizations would produce something bristle and error-prone, and building a polymorphic system around this would be antithetical to the Rust's ZCO philosophy.

Meanwhile, monomorphization can fit functions around the size of the type arguments and access method implementations directly, removing the need for any indirection in the first place. While indirection-based polymorphism can't reliably reimplement monomorphic polymorphism, the reverse is not true. You can reliably reimplement any indirection-based polymorphism with monomorphism, from fat pointers (in fact, Rust already has trait objects to help with that), class-based hierarchies, dynamic typing, etc.

Re: C constructs that still don't work in C++

#160
post #149

Earlier quoted context omitted.

It can always specialize where you could do monomorphization.

Not necessarily. In pure theory, yes. But in pure theory, monomorphized code can be deduplicated too. Monomorphization often forces types information to flow, whereas type-erasure considers that a bonus. As such, a compiler may accidentally introduce opaque boundaries that hide type information. Even in cases where this is the programmer's fault and the type info is truly lost, in monomorphisation, that becomes an ex…

The point is much easier to propagate information (and not accidentally lose it) than to deduplicate after specialiation, so I do not agree that this is only of theoretical relevance.

I agree that monomorphization has explicit rules that force specialization, I do not think this is an advantage at all because it is too rigid and one can introduce explicitness at the language level also for devirtualization where this is needed. In this sense, monomorphization is premature optimization which limits what can be expressed at the language level and makes the job of the optimizer much harder (and practically impossible to undo the damage completely).

Post reply on HN