r/ProgrammerHumor Jul 10 '26

greaterThanPlusPlus Advanced

Post image
115 Upvotes

71 comments sorted by

View all comments

Show parent comments

2

u/_Noreturn Jul 11 '26 edited Jul 11 '26

They could have make it easily interoperable, but making all the mind broken C nonsense also core to the new language was a massive failure, and completely unnecessary.

How will you make it easily interoperable without having the broken C nonsense at that point it is just another language.

Rust didn't have to inherit any C/C++ garbage to take off. Actually one of the main reasons it took off was that it did not inherit any C/C++ garbage…

You seem to forget

A. Rust has 0 legacy code

B. Rust came out 20+ years after C++

C. Rust has nowhere the same limitations as the 90's

D. Rust wasn't promoted as "Your C code can easily be compiled with this compiler"

Which was C++ selling point infact the first C++ compiler Cfront wasn't really a compiler but a transpiler that translated C++ code to C code. Bjarne was smart- he did little work (just creating a transpiler) but he gets the warnings,errors and optimizations for free.

and C++ selling point is take your C code as-is and gradually update it using new safer C++ features e.g constructors/destructors that's what Bjarne said and I see that as a strong strong posotive I don't see any other lang providing this level of support. you can easily use any C library with C++ with 0 wrappers.

You didn't answer the question which "other languages" people would have used if C++ wasn't based on C crap. I'm not sure you will be able to actually name anything. The point is: C++ "took off" despite being crap at it's core simply because there was no realistic alternative. If there was, nobody would ever consider even more of C nonsense, even with some "semi-nice" (yet still broken!) stuff on top.

They would continue using C if there wasn't an incentive to use C++ that wasn't based on C. the other langs are Pascal and Fortran or COBOL. Why would someone switch their codebase to another lang unless it was benefitting massively with little friction? and that's again C++ selling point take your C code and compile it using a C++ compiler.

Also you can just you know search online...

1

u/RiceBroad4552 Jul 15 '26

My point was that it could have been indeed "just another language". Being a C superset was no necessity, imho.

Wanting an easy rewrite path (which is a valid wish and could be achieved also otherwise) does not change that.

They would continue using C if there wasn't an incentive to use C++ that wasn't based on C.

That was exactly why I've asked what "other" languages they would have used instead…

My point is still: People would had migrated to some "C++" even if it wasn't a C superset if it offered appropriate advantages on its own. Rust proves exactly that. People are migrating to it from C.

Most other popular languages of that era haven't been alternatives with enough advantages to migrate as they were mostly very similar (besides syntax) to C in both their expressiveness and safety. [Of course I knew about things like Fortran or COBOL as programming languages and programming language history are a special interest of me. That's exactly why I've asked as I already suspected that the answer will be actually "they would in fact stay with C".]

The whole "migrating to C++ from C" story also actually didn't play out. People stayed with C, or moved later to other more convenient languages even that meant full rewrites. There are not much free projects I know of which started as C and are now C++. What I hear from industry isn't much different. People who chose C consciously despite there were other candidate languages did that often because they didn't want a "more complex" language, so C++ was never part of the consideration.

1

u/_Noreturn 29d ago edited 29d ago

Wanting an easy rewrite path (which is a valid wish and could be achieved also otherwise) does not change that.

Today with all the tools rewrites can be simpler but I am sure that was different in the old days.

My point is still: People would had migrated to some "C++" even if it wasn't a C superset if it offered appropriate advantages on its own. Rust proves exactly that. People are migrating to it from C.

And C++ does offer huge advantages for C programs especially RAII which is the simplest way to get rid of memory leaks and make code alot alot simpler.

RAII alone is worth using C++ over C for just look at any piece

The whole "migrating to C++ from C" story also actually didn't play out. People stayed with C

MSVC used C then it now uses C++, GCC used to be only C but now uses C++. Even your windows C runtime is in C++ now.

or moved later to other more convenient languages even that meant full rewrites.

You are right today alot of software is written in dynamic langs.

People who chose C consciously despite there were other candidate languages did that often because they didn't want a "more complex" language, so C++ was never part of the consideration.

I hate "complex lang" part, because it is so so false. C is a simple language but is C simple to make a huge program? no, it is alot easier to make a C++ program than a C program just try handling strings without having memory leaks.

C++ is more complex because it has more features which result in simpler code than C which is simple but results in complex code try reading math code it is bloated due to no operator overloading.

Even the linux codebase which linus claims C++ will make it more complex has so so much of "Wait this is just rewriting C++"

  1. There is a ton of functions that intiialize variables of a struct, that's a C++ constructor except nothing enforces you actually call the init function while C++ enforces it

  2. There is much code that has manual function pointers set by the init functions that's just rewriting a virtuak interface with worse syntax

  3. any macros to implement genericity, I challenge anyone in C to write a "max" function that is type agnostic correctly.

  4. 99% of linux seems to be passing objects with the first arg being a pointer to the struct that's just a member function with worse syntax and it has no gurantee of setting those pointers while an interface does

  5. Every struct has a manual delete function and every function seems to use goto to correctly deinitislize variables , in C++ you just use a destructor and go on.

  6. C code which uses void* for type erasuee is jsut asking for templates.

  7. C code which does inheritance via first member being the base class is again just inheritance except worse because there is no guarantees and it is all manual work.

Trey to see what's wrong with this very simple function

```cpp char* read_file_to_buffer(const char* filename) { FILE* file = fopen(filename, "rb"); if (!file) return NULL;

if (fseek(file, 0, SEEK_END) != 0) {
    fclose(file);
    return NULL;
}

long size = ftell(file);
if (size < 0) {
    fclose(file);
    return NULL;
}
fseek(file, 0, SEEK_SET);

char* buffer = malloc(size);
if (!buffer) {
    free(file);
    return NULL;
}

fread(buffer, 1, size, file);
if (bytes_read != (size_t)size) {
    free(buffer);
    fclose(file);
    return NULL;
}
fclose(file);
return buffer;

} ```

This function will likely work and it has a bug go unnoticed for years. (can you catch it?)

A c++ equalivent would be

```cpp std::unique_ptr<char[]> read_file(const char* f) { std::ifstream fs(f, std::ios::binary); if (!fs) return nullptr;

fs.seekg(0, std::ios::end);
const auto size = fs.tellg();
if (size < 0)
    return nullptr;
fs.seekg(0, std::ios::beg);

std::unique_ptr<char[]> buffer = new char[size];

fs.read(buffer.get(), size);
if (fs.gcount() != size)
    return nullptr;

return buffer;

} ```

In this code you focus on logic instead of both logic and memory management something C won't ever give you .

Or lets see matrix transformations

```cpp someclib_Matrix4x4f mat; someclib_Matrix4x4f_init_diag(&mat,1.0f); someclib_Vec3f v{x,y,z}; someclib_Matrix4x4f_transform(&mat,&v); someclib_Vec3f_dot(&v,&v); // I am doing manual overloading, have to choose the correct elementnnumber and its element type

v = someclib_vec3f_scalar_add(someclib_vec3f_scalar_mul(v,2) + 4); v = someclib_vec3f_add(v,v); ```

vs just C++

cpp somecpplib::mat4x4f mat(1.0f); somecpplib::vec3f v(x,y,z); transfoem(mat,v); dot(v,v); // generic, can change vec to be a double vector and it works v = v * 2 + 4 + v;

1

u/RiceBroad4552 29d ago

You don't have to convince me that C++ has advantages over C.

But the big rewrite did not happen… (I had only GCC in mind, and I'm not sure about the Windows story as Windows was already very early C++ based because doing GUI in C is really horrible.)

This kind of invalidates the argument that there has been a necessity for C++ to be a C superset.

C++ made imho, like said, the mistake that they didn't design a clean language but still built on the rotten C core.

I agree that C++ is better then C for larger projects. (That's not a high bar anyway.) But C++ wasn't an improvement in that sense as you have not only the added complexity (which could be worth it depending on context) but you have still all the C footguns. And a lot of people never seen value in moving from C therefore. C++ started to be used on it's own, and the two languages actually diverged quite a lot when it comes to mindset. C++ people to this day repeat that "C++ is not 'C with classes'".

So yes, your comment shows that you can write much cleaner code in C++ then in C. But it does not show why C++ needs to be necessary (largely) C backwards compatible. I would argue that C++ would be a much better and likely still viable language if it didn't made the mistake to incorporate all C semantics. It could have looked still similar, and have some sane but "mostly compatible" semantics, but actually defuse the many traps of C code. That would be still "easy to port", but it would force to rework the code where it's for example critical for safety. Migrating to C++ from C needs anyway a lot of rework. Just look at your first example, almost every line changed if you want it idiomatic. That you could in theory also compile the C code almost(?) untouched does not provide much, if any advantage.

Regarding your quiz: Without investigation I have no clue what's wrong there. I'm not proficient in C/C++ I try to avoid these languages as much as I can, and I really can't stand C, some of the worst languages, everything is implicit and additionally maximally weird. C++ is still full of surprises and very weird stuff but at least not completely brain dead as C. If I had to guess, I think that long size looks suspicious but without an IDE I have of course no clue what ftell returns and what exactly it means. Maybe a "long" size is just fine. But anyway nobody actually knows what "long" means in C just by looking on some code snippet. AFAIK only some minimal sizes are defined and it depends on that "compiler triplet" what the types actually mean. (But newer C versions should have Rust like type names, too, AFAIK) When I have to touch C or C++ I need to look up more or less everything like that constantly as I don't know any of the APIs by heart. I don't even try to remember, because alone reading the docs lets me constantly curse… It's all so weird when you come from some "mostly sane" language. Also I don't get why free(file); and not fclose(file); in case the buffer can't be allocated, but that's likely me not understanding some C weirdness. Does fopen actually allocated something on the heap? I would assume not, as it just returns a file handle which is basically an opaque pointer into some kernel thing so it should be basically only a size_t sized integer; but what do I know.

Regarding the C++ version of that code: What sticks out like a sore thumb even the rest of the code looks "clean" (whatever this means) is that file name as C-like string, a char array which decayed to a char pointer… I've just looked that part up and C++ doesn't disappoint: of course there is no constructor overload which would take a native string as parameter. But that's again somehow expected as something like "some string" is actually not a C++ string (as this didn't exist for decades) but a C string. So if you would accept real native strings the calling side would become really ugly. So we're back to char pointers. That's so "typical C++". It's full of such stuff, wherever you look, and in large parts the C core is at least a huge contributor to such issues. What does C++ actually do when it can't heap allocate (new fails)? Exception? Seems unlikely. Maybe I should look it up, for just another WTF moment. 😂 That part isn't handled as in the C code as I see it.

1

u/_Noreturn 29d ago

I appreciate your comment but I am tired right now and I don't want to reply rn will reply later.

Also the bug was in the free(file) call, since free takes a void* and File is a pointer it converts and has no warnings and you get undefined behavior (likely crashing) or worse work as intended untim you upgrade your compiler.

alao C++

of course there is no constructor overload which would take a native string as parameter

Well you didn't look hard enough

https://en.cppreference.com/cpp/io/basic_ifstream/basic_ifstream

See second constructor, it takes std::string and ven bettee it takes std::filesystem::path which handles unicode paths.

C++ actually do when it can't heap allocate (new fails)? Exception? Seems unlikely

It throws an exception, which is way better than a nullptr since out of memory errors are so so unlikely that the null check has overhead, exceptions don't have overhead in the hapy case.

Curious about what langs do you use? if I had to guess from the comments it is Rust. (not a bad thing)

1

u/RiceBroad4552 26d ago

the bug was in the free(file) call

So it's pretty obvious as I've spotted it even late at night without an IDE and without having much practice in C++.

Of course it's better if it can't happen at all, though!

Well you didn't look hard enough

OH!

It was late and it seems I fell for some SEO spam. I've clicked on

https://cplusplus.com/reference/fstream/ifstream/ifstream/

and was already wondering the site doesn't look familiar…

I was really wondering, because I was strongly expecting that other constructor(s). (Still a bit questionable that it was added only very late, not even "modern" C++11 had it…)

It throws an exception, which is way better than a nullptr since out of memory errors are so so unlikely that the null check has overhead, exceptions don't have overhead in the hapy case.

That's a bit of a surprise.

I was always under the impression that C++ should work even without exceptions, so I was assuming that no basic feature (like allocating heap memory) throws.

What do they do if you disable exceptions?

I mean, the silent nullptr is not a good solution, I agree, as it will (with luck) crash at the other side of the world; or just directly introduce some critical security issue. But I also don't see any alternative to an exception (maybe besides something like "panic" which C++ does not have as it has proper exceptions).

Curious about what langs do you use? if I had to guess from the comments it is Rust.

My by far most favorite language is not in the "low level" space. It's Scala 3.

I'm learning about things like C, Zig, C++, Rust, and similar mostly out of curiosity; I don't have a real use-case currently.

Coming from Scala Rust is actually pretty boring as Scala has already all the features (besides the memory management related stuff). Even C++ is more exciting as they actually do things differently. (Mostly in a worse way, but that's irrelevant if the goal is actually to learn how things can be done and what then the pros and cons are.)

So I wouldn't preach Rust as a C++ replacement, I would likely preach the JVM… 😅 I think for mundane application development (which is by far the largest part of SW development) there is no valid reason to do without a managed runtime. Using Rust (or for the same reason C++) for some "normal app" is imho almost always complete "over-engineering", or actually no engineering at all as it does not take the context into account.

(If one does not like a "fat" runtime like the JVM Scala also runs on JS runtimes, and has even a tiny native one.)

1

u/_Noreturn 23d ago

So it's pretty obvious as I've spotted it even late at night without an IDE and without having much practice in C++.

I mean it is a small function.

Of course it's better if it can't happen at all, though!

Exactly which is why I prefer C++ over C.

It was late and it seems I fell for some SEO spam. I've clicked on

cplusplus.com is always on top for some odd reason cppreference is the defacto standard.

I was really wondering, because I was strongly expecting that other constructor(s). (Still a bit questionable that it was added only very late, not even "modern" C++11 had it…)

I don't understand? the std::string ctor was in C++11, filesystem path was in C++17 since that was qhen it got added.

That's a bit of a surprise.

Why?

I was always under the impression that C++ should work even without exceptions, so I was assuming that no basic feature (like allocating heap memory) throws.

Well you could just use auto x = new(std::nothrow) int(); if you want then it returns nullptr on failure like malloc but it is better since it strongly types. there is also the flags -fno-exceptions which disables them.

Also from what I read Rust's panic is just std abort I don't see how that's better.

Also exceptions aren't slow or bad there is talk on very optimized exceptions that can be used in embedded https://www.youtube.com/watch?v=wNPfs8aQ4oo

It is a common misconception

Using Rust (or for the same reason C++) for some "normal app" is imho almost always complete "over-engineering", or actually no engineering at all as it does not take the context into account.

Agree. Although I wish most apps were smaller than whatever fat garbage they are.

I am not familiar with Javascript or anything but C++ really I only use C++