Live data from Hacker News

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

lospino.so

51–60 of 182 posts

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

#51
post #21
post #19

Earlier quoted context omitted.

That is the entire point, yes. Reasoning about layers of completely imaginary entities is what demotivates me about C++ and Rust. Meanwhile, hardware bits are very real (and getting more expensive recently). Having implemented slices and generics in C, now C++ feels like Vietnam flashbacks. https://replicated.wiki/blog/abc

Yet C23 isn't K&R C any longer, nor is the hardware a PDP 11. Also when we eventually start talking to agents that perform the whole execution steps by themselves, that is kind of irrelevant. Except for the lucky ones that still code to keep the infrastructure going, which is mostly C++.

The PDP-11 myth is getting a bit tired by now ;)

If C would be so hardwired to the PDP-11 architecture it would have died with it. In reality C works just fine on all sorts of hardware (like GPUs) with only minor extensions.

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

#52
You can pass a flag to clang to allow reordering field initializations in designator initializer thing. It makes the syntax super annoying in case of large structs anyway.

It doesn't matter unless you are using constructors or modifying some variables in the initialization expression anyway.

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

#53
post #29

I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. Many of these differences are intentional and defensible from the C++ side. But some are still surprising because they invalidate patterns that were historically common, performant, or idiomatic in C. The interesting part to me isn’t "C vs C++," but where the languages diverged philosophical…

The "stronger type system" is mostly a myth in my opinion. It was true in the past in pre-prototype C. The void pointer rules are better in C IMHO as they avoid unneeded casts (that then remove more type safety) and FAMs and variably-modified types can express things C++ simply can't do well.

I don’t understand your point at all, C++ objectively has a much stronger type system. It’s turing complete!

I’m not arguing that that’s better, or worse, but it’s definitely true and by no means a myth.

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

#54
post #29

Earlier quoted context omitted.

The "stronger type system" is mostly a myth in my opinion. It was true in the past in pre-prototype C. The void pointer rules are better in C IMHO as they avoid unneeded casts (that then remove more type safety) and FAMs and variably-modified types can express things C++ simply can't do well.

> The void pointer rules are better in C IMHO as they avoid unneeded casts ...so much this! A void pointer is an "any-pointer" by design. It shouldn't require casting from and to specific pointer types, that defeats the whole point of having void pointers in the first place.

> It shouldn't require casting from and to specific pointer types

You don't need to explicitly cast T* to void* (guaranteed to be safe), you only need to cast when converting out of void*.

The rules are basically the same as casting between pointer-to-derived-class and pointer-to-base-class and they make sense.

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

#55

From the article: In 2019 I wrote a short survey of C constructs that do not work in C++. The point was not that C is sloppy or that C++ is superior. The point was that C++ is not a superset of C, and that C programmers crossing the border should know where the checkpoints are. C++ was a superset of C 30-ish years ago. Now, as the author correctly identifies, it is not as both have taken different evolutionary paths.

30 years ago, in C89 and pre-standard C++, it was the case that `int foo()` in C is a function that accepts any parameters, and in C++ it is a function with no parameters. In C89 you have to write `int foo(void)` if you want no parameters. This counterexample to C++ being a superset of C was well-known even back then. Another well-known counterexample is implicit conversion from void*. In C89 you can do `int* foo = m…

Perhaps in c-with-classes(Cpre)? To the extent that its output could be considered C.

It looks like you're right and the answer to when was C++ a superset of C may well be "never".

From the description, Cfront had always been a full-fledged parser that only happened to output C since the very beginning.

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

#56
post #33

I think the problem is that C++ is a poorly designed language with a fundamentally flawed development process. Instead of letting compiler implementers decide which features to add and how to implement them, C++ employs a standards-first, top-down approach. Features are often defined by committee members who may not use modern C++ in their daily workflows, leaving it entirely up to the individual implementations to c…

C++ is a language with perfect 30-year backwards compatibility, and which mostly-maintains compatibility with another language it forked from (C), after 40 years of diverging development. Rust is a language which isn't backwards-compatible, and certainly not compatible with source code in other languages. Now, sure, Rust has its advantages, but - how can you fault C++ in the context of compatibility?

this compatibility sucks sometimes.

for example you want to add nice feature to c++ with nice syntax, but there is a similar syntax somewhere in C that nobody uses, but you have to support it. you end up with nice feature with horrible syntax.

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

#57

I wrote this after repeatedly seeing experienced C programmers hit the same sharp edges while moving into modern C++ codebases. Many of these differences are intentional and defensible from the C++ side. But some are still surprising because they invalidate patterns that were historically common, performant, or idiomatic in C. The interesting part to me isn’t "C vs C++," but where the languages diverged philosophical…

You might be interested in the scpptool feature to help convert C code to a subset of C that will also compile as C++ (under clang++ at least) [1]. While many of the necessary modifications are fairly trivial, some of them aren't completely so. For example, C++ does not allow `goto`s that would skip over the declaration/initialization of a variable that would be accessible after the jump. So getting the C code to work as C++ can involve some (automatic) code restructuring.

Another annoying detail is that C++ doesn't seem to like forward references of `enum`s. That is, while

    struct A* a_ptr;
is fine in both C and C++ even before `struct A` has been defined, apparently

    enum A* a_ptr;
is not cool in C++ until after `enum A` has been defined.

One arguable benefit of keeping your C code compatible with (or at least convertible to) C++, is that you can theoretically use scpptool's auto-translation feature as build step to produce memory-safe executables from C code via transpilation to a memory-safe subset of C++.

[1] https://github.com/duneroadrunner/SaferCPlusPlus-AutoTransla...

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

#58
post #46
post #42

Earlier quoted context omitted.

Rust is also the systems programming language of the future. They're pretty much doing everything right.

What IMHO Rust does not get right and why I do not use it: long compilation times, high complexity, its syntax, polymorphism based on monomorphization, the requirement for many dependencies to get anything done, an ecosystem susceptible to supply-chain attacks, no ISO standard.

Out of curiosity, what do you think is wrong with monomorphization-based polymorphism? The other alternatives I'm aware of are 1. type-erasure via v-table based dynamic dispatch (which Rust also has in the form of the `dyn` keyword), which has performance and memory-allocation overhead and 2. macros, which Rust also has and, if used for polymorphism, would essentially be like compile-time monomorphization, but clunkier.

Maybe I'm missing something though and there are other alternatives done differently in other languages?

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

#59
post #12

Address white_house{ .street = "1600 Pennsylvania Avenue NW", .city = "Washington", .state = "District of Columbia", .zip = 20500, }; For me this is the most important initialization in C that helps with clarity so much, I used mostly structs to have function parameters intialized like this However C++ had at time no default initialization for unmentioned fields, so in 2017 I had to remove it when converting the code…

Designated initializers were unofficially supported by GCC (and clang IIANM) since around when C++11 was supported. See:

https://godbolt.org/z/3aKaa7dnM

only if you specifically ask to get an error, would you actually get it.

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

#60

Earlier quoted context omitted.

30 years ago, in C89 and pre-standard C++, it was the case that `int foo()` in C is a function that accepts any parameters, and in C++ it is a function with no parameters. In C89 you have to write `int foo(void)` if you want no parameters. This counterexample to C++ being a superset of C was well-known even back then. Another well-known counterexample is implicit conversion from void*. In C89 you can do `int* foo = m…

Perhaps in c-with-classes(Cpre)? To the extent that its output could be considered C. It looks like you're right and the answer to when was C++ a superset of C may well be "never". From the description, Cfront had always been a full-fledged parser that only happened to output C since the very beginning.

> a full-fledged parser

perhaps more accurately a fully fledged compiler (that emitted C)

Post reply on HN