C++ Stockholm Syndrome


  • Considered Harmful

    @lb_ More typing isn't always worse. You could write all your GUI code in one place, but instead it gets split up into models, views, and controllers. And I've yet to see an example of if constexpr that's actually useful and couldn't be done with specialization.



  • @pie_flavor said in C++ Stockholm Syndrome:

    I've yet to see an example of if constexpr that's actually useful and couldn't be done with specialization.

    All uses of if constexpr can be done with specialization. The difference is that if constexpr makes it dramatically simpler and easier to read and write. With specializations you may have to pass local variables as parameters to specializations to 'maybe' do code based on the condition, and whenever you need to change the implementation or add another variable you have to adjust all specializations. It can become a nightmare very fast without if constexpr, and in fact it was a nightmare before we had it.



  • @topspin said in C++ Stockholm Syndrome:

    since the latter should at least fall under the as if rule.

    That's only the case if log and sqrt are guaranteed to be the standard library implementations of those functions and not some crazy LD_PRELOAD-injected version.


  • Impossible Mission - B

    @pie_flavor said in C++ Stockholm Syndrome:

    @lb_ I never brought up scripting languages, and you only did on a completely unrelated topic. C++ is not a scripting language

    What is Template if not a scripting language whose execution engine is the C++ compiler?



  • @lb_ said in C++ Stockholm Syndrome:

    So since I'm stuck with C++ maybe I just have stockholm syndrome, but here's some requirements for any replacement language:

    I don't have quite so many bullet points, but we share several. The things I'd like a replacement language to have are:

    • Exceptions
    • Constructors and Destructors
    • Static typing
    • Good support for generic programming
    • A memory model that lets you determine how objects will be laid out if you need to.
    • Better syntax and build rules.
    • User types treated the same as built in types.

    Largely, I want C++ without C compatibility. A lot of the mess in C++ (and a big part of its success) is due to having to follow a syntax and retain the same meaning as a language lacking a lot of its features. C can get away with its compilation model for various reasons (you can link against something compiled in a different compiler being the biggest one), but C++ can't. And if it had been created with its own requirements from the get go, it would be a much better language. Of course, it would probably have been less successful too. Technical merit doesn't determine success, and Stroustrup seemed to have a good grasp of this idea. He made the trade-offs he felt he needed to, and overall I prefer the language we did get to a hypothetically better language that wasn't adopted.



  • @masonwheeler said in C++ Stockholm Syndrome:

    What is Template if not a scripting language whose execution engine is the C++ compiler?

    It's clearly a game engine: https://blog.mattbierner.com/stupid-template-tricks-super-template-tetris/


  • BINNED

    @ben_lubar said in C++ Stockholm Syndrome:

    @topspin said in C++ Stockholm Syndrome:

    since the latter should at least fall under the as if rule.

    That's only the case if log and sqrt are guaranteed to be the standard library implementations of those functions and not some crazy LD_PRELOAD-injected version.

    That's not an issue. The standard library is part of the language specification, but the spec has no concept of dynamic libraries etc. Also you can statically compile the library in.
    Anyways, the compiler can assume knowledge of the implementation and e.g. replace it with intrinsics. Another example is rewriting manual memory copies with calls to memcpy.


  • ♿ (Parody)

    @masonwheeler said in C++ Stockholm Syndrome:

    @ben_lubar said in C++ Stockholm Syndrome:

    @masonwheeler said in C++ Stockholm Syndrome:

    @topspin said in C++ Stockholm Syndrome:

    Got a specific example where this is horrible so we can make sure to talk about the same thing?

    You run into it all the time in GUI programming. Stuff that looks like:

    MyWidget.Frob();
    try:
       DoStuffWith(MyWidget);
    finally:
       MyWidget.UnFrob();
    

    Where Frob represents temporarily placing it in a specific state that should be reversed once you're done with whatever you're doing.

    That has nothing to do with resource acquisition or destruction, but you still want it to be exception-safe so that if a recoverable exception gets thrown, it doesn't leave your UI in an inconsistent state.

    std::frob frobbed(MyWidget);
    DoStuffWith(MyWidget);
    // compiler calls frobbed.~frob() when scope ends.
    

    Exactly. When all you have is a hammerRAII, everything starts to look like a nailclass with its own constructor and destructor. Add that in to the example and it looks a lot less simple and clean.

    It sounds more like, "When you hate C++ it doesn't matter if it ever got anything right because it all looks wrong to you." Did RAII run over your dog?


  • ♿ (Parody)

    @dkf said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    I still don't see how being Turing complete, whether by accident or not, is a problem.

    It's a problem because C++ compilers aren't exactly the world's nicest or most efficient scripting engines. (This is not a comment on the code that they produce or the efficiency of other parts of the compilation pipeline.) Systems designed from the beginning for generating code using programmable transforms can be a lot more efficient.

    Sure, but I don't think that really addresses mason's alleged complaint about "Turing complete by accident," assuming he is even correct about that (I don't know enough about the history of the language to be able to say).


  • BINNED

    @boomzilla said in C++ Stockholm Syndrome:

    Sure, but I don't think that really addresses mason's alleged complaint about "Turing complete by accident," assuming he is even correct about that (I don't know enough about the history of the language to be able to say).

    He is historically correct about that part, but I'm not sure how it matters. I guess the problem is that, at least until recently, template meta-programming was a pretty awful, duck-typed, functional* sub-language; and a pain to write and debug.

    *I've recently found a post about "stateful metaprogramming", but fortunately the consensus seems to be that's a loophole and too arcane, so it will be prohibited.


  • Banned

    @boomzilla said in C++ Stockholm Syndrome:

    @dkf said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    I still don't see how being Turing complete, whether by accident or not, is a problem.

    It's a problem because C++ compilers aren't exactly the world's nicest or most efficient scripting engines. (This is not a comment on the code that they produce or the efficiency of other parts of the compilation pipeline.) Systems designed from the beginning for generating code using programmable transforms can be a lot more efficient.

    Sure, but I don't think that really addresses mason's alleged complaint about "Turing complete by accident," assuming he is even correct about that (I don't know enough about the history of the language to be able to say).

    Templates definitely are Turing complete, and they definitely weren't made that on purpose. The only open question is whether it actually makes them worse, and how much less bad they would be without it. From my brief study of various proofs of Turing completeness, it looks like integer parsmeters is the critical piece, so non-Turing-complete templates would be templates without integer parameters. 100% awfulness with 10% utility of what we have now.


  • Considered Harmful

    @kian said in C++ Stockholm Syndrome:

    @lb_ said in C++ Stockholm Syndrome:

    So since I'm stuck with C++ maybe I just have stockholm syndrome, but here's some requirements for any replacement language:

    I don't have quite so many bullet points, but we share several. The things I'd like a replacement language to have are:

    • Exceptions
    • Constructors and Destructors
    • Static typing
    • Good support for generic programming
    • A memory model that lets you determine how objects will be laid out if you need to.
    • Better syntax and build rules.
    • User types treated the same as built in types.

    Largely, I want C++ without C compatibility. A lot of the mess in C++ (and a big part of its success) is due to having to follow a syntax and retain the same meaning as a language lacking a lot of its features. C can get away with its compilation model for various reasons (you can link against something compiled in a different compiler being the biggest one), but C++ can't. And if it had been created with its own requirements from the get go, it would be a much better language. Of course, it would probably have been less successful too. Technical merit doesn't determine success, and Stroustrup seemed to have a good grasp of this idea. He made the trade-offs he felt he needed to, and overall I prefer the language we did get to a hypothetically better language that wasn't adopted.

    Rust.


  • Banned

    @pie_flavor you forgot footnotes:

    1) In Rust, you return Resut (a value-or-error type) rather than throw exceptions, but it works pretty neatly - it's nothing like C or Go.

    2) There are no constructors in Rust, but there's a common pattern of making a new() static method, with or without params, for object creation purposes - avoiding all problems with constructors ye retaining the same utility. Also a Default trait. Also, no equivalent of placement new as of yet, but they're working on it.


  • Considered Harmful

    @gąska placement new?


  • Banned

    @pie_flavor a.k.a. syntax sugar for calling constructor on arbitrary this. Useful for custom non-global allocators and other funny stuff.

    Edit: note that Rust supports custom global allocators.


  • Discourse touched me in a no-no place

    @topspin said in C++ Stockholm Syndrome:

    That's not an issue.

    More to the point, if you do that sort of stupid thing and come a cropper then you've got nobody to blame but yourself. ;) Similarly, if you deliberately put your fingers in a mincing machine, you really ought to not expect the result to go well for your hopes at being a concert pianist…


  • Discourse touched me in a no-no place

    @gąska said in C++ Stockholm Syndrome:

    a.k.a. syntax sugar for calling constructor on arbitrary this.

    a.k.a “make me an object here”. Very useful in low-level programming, especially against memory-mapped hardware.


  • Impossible Mission - B

    @gąska said in C++ Stockholm Syndrome:

    There are no constructors in Rust, but there's a common pattern of making a new() static method, with or without params, for object creation purposes - avoiding all problems with constructors ye retaining the same utility.

    How does this avoid all problems with constructors while retaining the same utility?


  • BINNED

    @masonwheeler said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    There are no constructors in Rust, but there's a common pattern of making a new() static method, with or without params, for object creation purposes - avoiding all problems with constructors ye retaining the same utility.

    How does this avoid all problems with constructors while retaining the same utility?

    I missed some part of the argument, what are the problems with constructors to begin with and why leave them out?


  • ♿ (Parody)

    @topspin said in C++ Stockholm Syndrome:

    He is historically correct about that part, but I'm not sure how it matters.

    Yes, exactly. He keeps saying it as though it's some sort of obvious gotcha, when in fact it's mostly irrelevant and downstream of the major :wtf:s.

    @topspin said in C++ Stockholm Syndrome:

    I guess the problem is that, at least until recently, template meta-programming was a pretty awful, duck-typed, functional* sub-language; and a pain to write and debug.

    Well, yeah.


  • Banned

    @topspin said in C++ Stockholm Syndrome:

    @masonwheeler said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    There are no constructors in Rust, but there's a common pattern of making a new() static method, with or without params, for object creation purposes - avoiding all problems with constructors ye retaining the same utility.

    How does this avoid all problems with constructors while retaining the same utility?

    I missed some part of the argument, what are the problems with constructors to begin with and why leave them out?

    1. They are special. Reducing number of "special" things in a language is always good - it reduces complexity and makes it easier to uniformly handle the "regular" and the "special" thing by making them both "regular".
    2. It's impossible to handle errors in constructors sensibly without exceptions. Some will of course point out it's only a problem if you don't have exceptions (and make it into an argument why Rust sucks for not having exceptions), but this works both ways - not having exceptions is only a problem if you have constructors, and Rust doesn't have constructors.

  • kills Dumbledore

    @gąska said in C++ Stockholm Syndrome:

    not having exceptions is only a problem if you have constructors

    No


  • BINNED

    @gąska said in C++ Stockholm Syndrome:

    They are special. Reducing number of "special" things in a language is always good - it reduces complexity and makes it easier to uniformly handle the "regular" and the "special" thing by making them both "regular".

    How does Rust (to use that example) deal with things like copy construction? Is all that explicit?



  • @jaloopa said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    not having exceptions is only a problem if you have constructors

    No

    Care to elaborate? In the C++ world, exceptions are the way to report a failure in a constructor. Being able to have partially constructed objects in an invalid state after calling a constructor is considered a design flaw.


  • kills Dumbledore

    @lb_ Not having exceptions is a problem whether you have constructors or not. Most exceptions I throw aren't from constructors



  • @jaloopa said in C++ Stockholm Syndrome:

    @lb_ Not having exceptions is a problem whether you have constructors or not. Most exceptions I throw aren't from constructors

    I thought it was best practice to make sure your constructors can't throw exceptions (usually by doing nothing but assignment and very simple exception-safe calculations). But what do I know, I never went to any of those fancy programming schools.



  • @benjamin-hall I think that used to be a thing some time ago. The more modern mindset is that throwing exceptions from a constructor is OK (assuming there is a reason to do so). In the end, constructors are not that special, they are still mostly just ordinary functions (the main exception being that the compiler knows how to invoke them under a specific set of circumstances).

    Destructors are still different - generally, you shouldn't throw from them. Since that can lead to partially destroyed objects.



  • re: Constructors and Exceptions..... The reason for the "olde school" of NO, was because an exception in the constructor does not invoke the destructor. As RAII has become more ubiquitous, the percentage risk of "memory leaks" from this fact has dropped; swinging the general guidance.


  • Impossible Mission - B

    @thecpuwizard said in C++ Stockholm Syndrome:

    re: Constructors and Exceptions..... The reason for the "olde school" of NO, was because an exception in the constructor does not invoke the destructor.

    :wtf:

    Yet another example of how poorly thought-out the C++ language is.


  • Banned

    @topspin said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    They are special. Reducing number of "special" things in a language is always good - it reduces complexity and makes it easier to uniformly handle the "regular" and the "special" thing by making them both "regular".

    How does Rust (to use that example) deal with things like copy construction? Is all that explicit?

    Yep. The standard library has the Clone trait with clone() method that you can #[derive] (auto-implement) on your types. You can also implement it manually where needed. You can also choose not to implement it (it's the default).


  • Banned

    @jaloopa said in C++ Stockholm Syndrome:

    @lb_ Not having exceptions is a problem whether you have constructors or not. Most exceptions I throw aren't from constructors

    Most exceptions can be replaced with error returning quite easily. Constructor exceptions are about the only ones that can't.


  • Banned

    @cvi said in C++ Stockholm Syndrome:

    Destructors are still different - generally, you shouldn't throw from them. Since that can lead to partially destroyed objects.

    Um, no. You shouldn't throw in destructors because throwing causes stack unwind, which causes destruction of everything on the way to catch block, and throwing while unwinding causes instant abort.


  • Banned

    @masonwheeler said in C++ Stockholm Syndrome:

    @thecpuwizard said in C++ Stockholm Syndrome:

    re: Constructors and Exceptions..... The reason for the "olde school" of NO, was because an exception in the constructor does not invoke the destructor.

    :wtf:

    Yet another example of how poorly thought-out the C++ language is.

    An exception in constructor means the object hasn't been constructed. Why would you ever want to destroy an unconstructed object!?


  • Banned

    Whoever downvoted my post: I expect to hear your counterargument.


  • Impossible Mission - B

    @gąska said in C++ Stockholm Syndrome:

    An exception in constructor means the object hasn't been fully constructed. Why would you ever want to destroy an unconstructed object!?

    That's why. It's quite possible to have half of the construction process finished, with several sub-objects constructed that need to be cleaned up, when the constructor blows up.


  • Banned

    @masonwheeler the members ARE destructed, as well as local variables in constructor. Only the class's main destructor doesn't run.


  • Impossible Mission - B

    @gąska who's destructing them, with no destructor?

    (lemme guess: the answer is "even more RAII cancer"?)


  • Banned

    @masonwheeler it's called RAII. Out of scope - out of mind.


  • Impossible Mission - B

    @gąska Yup, called that. :rolleyes:

    So how does the RAII system know which fields on the dead object are valid assignments and which are uninitialized memory garbage, given that C++ neglects to zero out the memory before the constructor runs?


  • Banned

    @masonwheeler before constructor body is run, members are initialized in the order they were declared in class body, with constructor arguments taken from initialization list. If an exception is thrown in member constructor, all previous members are destroyed. If exception is thrown i constructor body, all members are destroyed.

    I mean, what else did you think happens? This is the only way it might possibly work.



  • @gąska said in C++ Stockholm Syndrome:

    @jaloopa said in C++ Stockholm Syndrome:

    @lb_ Not having exceptions is a problem whether you have constructors or not. Most exceptions I throw aren't from constructors

    Most exceptions can be replaced with error returning quite easily.

    Not without having to have some type of explicit flow between the point at which the "error" occurs and the place where it can properly be handled.


  • Banned

    @thecpuwizard and this explicit flow control is literally this:

    ?
    

  • Impossible Mission - B

    @gąska said in C++ Stockholm Syndrome:

    If exception is thrown i constructor body, all members are destroyed.

    I mean, what else did you think happens? This is the only way it might possibly work.

    Yeah, that's the part I'm wondering about. Because it seems like the only way it might possibly work involves destructing all members, whether or not they've been constructed at all, which involves trying to treat uninitialized members containing random garbage as real data, leading to corruption, undefined behavior, and 🍄☁.


  • Banned

    @masonwheeler ahem...

    before constructor body is run, members are initialized in the order they were declared in class body


  • Impossible Mission - B

    @gąska ahem...

    ...with constructor arguments taken from initialization list.

    What about members that are constructed in the constructor body, rather than being passed in in the initialization list?


  • Banned

    @masonwheeler they're default constructed, then replaced by what you did in constructor body. Similar to Foo foo; foo = bar();.


  • Impossible Mission - B

    @gąska Wow. So instead of simply blitting 0s into the memory space, it runs default constructors for everything?

    So much for "designed for high performance..." :headdesk:


  • Banned

    @masonwheeler said in C++ Stockholm Syndrome:

    @gąska Wow. So instead of simply blitting 0s into the memory space, it runs default constructors for everything?

    Blitting 0s usually doesn't give you valid object.

    @masonwheeler said in C++ Stockholm Syndrome:

    So much for "designed for high performance..." :headdesk:

    Your argument is bullshit and you know it.


  • Impossible Mission - B

    @gąska said in C++ Stockholm Syndrome:

    Blitting 0s usually doesn't give you valid object.

    How? If not, something is very wrong with your object.

    Your argument is bullshit and you know it.

    Hmm?


  • Banned

    @masonwheeler said in C++ Stockholm Syndrome:

    @gąska said in C++ Stockholm Syndrome:

    Blitting 0s usually doesn't give you valid object.

    How? If not, something is very wrong with your object.

    Try zero-filling SQL connection, or file handle, or callback, or graphics context, or mutex, and see how it goes. And no, null object which you can't use before further initialization isn't valid object.

    Besides, if you're about to initialize something with real values, why initialize it with zeros? Wouldn't it... decrease performance?


Log in to reply