Live data from Hacker News

C++ and the Culture of Complexity (2013)

blog.greaterthanzero.com

271–280 of 285 posts

Re: C++ and the Culture of Complexity (2013)

#271

Earlier quoted context omitted.

"dragged in every last weird and contradictory feature of what is a really enormous language" This happens with every language that has a lot of features. You have to try them before you can form an opinion.

> This happens with every language that has a lot of features. Seems like the key is to not have a lot of features, then.

Then we should be using FORTRAN 77 forever?

Re: C++ and the Culture of Complexity (2013)

#272

Earlier quoted context omitted.

How would exactly an library compiled for 32 bit big endian POWER interoperate with a program written for 64 bit little endian ARM?

This doesn't work with C either or does it? C has a reasonable ABI so maybe we should get to the point where exchanging C++ libraries is as easy as doing this with C

The point is there is no standard C++ (or even C) ABI because it is not possible to standardize one. At best you can standardize a platform specific ABI. Which is in fact what happens in practice on most platforms, but it is up to the platform mantainers and the C++ standard itself can't have nothing to say.

Regarding the C ABIs, they are the lingua franca for interchange between languages because, a) as C is semantically poor, it is the minimum common denominator, and b) it is often the OS ABI.

Re: C++ and the Culture of Complexity (2013)

#273
post #40

Earlier quoted context omitted.

Object Pascal, Eiffel, Ada, Mesa/Cedar, Oberon, Modula-2, Modula-3, Oberon, Oberon-2, Oberon07, Active Oberon, Component Pascal, Sather, Swift, D, Go, Rust are OO languages[1] and value based as well. [1] - As usual, there are many ways of doing OO, not just C++/Java style.

Interestingly half of those are Wirth or Wirth derived languages. He seems to like value based programming.

I just remembered the quip about "a PASCAL programmer knowing the value of everything and the Wirth of nothing".

Re: C++ and the Culture of Complexity (2013)

#274
post #258

Earlier quoted context omitted.

Headers are what need fixing first. They are why I would never consider using C++ for any new project and avoid jobs that require maintaining C++ code. C++ is the steam power of computing and keeping legacy monoliths running doesn't do anyone any favors. That shit should have been piece-by-piece rewritten by now.

You're forgoing all of the sweet cash that C++ legacy maintainers will make in 20-odd years. Like the COBOL people right now.

Hey! That's my retirement plan!

Re: C++ and the Culture of Complexity (2013)

#275

Earlier quoted context omitted.

They really aren't that bad... in fact, they're pretty useful. Source: your everyday C++ programmer

They’re great, really. Yes, it takes effort to master, but then you can generate faster, safer, generic code with much less effort. Source: Another everyday C++ programmer. There are dozens of us. Dozens!

It's unfortunate when your codebase is C++03 only and intends to remain that way for compatabillity with other vendors. Yay for consumer electronics!

Re: C++ and the Culture of Complexity (2013)

#276
post #97

Earlier quoted context omitted.

It seems to have many fewer language-level features. No lvalue/rvalue distinction, pointers are not elevated to a language-level feature (only references), only a very limited exception mechanism (panic) that doesn't try to generalize to support general validation (rather general validation is done with Result which is a plain old datatype written in the language, though admittedly it relies on a macro for use - more…

FWIW > Result which is a plain old datatype written in the language, though admittedly it relies on a macro for use It does not. It relies on a special construct (!) or macro (try!) for convenience , but these are not necessary (a popular alternative is to use the various HoFs instead) and desugar to pretty trivial (if possibly repetitive) code: macro_rules! try { ($expr:expr) => (match $expr { $crate::result::Result…

I don't think Result would be seen as an acceptable replacement for exceptions without the macro/special construct. But I should've been clearer.

Re: C++ and the Culture of Complexity (2013)

#277
post #207

Earlier quoted context omitted.

Forgot to mention couple other design decisions: No new, delete operators in any C++ code. ISR code was also in C++. All objects are statically allocated - with 4MB of SRAM, one can easily see why. It allows tightly control memory usage by the developer. All regression tests are automated. There were test scripts for all functional HW/SW components. Found one bug triggered in 24.9 days time frame (31 bit timer counte…

Very interesting. Was the build environment all inside MPW?

I don't remember. Long time ago.... Likely just steps inside makefile.

Not really a big fan of the Mac at that time - It was before Steve Jobs came back and merge the OS with Next? The Mac was very unstable. I remember it crash 3-5 times a day for my daily tasks - editing, cross compile.

Re: C++ and the Culture of Complexity (2013)

#278
post #206

I like the fact that in C++, the line x = y; behaves the same if the types are int and vector (unlike e.g. Java and Python).

Except you are not always assured on what = does when reading other people's code. :)

Well, you can define a function in Java called setFoo, but that instead sets bar. Similar.

You can intentionally confuse in most letters if you want to.

Re: C++ and the Culture of Complexity (2013)

#279
post #253
post #240

Earlier quoted context omitted.

A simple case is hiding the implementation and exposing a public API. Let's use objects to make it something C++ ought to be good at and C ought to be bad at. In C, you write a header file adder.h: struct Adder; struct Adder *adder_create(void); void adder_setup(struct Adder *, int, int); int adder_operate(struct Adder *); void adder_delete(struct Adder *); You can easily imagine how one would trivially implement the…

It's convoluted because the idea of forcing an object to always be allocated on the heap is convoluted. The real fix for this problem is the modules system, where the compiled module can expose an object's size without exposing its contents. Your example shows why header files suck more than anything about the core semantics of C++ as a language.

> The real fix for this problem is the modules system, where the compiled module can expose an object's size without exposing its contents.

Exposing the object size is already too much, it's part of the ABI. The truth is : we can't have our cake (maximum perf due to stack allocation) and eat it too (hide all implementation details)

Re: C++ and the Culture of Complexity (2013)

#280
post #261

Earlier quoted context omitted.

About your two realizations: 1. I've "exposed" parts of the private implementation in that they were in the header file, yes. They were also labeled "private". That means that someone can read that and gain more information about my implementation then they could from just public information, I suppose. It also means that nobody can actually use them in code, because they're private . So you can think of that as "exp…

Maybe I just don't have your problems, but I'm still not seeing this as much of an issue at all. Surely problems are always personal, this all did start with the term "pet peeve". For me, one of the peeves that comes back over and over is indeed that it seems that's near impossible to write a separation between the API and the implementation in C++ that is clean and beautiful. That's one of the first things in any pr…

> So the language that forces me to do just that for the sake of convenience for the language designer and compiler writers is just plain stupid.

Nothing prevents you from getting the same ABI hiding in C++, but the users of your code will greatly benefit: no possibility of memory leaks, ownership is enforced since copy & move are disabled, etc:

    /// Adder.hpp ///
    struct Adder {
      public:
        Adder(int, int);
        ~Adder(); 
        
        int operator()();

      private:
        struct Impl;
        std::unique_ptr impl;
    };

    /// Adder.cpp ///
    struct Adder::Impl { 
        // your private stuff
    };

    Adder::Adder(int x, int y)
      : impl{std::make_unique(x, y)} { 
      
    }

    Adder::~Adder() = default; 

    int Adder::operator()() { 
      return impl->stuff * 2;
    }

    /// main.cpp ///

    int main() {
        Adder adder{1, 2};
        return adder();        
    }

    /// your main.c ///

    int main(int argc, char** argv) {
        struct Adder* adder = adder_create(); // must not forget
        adder_setup(adder, 1, 2); // must not forget
        int res = adder_operate(adder); // note how all lines are longer
        adder_delete(adder); // must delete
        return res; // we had to introduce a specific variable just for the sake of keeping the return value else we wouldn't be able to delete
    }

Of course, your code wouldn't pass code review in either cases: introducing indirections through implementation hiding like this kills performance, in C and C++ likewise. And it's not like hiding your stuff in another object file will prevent anyone from knowing your impl... disassembly & code recreation tools are extremely powerfuls nowadays.
Post reply on HN