[HN Gopher] I have no constructor, and I must initialize
___________________________________________________________________
I have no constructor, and I must initialize
Author : cyber1
Score : 264 points
Date : 2024-07-05 08:42 UTC (14 hours ago)
(HTM) web link (consteval.ca)
(TXT) w3m dump (consteval.ca)
| jakewins wrote:
| Man I get vertigo reading this. Reminds me of trying to
| understand Java constructors and object initialisation.
|
| It's been a while now, and at least in my experience so far Go
| and Rusts choice of not having special constructors really
| simplifies a lot.
|
| Is there anyone that's had the experience of missing constructors
| once you swapped away from them?
| _ZeD_ wrote:
| dude, java constructor are _easy_... that C++ stuff is really
| black magic
|
| and from what I understand rust constructors are basically the
| same as java, no?
| masklinn wrote:
| Rust does not have constructors at all[0], it uses factory
| functions (conventionally named `new_somethignsomething`) but
| those are not special to the language.
|
| [0] except in the more generalised haskell-ish sense that
| structs or enum variants can be constructed and some forms
| ("tuple structs" and "tuple variants") will expose an actual
| function
| collinvandyck76 wrote:
| I've often longed for first class constructors in Go and
| Rust. It was more of a problem for me with Go because you
| can omit a struct field when building a value, something
| you can't do in Rust unless it has an explicit Default impl
| and even then you have to explicitly add
| ..Default::defualt() when you're building the value.
|
| I never thought that constructors were that burdensome and
| therefore do not understand the omission in other languages
| like Go and Rust that followed. Quite the opposite really
| -- knowing that a type always went through a predefined
| init was comforting to me when writing Java.
| mmaniac wrote:
| Rust doesn't have constructors. By convention, a static
| method called new returns a struct - no magic.
| jakewins wrote:
| I think if you think constructors in Java are easy, you are
| much, much smarter than I am or have missed some really,
| really subtle footguns.
|
| Eg:
|
| - Java constructors can return the object before they
| complete construction, finishing at a later time; this is
| visible in concurrent code as partially constructed objects
|
| - Java constructors can throw exceptions _and_ return the
| partially constructed object at the same time, giving you
| references to broken invalid objects
|
| - Just.. all the things about how calling super constructors
| and instance methods interleaved with field initialization
| works and the bazillion ordering rules around that
|
| - Finalizers in general and finalizers on partially
| constructed objects specifically
|
| I don't in any way claim it's on the same level as C++, but
| any time I see a Java constructor doing _any_ method calls
| anymore - whether to instance methods or to super
| constructors - I know there are dragons
| SpaghettiCthulu wrote:
| > - Java constructors can return the object before they
| complete construction, finishing at a later time; this is
| visible in concurrent code as partially constructed objects
| > > - Java constructors can throw exceptions _and_ return
| the partially constructed object at the same time, giving
| you references to broken invalid objects
|
| Java constructors do not actually return the object. In
| Java code, it would appear to the caller as though the
| contructor returns the new instance, but that is not really
| the case. Instead, the new object is allocated and then the
| constructor is called on the object in (almost) the same
| manner as an instance method.
|
| Additionally, Java constructors can only leak a partially
| initialized object if they store a `this` reference
| somewhere on the heap (for example, by spawning a thread
| with a reference to `this`). The assertion that this gives
| you a reference to a "broken invalid object" is only
| potentially correct from the perspective of invariants
| assumed by user-written code. It is perfectly valid and
| well-defined to the JVM.
|
| > - Just.. all the things about how calling super
| constructors and instance methods interleaved with field
| initialization works and the bazillion ordering rules
| around that
|
| This is a gross mischaracterization of the complexity.
| There is only a single rule that really matters, and that
| is "no references to `this` before a super constructor is
| called". Until very recently, there was also "no statements
| before a super constructor is called".
|
| > - Finalizers in general and finalizers on partially
| constructed objects specifically
|
| Finalizers are deprecated.
| cvoss wrote:
| > bazillion ordering rules
|
| There are 3 which pertain to object initialization in Java.
|
| 1. super is initialized in it's entirety by an implicit or
| explicit call to `super()`
|
| 2. All instance initializers of the present class are
| invoked in textual order.
|
| 3. Constructor code following the `super()` call is
| executed.
|
| The only awkward thing here is the position of #2 in
| between #1 and #3, whereas the text of a constructor body
| suggests that #1 and #3 are consecutive. It gets easier to
| remember when you recognize that, actually, there's a
| defect in the design of the Java syntax here. A constructor
| looks like a normal function whose first action must be a
| `super()` call. It's not. The `super()` call is it's own
| thing and shouldn't rightly live in the body of the
| constructor at all.
|
| Edit: Tweaks for clarity.
| vips7L wrote:
| I think you're exaggerating the complexity here. There are
| corner cases yes, but the compiler will warn you about
| them.
| marcosdumay wrote:
| Those are the normal issues inherent to constructors as a
| concept (except for the finalizer one).
|
| Any language that has constructors has some complex rules
| to solve those things. And it's always good to check what
| they are when learning the language. Java has one of the
| simplest set of those rules that I know about.
| DougBTX wrote:
| Inside a constructor you can access a partially initialised
| "this" value, and even call methods on it, which leads to
| rules like: "Do not call overridable methods in
| constructors"[0], as they can lead to surprising, non-local,
| bugs.
|
| Rust has functions associated with types which are
| conventionally used like constructors, but critically the new
| objects must have all their fields provided all at once, so
| it is impossible to observe a partially initialised object.
|
| [0] https://learn.microsoft.com/en-
| us/dotnet/fundamentals/code-a...
| titzer wrote:
| Virgil solved this a little differently. The initialization
| expressions for fields (outside of constructors) as well as
| implicit assignment of constructor parameters to fields
| happens before super constructor calls. Such initialization
| expressions cannot reference "this"--"this" is only
| available in _constructor bodies_. Initializing fields
| before calling super and then the chaining of super calls
| guarantees the whole chain of super constructor calls will
| finish before entering the body of a constructor, and all
| fields will be initialized. Thus by construction, virtual
| methods invoked on "this" won't see uninitialized fields.
|
| https://github.com/titzer/virgil/blob/master/doc/tutorial/C
| l...
| zozbot234 wrote:
| You can most likely use session types to soundly observe a
| partially initialized MaybeUninit<MyObject> in Rust. The
| proper use of session types could ensure that the object is
| only assumed to be initialized after every field of it has
| been written to, and that no uninitialized fields are ever
| accessed in an unsound way. The issue though is that this
| is not automated in any way, it requires you to write
| custom code for each case of partial initialization you
| might be dealing with.
| masklinn wrote:
| There are a few somewhat esoteric cases where constructors
| working in-place allow magic which can be hard to replicate
| otherwise e.g. Rust is still missing _guaranteed_ "placement
| new" type behaviour.
|
| Unless you want to `ptr::write` individual fields by hand into
| a `MaybeUninit`, which you can absolutely do mind but that...
| is not very ergonomic, and requires structs to be specifically
| opted into this.
| wongarsu wrote:
| Which can be an issue if you want to initialize a 2MB large
| heap-allocated object (e.g. heap-allocating a large nested
| struct or a big array).
|
| Without guaranteed "placement new" that can mean that your
| 2MB object gets constructed on the stack and copied to the
| heap. And while Linux defaults to a 4MB stack, Windows
| defaults to 1MB and will crash your program. Or it might work
| if the compiler optimizes in your favor.
|
| It's not something you encounter frequently, it can be worked
| around, and Rust will eventually solve it ergonomically
| without introducing constructor hell (probably with just a
| keyword). But finding the best language-level solution isn't
| straightforward (efforts to fix this for rust are ongoing for
| 9 years)
| bennettnate5 wrote:
| It can also be an issue if you want to wrap any API that
| requires fixed memory locations for objects (such as POSIX
| semaphores). It's UB to call a POSIX semaphore from any
| other memory location than where it was initialized, so
| making a `Semaphore::new()` API is just asking for trouble.
| You can deal with it by `Box`ing the semaphore, but then
| you can't construct the semaphore in a shared memory
| segment (one of the stronger use cases for process-shared
| semaphores).
|
| I have a hunch this is why there's no Semaphore
| implementation in the Rust standard library, though it
| could be due to fundamental inconsistencies in semaphore
| APIs across OSs as well -\\_(tsu)_/-
| masklinn wrote:
| No, Rust doesn't have semaphores in the stdlib[0] because
| it was not clear what precise semantics should be
| supported, or what purpose they would serve since by
| definition they can't mitigate exclusive and thus write
| access to a resource and mitigating access to _code_ isn
| 't much of a rust convention. And nobody has really
| championed their addition since.
|
| Furthermore, they still present a fair amount of design
| challenges in the specific context of Rust:
| https://neosmart.net/blog/implementing-truly-safe-
| semaphores...
|
| [0] technically they were there, added in 0.4, never
| stabilised, deprecated in 1.7, and removed in 1.8
| godshatter wrote:
| >Which can be an issue if you want to initialize a 2MB
| large heap-allocated object (e.g. heap-allocating a large
| nested struct or a big array).
|
| >Without guaranteed "placement new" that can mean that your
| 2MB object gets constructed on the stack and copied to the
| heap. And while Linux defaults to a 4MB stack, Windows
| defaults to 1MB and will crash your program. Or it might
| work if the compiler optimizes in your favor.
|
| C gets a lot of hate, often for good reasons, but at least
| you know where your memory is coming from when you are
| allocating it yourself. If you're allocating a large heap-
| allocated object, you're grabbing the memory directly from
| the heap.
| wongarsu wrote:
| Memory allocation is one of the areas where currently
| C/C++ has or had genuine advantages over Rust. Custom
| allocators took Rust years, and giving standard library
| constructs like a Vector a custom allocator that isn't
| the global allocator is still experimental (=opt-in
| nightly-only). Similarly while Rust gives you good
| control over where the data ends up being stored, there
| is no way to make sure it isn't also put on the stack
| during function execution. One of the implicit
| assumptions underlying the language seems to be that the
| stack is cheap and effectively infinite while the heap is
| expensive. So you have a lot of control over what touches
| the heap, but less control over what touches the stack.
|
| Those are temporary pains that have remedies in the
| works. Rust is a fairly young language, and a lot of
| good-enough solutions get thrown out before ever getting
| beyond the experimental stage. But if you are writing
| software today then needing absolute control over where
| exactly your data touches is a good reason to prefer
| C/C++ today. Not that that's a very common need.
| marton78 wrote:
| After almost 20 years of experience with C++, there are still
| some gnarly details I wouldn't have imagined. What a God awful
| language!
|
| Kudos to that author for the great, eye catching title and the in
| depth detail!
| unwind wrote:
| In case it's not known to everyone, the title is an obvious nod
| to "I Have No Mouth, and I Must Scream" [1], a 1960s US sci-fi
| story by Harlan Ellison.
|
| 1:
| https://en.wikipedia.org/wiki/I_Have_No_Mouth,_and_I_Must_Sc...
| bookofjoe wrote:
| https://talesofmytery.blogspot.com/2018/10/harlan-
| ellison-i-...
| _vaporwave_ wrote:
| That plot summary is... dark. Does anyone know how long the
| story is? Most of the copies I found online are collections
| of short stories.
| neckro23 wrote:
| It's a short story, a brief one (~32 kB): https://gist.gith
| ub.com/neckro/0f3a9ec60be34e3164c6677d4ecc1...
|
| CW though, it _is_ pretty grim. Very early example of the
| "AI takes over the world, decides humans are redundant"
| trope though. (Maybe the first?)
| tannhaeuser wrote:
| The question is which IHNMAIMS character the poster
| identifies with to have deserved his OOP misery, given all
| protagonists are imprisoned for life (or for eternity,
| actually, I believe) as a sentence for the bad things they
| did ;) Note there's also the adventure game created after the
| book, overseen and with a script also by Ellison.
| tpoacher wrote:
| pc adventure game was good too (i.e., messed up)
| wavemode wrote:
| Always obligatory https://mikelui.io/img/c++_init_forest.gif
| CoastalCoder wrote:
| Thanks, I'd never seen that one!
|
| So horrifyingly true.
| fouronnes3 wrote:
| If you enjoy this, a few years ago I made the "C++ iceberg"
| meme (with clickable links!). I've been thinking about
| making an updated V2 with all the "you forgot about X"
| messages I've been getting.
|
| https://fouronnes.github.io/cppiceberg/
| throwup238 wrote:
| God bless you for making this. I plan to incorporate
| several of these features at work in the hope of
| summoning Cthulu and killing the company once and for
| all.
|
| What's your favorite "you forgot X"? You should
| definitely make an updated v2 because every link I've
| opened from the bottom half has been absolutely bonkers.
|
| Three dimensional analog literals drawn using ASCII? What
| the flying hell was the standards committee thinking.
| java-man wrote:
| else while
|
| is perfectly fine, not only in c++.
| CoastalCoder wrote:
| > If you enjoy this
|
| Well, I do appreciate your work, and the information is
| certainly helpful.
|
| But it's a bit like a urologist explaining what it will
| be like when you pass a kidney stone.
|
| And then find out that the C++ standards committee is
| working on a new kidney-stone shape that's backwards
| compatible, but adds more jagged spikes.
| queuebert wrote:
| I should print this and put it on my wall for all those times
| when I'm frustrated with Rust lifetimes.
| GuB-42 wrote:
| C++ is a popular multi-paradigm language that is both cutting
| edge and 40 years old (more if you count C), there is simply no
| way around that level of complexity.
|
| You have "C with classes" that coexist with the "modern" way,
| full of smart pointers and functional programming. It is
| popular in embedded systems, video games, servers, and GUIs
| (mostly Qt). And if you look at the code, it is as if it was a
| different language, because the requirements are all very
| different. Embedded system need low level hardware access,
| video games are all about performance, servers want safety, and
| GUIs want flexibility.
|
| There are less awful alternative to C++. For example C on one
| end of the spectrum and Rust on the other end. But none of them
| cover every C++ use case.
| hu3 wrote:
| Zig looks promising too.
| marcosdumay wrote:
| > multi-paradigm
|
| Well, it does unstructured imperative, structured imperative,
| and OOP imperative!
|
| Except if you count template programming, because that one is
| pure functional, but only runs at compile time.
| bee_rider wrote:
| C++ needs a different name from multi-paradigm. Java is a
| multi-paradigm language. C++ is an omni-paradigm language. If
| there's a paradigm,
|
| - There's at least an ugly library to do it in C++
|
| - There might be support baked directly into the language
|
| - Or you could do it in Lisp, but that would be too easy
| codeflo wrote:
| And if you dare to combine two of the paradigms it
| supports, you get UB.
| snappythrowaway wrote:
| What is UB?
| MaxBarraclough wrote:
| _Undefined behaviour_.
|
| Here's an article on the topic: https://cryptoservices.gi
| thub.io/fde/2018/11/30/undefined-be...
| aaroninsf wrote:
| > But none of them cover every C++ use case.
|
| Literal lol... this is not an argument in favor of C++.
| slashdave wrote:
| I would sort of agree, except when c++ was invented, it was
| even more awful in practice (does anyone remember the chaos
| around STL and template caches?). So, age isn't really a
| factor.
| wredue wrote:
| If you're looking for a language with less complexity than
| C++, you're surely not going to find that in rust.
| kelnos wrote:
| I disagree. To me, the complexity described in this article
| is more complex than anything you'll find in Rust.
|
| Actually, strike that: I'm not sure if it's true or not
| (though I suspect it is), but it doesn't actually matter.
| What I'm really getting at here is that there is nothing in
| Rust that behaves so confusingly or ambiguously as what's
| described in this article. If you're writing Rust, you'll
| never have to remember these sorts of rules and how they
| are going to be applied to your code.
|
| I do agree that _reading_ someone else 's Rust can be a
| challenge, if they're using Rust's type system to its
| fullest, and you're (quite reasonably and understandably)
| not up to speed on the entirety of it. And that _is_ a
| problem, agreed; though, at least, fortunately it 's not a
| problem of ambiguity, but more of a learning-curve issue.
|
| But I have never been writing Rust and have been confused
| about what the code I'm writing might do, never had to
| consult and puzzle out some obscure documentation in order
| to ensure that the code I was writing was going to do what
| I expected it to do. C++ falls so incredibly flat in this
| department, and that's why I avoid using it like the
| plague.
| ghosty141 wrote:
| I've been working with C++ at my job for 2.5 years now and I've
| already come to this conclusion. Wouldn't wanna use it if there
| is any other way.
|
| The fact that you can do almost anything IS pretty cool, but
| without having at least one C++ wizard at hand it can drive you
| nuts.
| ryandrake wrote:
| Just another person's opinion: I've been using C++ for my
| entire career, and to be honest, if I'm starting a new solo
| project, I reach for it unless there is some major technical
| reason not to. Yes, it can be messy. Yes, there are footguns.
| But as a developer, you have the power to keep it clean and
| not shoot the footguns, so I'm still ok with the language.
|
| If I was starting a new work project with a lot of junior
| team members, or if I was doing a web project, or a very
| simple script, fine I'll use a different language. There can
| definitely be good reasons not to use C++. But I'm at the
| point in my expertise that I will default to C++ otherwise.
| I'm most productive where I am most familiar.
| kmoser wrote:
| > Yes, there are footguns. But as a developer, you have the
| power to keep it clean and not shoot the footguns, so I'm
| still ok with the language.
|
| With all due respect to your expertise, the whole idea of a
| footgun is that it tends to go off accidentally. The more
| footguns a language contains, the more likely you are of
| accidentally firing one.
| jeffbee wrote:
| I think what he's saying is that C++ users don't need to
| go to the Footgun Outlet Mall and wantonly brandish each
| of their credit cards. You can leave the subtle parts of
| the language on the shelf, in many cases.
| 725686 wrote:
| "you have the power to keep it clean and not shoot the
| footguns". Really? Do you think footguns are intentionally
| shot?
| bee_rider wrote:
| What even is a footgun supposed to be? The analogy
| doesn't really make sense, in that... I mean the first
| thing anybody learns about guns is that they are "always
| loaded" (even when you know they aren't) and you only
| point them at things you want shot.
|
| Is a footgun a gun that only aims at feet? Because that
| seems like a dumb thing to invent in the first place. Or
| is it a gun that happens a to be aiming at feet? That
| seems like something that could only exist by user error.
|
| I think "enough rope to hang yourself" is a more accurate
| description of almost every programming languages, since
| rope is at least intended to be useful (although it is a
| bit more morbid of an analogy).
| rmwaite wrote:
| Imagine that you had a gun and one of the features of the
| gun was that if you had sunglasses on and something in
| your left pocket, holstering the gun would cause it to
| immediately fire. You could argue that the gun shouldn't
| behave this way, but it's also possible that others are
| dependent on this behavior and you can't remove it.
|
| This is a footgun - the way to avoid the holster firing
| is to simply not wear sunglasses, or keep something in
| your left pocket, and then it would never fire. But the
| problem is that both of those things are extremely common
| (for good reason). It's a poorly thought out feature
| because it has severe consequences (potentially shooting
| your foot) for extremely common situations (wearing
| sunglasses and using your left pocket).
| bee_rider wrote:
| I basically don't agree that anybody could depend on this
| holstering-causes-it-to-fire behavior. Or at least, their
| use-case requires design compromises that are so
| unthinkably ridiculous as to make the gun they want
| something that no reasonable person without that use-case
| would use.
|
| It is possible that the entire field of programming is
| full of ridiculous people. But it seems more likely that
| C++ is like a gun with no safety, or something along
| those lines.
| AnthonyMouse wrote:
| A lot of the footguns come from compiler authors wanting
| to make things UB because it allows them to perform
| certain optimizations, but then you end up with a lot of
| things that are formally UB even though in practice they
| _usually_ do the intuitively expected thing. But then,
| because the widely done thing is actually UB, the
| compiler is allowed to do something counterintuitive
| which causes your program to blow up.
|
| An obvious example is omitting NULL pointer checks.
| Passing a NULL pointer to certain system library
| functions is UB even if it would ordinarily be expected
| to be reasonable, e.g. memset(NULL, 0, 0), so some
| compilers will see that you passed a pointer to memset,
| and passing a NULL pointer to memset is UB, therefore it
| can omit a subsequent NULL pointer check guarding a call
| to _something else_ when the something else _isn 't_
| going to behave reasonably given a NULL pointer.
|
| This is an insane footgun, but it also allows the
| compiler to omit a runtime NULL pointer check, which
| makes the program faster, so people who care most about
| performance lobby to keep it.
| samatman wrote:
| Just to carry onwards with the use/mention distinction
| we're aggressively erasing here, you seem to question
| whether actual, real-life footguns exist.
|
| They do! Here's a reference.
| https://en.wikipedia.org/wiki/Slamfire
|
| Another common way to shoot yourself in the foot is a gun
| which will go off if you drop it. An example of a gun
| where early models were especially susceptible is the
| Lanchester:
| https://en.wikipedia.org/wiki/Lanchester_submachine_gun
| kelnos wrote:
| > _I basically don't agree that anybody could depend on
| this holstering-causes-it-to-fire behavior._
|
| It's an idiom. It's not supposed to be entirely logically
| consistent. It means what it means because people have
| decided that it means what it means. Your objections
| aren't really relevant.
|
| "Footgun" is I think a fairly recent addition to the
| English lexicon, but it's based on the centuries-old "to
| shoot yourself in the foot". It seems silly to argue with
| centuries of English idiomatic usage; no one, by
| definition, is going to win an argument against that.
| wvenable wrote:
| Yeah I don't think that's a good analogy. Instead, you
| have guns that don't let you point at your feet. So you
| can never shoot yourself there. However, if you ever need
| to shoot straight down for a legitimate reason, you're
| out of luck. In C++, you can shoot everywhere without
| restrictions and sometimes that means shooting yourself
| in the foot or the head.
| sqeaky wrote:
| At this point a footgun can stand alone in this industry
| as a term with its own meaning outside of analogy.
|
| It is any trap in something technical that is likely to
| cause problems from perceived normal use.
|
| Compare to related terms: "Pit of failure", "Turing
| tarpit", and "Pit of success".
| samatman wrote:
| I've long been partial to this formulation:
|
| > _1972 - Dennis Ritchie invents a powerful gun that
| shoots both forward and backward simultaneously. Not
| satisfied with the number of deaths and permanent
| maimings from that invention he invents C and Unix._
|
| Some of us learn to lean to the side right before pulling
| the trigger...
|
| http://james-iry.blogspot.com/2009/05/brief-incomplete-
| and-m...
| kelnos wrote:
| "Footgun" comes from the English idiom "to shoot yourself
| in the foot", which means "to act against your own
| interests" (usually accidentally). (Consider similar
| idioms, like "to dig your own grave".)
|
| I think you're being a bit too literal. It's not an
| analogy at all, and this has nothing to do with firearms
| best practices. If we were to define a footgun as "a gun
| that is only capable of shooting you in the foot" (or
| perhaps more broadly usefully, "a gun that in theory can
| be useful, but it is nearly impossibly difficult to make
| it do anything other than shoot you in the foot"), then
| the entire point of using the term is to describe
| something that has no useful, logical purpose, and is
| unsafe to use, even as designed.
|
| Being "given enough rope to hang yourself" is indeed
| another good idiom to use for things like this, but the
| implication is different, I think: when you're given
| enough rope to hang yourself, the outcome is still very
| much in your hands. You can intentionally or
| unintentionally use that rope to hang yourself, or you
| can be reasonably expected to use that rope in another
| way that would turn out to be safe or useful.
|
| "Footgun", by contrast, is used to describe something
| that has no (or negligible) safe uses. Maybe the original
| intent behind the design of what's being described that
| way was to have safe uses, but ultimately those safe uses
| never really panned out, or were so dwarfed by the unsafe
| uses that the safe use isn't worth the thing existing in
| the first place. But, unfortunately, there are some
| people -- maybe only 0.01% of people -- who are able use
| it safely, and critically depend on that safe use, so we
| can't completely destroy all these footguns and save
| everyone else from the error of their ways. And
| unfortunately most everyone else sees these 0.01% of
| uses, and believes they are so useful, so efficient, so
| brilliant, they want to try it too... but in their hubris
| they end up shooting themselves in the foot, like most
| others before them.
| sqeaky wrote:
| There are more an less risky behaviors. This is really
| well explored space in C++. Just using value semantics,
| shared_ptr, and RAII instead of naked news and reckless
| mallocs would improve several "old" codebase I have
| worked in. Maybe people shouldn't be reaching for
| const_cast so often, and similar. In some new languages
| some corner case may be unexplored.
|
| If you are fortunate enough for your domain to have good
| IO libraries then there is a chance you can do everything
| the "Modern" way avoid a lot of the headache and avoid
| most of the footguns entirely. That maturity and omni-
| pattern availability is potent, but all that power does
| come with the possibility of mistakes or surprises.
|
| Compare to newer languages where we don't know what might
| break or might need to do something the language omits as
| part of its paradigm. I have done a ton of Ruby projects
| and about half the time we need more performance so I
| need to bust out C to rewrite a hotspot in a performance
| sensitive way. Or sometimes you just really want a loop
| not a functional stream enumerator like is the default in
| Ruby. For a new language, Theo tried the 1 billion row
| challenge in Gleam and the underlying file IO was so slow
| the language implementers had to step in.
|
| This is an engineering and a business choice. There are
| reasons to avoid C++ and footguns, like any risk, are
| among them. These aren't risks without mitigation, but
| that mitigation has a cost. Just like newer languages
| have reasons not to use them. A team needs to pick the
| tools with risks and other cons they can handle and the
| pros that help them solve their problem.
| kelnos wrote:
| > _There are more an less risky behaviors._
|
| The problem is that your definition of risk may not be
| the same as others', and so there isn't always agreement
| on what is ok and not ok to do. And regardless, humans
| are notoriously bad at risk assessment.
|
| > _This is really well explored space in C++. Just using
| value semantics, shared_ptr, and RAII instead of naked
| news and reckless mallocs would improve several "old"
| codebase I have worked in. Maybe people shouldn't be
| reaching for const_cast so often, and similar._
|
| Right, and all that is exactly the point: all of that
| stuff is in wide use out there, and I suspect not just in
| "old" code bases. So there's still not consensus on
| what's safe to use and what's too risky.
|
| And regardless, I have enough to think about when I'm
| building something. Remembering the rules of what
| language features and APIs I should and shouldn't use is
| added noise that I don't want. Having to make quick risk
| assessments about particular constructs is not something
| I want to be doing. I'd rather just write in a safer
| language, and the compiler will error out if I do
| something that would otherwise be too risky. And as a
| bonus, other people are making those risk assessments up-
| front for me, people in a much better position than I am
| to do so in the first place, people who understand the
| consequences and trade offs better than I do.
|
| I _really_ like this value proposition: "if the compiler
| successfully compiles the code, there will be no buffer
| overruns or use-after-free bugs in it" (certainly there's
| the possibility of compiler bugs, but that's the only
| vector for failures here). For C++, at best, we can only
| say, "if you use only a particular subset of the language
| and standard library that the compiler will not define or
| enforce for you (find a third party definition or define
| it yourself, and then be very _very_ careful when coding
| that you adhere to it, without anyone or anything
| checking your work), then you _probably_ won 't have any
| buffer overruns or use-after-free bugs." To me, that's
| almost worse than useless; even if I find a C++-subset
| definition that I think is reasonable, I'm still not
| really protected, because I still have to perfectly
| adhere to it. And even if I do, I'm still at the mercy of
| that subset definition being "correct".
| alex_lav wrote:
| > I've been using C++ for my entire career, and to be
| honest, if I'm starting a new solo project, I reach for it
|
| This is "I use the language I always use because I always
| use it", and not actually a praise or C++ specifically.
| sqeaky wrote:
| Presumably "entire career" means some amount of exposure
| to other things.
|
| In my 21 years coding professionally, I will settle on
| C++ or Ruby for most problems depending on context. Ruby
| for quick, dirty, and "now!", while I use C++ for Long
| lasting, performance, strongly typed, and compatible
| things. Those aren't perfect categories and there are
| reasons to pick other tools, but Choosing C++ after a
| long career does mean something more than "I am
| comfortable with this".
| philsnow wrote:
| I don't think I've ever gotten paid for a line of c++ but
| Google has a "style guide" for internal c++ code that omits
| something like 3/4 of the language, and people seemed pretty
| happy with it overall. Maybe not "happy" but "grudgingly
| accepting because it beats the Wild West alternative".
| fsckboy wrote:
| is google's "internal" style guide this?
|
| https://google.github.io/styleguide/cppguide.html
| JasonSage wrote:
| Nit: parent didn't call it an internal style guide, but a
| style guide for their internal C++.
|
| (I'm sure it is.)
| fsckboy wrote:
| Nit nit: I don't accept your quibble, I think my usage
| was well within English usage standards; I even put
| "internal" in quotes! Consider this hypothetical
| conversation:
|
| "Is the style guide they use for internal projects the
| same as this style guide that they have published
| externally?"
|
| "could you clarify which ones you're talking about?"
|
| "Is the internal style guide you described the same as
| this one I found in google's account on github?"
|
| "oh, I see what you mean"
|
| will you send your second, or shall we simply pistols-at-
| dawn?
| Maxatar wrote:
| >"Is the style guide they use for internal projects the
| same as this style guide that they have published
| externally?"
|
| Consider that the style guide that AirBnB uses for
| internal projects is not the same as the style guide they
| publish externally, and you can sympathize with why the
| distinction matters :P.
| samatman wrote:
| Nit^3: this point would have been effectively conveyed as
| '"Google's internal style guide"'. By putting only
| "internal" into quotes, you call into question whether
| its public existence invalidates the internal nature of
| it.
|
| Whereas the respondent said this:
|
| > _Google has a "style guide" for internal c++ code_
|
| This is a style guide for definitely-internal c++ code,
| with the internality of the style guide itself
| unspecified. I'm not sure what the effect of the scare
| quotes around "style guide" is meant to be, just that it
| doesn't move the internal part next to the style guide
| part.
|
| Putting the whole thing in quotes, rather than just
| "internal", questions whether the guide you found is the
| guide referred to, rather than the internal nature of the
| style guide itself, which the quoted sentence takes no
| position on.
|
| This has been your daily dose of Hacker News style guides
| for discussing style guides.
| kelnos wrote:
| I think this is a tough one, and different people are
| going to interpret it differently.
|
| The fact that you put "internal" in quotes suggested to
| me a mild level of sarcasm or disbelief, i.e, I read your
| message as "You mean _this_ style guide, published on the
| internet, for all to see? Clearly that 's not
| 'internal'!"
|
| Either way, to me, "internal style guide" (regardless of
| any quotes placed around any word) means "style guide
| that is internal" (that is, the style guide itself is
| private or unpublished).
|
| But the person you were replying to called it a "style
| guide for internal c++ code": that word ordering makes it
| clear that "internal" is describing "c++ projects", and
| that the internal/external (or unpublished/published or
| private/public) status of the style guide itself is not
| being talked about at all.
|
| (As an aside, if the commenter upthread had instead said
| "internal style guide for c++ code", that could have also
| meant the same thing, but would have been ambiguous, as
| it wouldn't have been clear if "internal" was describing
| "style guide" or "c++ code", or both, even. But "style
| guide for internal c++ code" is about as unambiguous as
| you can get.)
| marcosdumay wrote:
| C with classes and text-template generics would be an ok
| subset of the language, if external concepts didn't keep
| creeping into its semantics. The problem is that they do.
|
| Almost every part of C++ creeps into almost every other
| part, and C was already complex enough... and let's just
| ignore that C++ is not completely compatible with C.
| jimbobthrowawy wrote:
| Is it really 3/4ths the language? (mostly culled libraries,
| or features?) I remember reading an old pdf published by
| the US air force about the subset of c++ features you're
| allowed to use for contracted software, and it's so
| different it may as well be a different language.
|
| I think I found it via a stackexchange answer about how the
| "Wiring" language for Arduino sketches differs from regular
| c++. In Wiring, it's mostly things like no rtti, no virtual
| methods not resolvable at compile time, no exceptions,
| unsafe-math, permissive casting, pre-build system
| concatenates all .ino files into one .cpp file, very
| limited libraries, and some default includes.
| FreezerburnV wrote:
| "There are only two kinds of languages: the ones people
| complain about and the ones nobody uses." - Bjarne Stroustrup
|
| Not disagreeing that C++ is awful in a lot of ways and super
| difficult though. But I still weirdly like it, personally. I
| find it a fun challenge/puzzle to work with.
| zarathustreal wrote:
| I find it annoying to have to solve a puzzle to make progress
| solving my intended puzzle (i.e. whatever I'm computing)
| umanwizard wrote:
| I think we can say Rust is beyond the "nobody uses" stage by
| now, and it's much simpler and easier than C++. (And people
| who use it tend to like it, proving Bjarne wrong).
| fiddlerwoaroof wrote:
| Or, because there's so many languages around now, they just
| use something else. I really don't like working with Rust
| myself and so I use other languages.
| saurik wrote:
| I'm sorry; you think people don't complain about Rust?
| There are tons of articles posted here from people
| complaining about Rust in various ways. Bjarne wasn't
| saying whether most people like it... that's orthogonal: I
| actually like C++, yet I have been complaining about it--at
| times quite _bitterly_ --since before it was even
| standardized!
| tomjakubowski wrote:
| Indeed, I am a huge proponent of Rust and have been using
| it since before 1.0 (even contributed to it, in the past)
| -- and I complain about Rust a lot, too. Trying to
| restate Bjarne's point here: if I wasn't using Rust, then
| I wouldn't have any reason to complain about it.
| alex_lav wrote:
| Saying people complain about something is not the same as
| saying nobody likes it...
| dgfitz wrote:
| Rust is neither simple nor easy. Full stop.
| diffxx wrote:
| I truly loathe that quote. It is a tautology that is used to
| deflect legitimate criticism.
| RogerL wrote:
| And it is not true (for any reasonable reading of the
| quote). There are very popular languages that don't get the
| deserved hate that C++ does. Sure, Python is slow,
| packaging/versioning is painful, but it is nothing like C++
| complaints.
|
| I mean, a standard (and stupid IMO) interview question is
| rate your C++ expertise from 1-10, and if you answer more
| than about 5-6 you get bounced for lying or not recognizing
| your limitations, while they gleefully point out Stroustrup
| wouldn't answer 9-10.
| wredue wrote:
| I mean. Python:
|
| Bolted on, very terrible OO that should never be touched
|
| Some of the most batshit insane ideas of encapsulation
| anyone has ever seen
|
| Some of the most batshit insane return rules anyone has
| ever seen
|
| Encouraged inconsistency from the language in the form of
| functions like "Len" that are added because sometimes
| someone feels it reads better?
|
| Encouraged unwinding exceptions as _regular flow control_
| (lol. Yikes)
|
| It is nearly universally agreed that Python has
| significant code management issues as code bases scale
|
| This is all ignoring debates of fundamental typing
| issues. Personally, I hate what Python does, but some
| people seem to prefer it.
|
| Let us not pretend Python doesn't have some language
| problems on top of its tooling problems.
| gpderetta wrote:
| You forgot "it is so slow you might be faster with pen
| and paper".
| catlifeonmars wrote:
| I feel that if the language is a challenge to work with, it
| better give you your money's worth. In 2024, there are plenty
| of other languages with better ROI, if you want a challenge.
|
| In any case, I think the primary goal of any programming
| language is to get out of your way and let you tackle more
| interesting problems related to the problem domain that led
| you to start writing a program in the first place.
| qsdf38100 wrote:
| So you hate C++. Great, thanks for your informative insights.
| echelon wrote:
| A language shouldn't be this complicated. This is dangerous and
| impossible for teams full of juniors and busy people with
| deadlines. We're only human.
| 082349872349872 wrote:
| I believe those teams just use constructors; this is a corner
| case, not SOP.
| echelon wrote:
| C++ should start pulling things out of the language with new
| editions. It would improve quality of life dramatically.
| falcor84 wrote:
| How about (C++)-- ?
| Joel_Mckay wrote:
| There was a C--, and it was an Assembly macro C like
| syntax based compiler.
|
| https://en.wikipedia.org/wiki/C--
|
| The GNU gcc/g++ was far more important to standardization
| than most people like to admit.
|
| Have a great day, =)
| pjmlp wrote:
| Rust style editions don't work with binary libraries,
| across compilers, or template code across editions, with
| semantic differences.
|
| That is why the epochs proposal was rejected.
|
| Additionally, the main reason many of us, even C++
| passionate users, reach out to C++ instead of something
| else, is backwards compatibility, and existing ecosystem.
|
| When that is not required for the project at hand, we
| happily reach out to C#, D, Java, Go, Rust, Zig, Swift,
| Odin,.... instead.
| jamincan wrote:
| If Rust style editions can work across modules, why
| couldn't they work across binary libraries and so forth?
| The whole point is to allow the language to progress
| while maintaining backward compatability.
| dathinab wrote:
| they don't work with a backward compatible application
| binary interface
|
| or more specifically they only work with ABI stability if
| they ABI doesn't change between epochs
|
| which isn't a issue for Rust because:
|
| - it is cleanly modularized
|
| - it build a whole module "at once"
|
| - it doesn't have a "stable" ABI (outside of "extern/repr
| C" parts which don't contain non reprC parts rust doesn't
| even guarantee ABI compatibility between two builds in
| exactly the same context*(1))
|
| - tends to build everything from source (with caching)
|
| - a lot of internees are intentionally kept "unstable" so
| that they can change at any time
|
| on the other side due to how C/C++ build things, doesn't
| have clean module isolation, how it chooses build units,
| how all of that is combined, how it's normal to include
| binaries not build by your project (or even you), how
| such binaries contain metadata (or don't) and how too
| much tooling relies on this in ways which make changes
| hard, how it doesn't have build-in package management,
| how it you specify compiler options and how compiler
| defaults are handled etc. come together to make that
| impossible
|
| in a certain way how you specify that you use C++11,17
| etc. is the closest C++ can get to rust editions
|
| like initially it might seem easy to introduce syntax
| braking changes (which most rust edition changes boil
| down to) but then you realize that build units using
| other editions have to be able to read the header file
| and the header file e.g. in context of templates can
| contains any kind of code and that header includes aren't
| that much different too copy pasting in the header and
| that you don't have a standard package manager which can
| trace which edition a header has and endless different
| build systems and you kinda give up
|
| purely technically it _is fully possible to have rust
| like editions in C++_ but practically/organizationally in
| context of e.g. backward compatibility with build systems
| it's just way to disruptive to be practical
| 0xffff2 wrote:
| > When that is not required for the project at hand, we
| happily reach out to C#, D, Java, Go, Rust, Zig, Swift,
| Odin,.... instead.
|
| Which is all well and good for us, the application
| developers. But if C++ wants to exist in the future as a
| thriving language (as opposed to moving in to the nursing
| home with Cobol and Fortran), then it needs to come up
| with some solution to remove cruft.
| pjmlp wrote:
| Until those languages decide to be fully bootstraped,
| alongside Khronos and OpenGroup being welcoming to them
| for newer standards, C++ won't go away.
| Someone wrote:
| It has a solution: obsoleting features and then removing
| them. For examples, see
|
| https://en.wikipedia.org/wiki/C%2B%2B17#Removed_features
|
| https://en.wikipedia.org/wiki/C%2B%2B20#Removed_and_depre
| cat...
|
| https://en.wikipedia.org/wiki/C%2B%2B23#Removed_features_
| and...
|
| Part of their 'problem' is that they have lots and lots
| of users with long-living code bases. That means that, if
| they move fast and break things, their users won't move
| to newer versions of the language.
|
| Another part is that they want to be able to generate the
| fastest code possible. That leads to such things as
| having all kinds of constructors ('normal' ones, copy
| constructors, move constructors), and giving developers
| the ability to tweak them for maximum performance.
|
| In addition, a lot of this was invented after the
| language was in use for decades. I think that makes the
| constructor story more complicated than needed.
| estebank wrote:
| > don't work with binary libraries,
|
| None of the edition changes that Rust has made have any
| effect on the ABI. It also has no stable Rust ABI, so
| there wasn't an effort to formalize that, but 1) ABIs
| should always be versioned (to avoid getting stuck with a
| bad ABI) and 2) you can use editions for other kinds of
| change in the meantime.
|
| > across compilers,
|
| This is almost tautological. Yes, having two C++
| compilers agree to their support of editions is the same
| as them agreeing to their support of concepts. I don't
| see how this is a critique of the strategy.
|
| > template code across editions, with semantic
| differences.
|
| Rust defines editions at the compilation unit level: the
| crate. But it has macros (which are akin to templates)
| and editions _are_ handled at that boundary (you can have
| code in one edition invoke macros in another) because the
| compiler tracks editions at the token level (the
| information is attached to their Span). There 's no
| reason editions in C++ can't work with templates. You
| would have to specify the edition of the template, and
| given C++ semantics you might have to have an opt-in
| scope to say "use this edition here, override the rest of
| the file", but it would be possible.
| pjmlp wrote:
| Rust editions are very conservative, expect everything to
| be built from source, with the same compiler, and don't
| touch semantic changes across versions, mostly grammar
| changes.
|
| Example, there is no story for scenario, where a callback
| defined in one version, is used in another crate version,
| calling into code, using yet another version, while
| passing a closure with a specific type with semantic
| changes across all versions.
|
| I am not yet convinced they will scale at the size of
| industry use cases for C and C++, with a plethora of
| compilers, and mixing several editions on a 30 year old
| codebase.
| dataflow wrote:
| They can't pull the rug out now, but I highly recommend making
| your own clang-tidies to flag confusing constructs (like
| defaulted out-of-line constructors) and preventing them from
| being committed.
| gosub100 wrote:
| My guess is all these details are necessary to provide C++
| "strong exception guarantee" against partially constructed
| objects. Perhaps if your member objects can throw exceptions,
| some of these pedantic initialization rules can come to the
| rescue and allow, say, a library implementor to limit
| initialization code to places where exceptions can be handled.
| bun_terminator wrote:
| True, however in practice this is rarely an issue. You usually
| only use a tiny subset of construction rules. And if you ever
| make a mistake, they are easily caught by static analysis
| tools.
| smackeyacky wrote:
| It's quite a big issue. It's actually a bit worse than the
| article makes out if you throw static objects into the mix
| and get race conditions where you don't know which objects
| get constructed first. C++ has to be approached with caution
| even by experienced devs.
| bun_terminator wrote:
| experienced (and even the not so much) devs know the perils
| of static initialization and avoid it.
| maccard wrote:
| I agree with the parent - global initialisation order is a
| once-bitten-never-again, and the reality is that working in
| most codebases doesn't require understanding all of these
| rules - knowing the quirks is usually only required by one
| or two people and the rest can work with what they've got.
| TinkersW wrote:
| that is a novice issue, it is easily avoided
| dathinab wrote:
| it being this complicated can be fine (if there isn't too much
| of it)
|
| but only if not knowing how the complicated parts work doesn't
| create any subtle issues and has reasonable compiler time
| errors and isn't fundamental needed to write any code
|
| Because then you can use the language without needing to know
| how exactly that complexity works and if you get it wrong you
| get a reasonable compiler error. And then decide to either
| spend some time to learn what you didn't know or you just write
| the code differently. But in either case you don't have a
| situation with a unexpected runtime error which should be
| impossible and where you have no good way to know where to even
| start looking.
| jjmarr wrote:
| Working as a junior in a C++ codebase is great for my career
| because the skill floor is so high. Because it's so difficult
| to do anything there's a lot of room to distinguish myself.
|
| No other language creates as many problems for programmers as
| C++.
| wateralien wrote:
| Upvote for the title.
| gattilorenz wrote:
| What an beautiful blog theme, obviously inspired by the DEC-era
| computers but also clean and minimal. Refreshing!
| imperialdrive wrote:
| Ditto
| georgestagg wrote:
| I like how the rules to the right of the headings react to the
| page width and how many lines are used.
| kazinator wrote:
| > _Otherwise, zero-initialize and then default-initialize._
|
| That can't be right ... is it? Things cannot be initialized
| twice. Isn't it more like "Otherwise, recurse the value-
| initialization over the bases and members". Then, those that are
| not classes or arrays get zero-initialized.
| SpaghettiCthulu wrote:
| I think it would be perfectly legal to zero-initialize the
| entire thing and then default-initialize, because
| initialization assumes the value is undefined.
| bregma wrote:
| You can only initialize once. After it's been initialized
| you're just assigning values, and that's not what happens
| during initialization. It's either a misunderstanding on
| behalf of the author or the words as written are not
| conveying the correct idea.
| leni536 wrote:
| Both "zero-initialize" and "default-initialize" are terms that
| have precise definitions. In this context if you substitute the
| definitions it just means first zero-initializing the non-
| static data members (and zeroing the padding), then calling the
| default constructor.
|
| It doesn't mean that the lifetime of the object starts twice,
| or anything weird like that.
| 3l3ktr4 wrote:
| This is the best title, OP.
| gpderetta wrote:
| > [...] The printed result would be 0. This is because we value-
| initialize t and, since T has a non-user-provided default
| constructor, the object is zero-initialized (hence t.x is zero-
| initialized) then default-initialized (calling the implicitly-
| defined default constructor, which does nothing).
|
| That doesn't seem correct: a defaulted constructor still default-
| initializes the members, not value initialize. I don't think
| there is any difference between defaulting inline and out of
| line. GCC seems to agree: https://gcc.godbolt.org/z/r4re5TE5a
|
| edit: I missed that the author is actually value-initializing
| x!!! The result definitely violates expectations!
|
| Generally, the details of the rules are arcane and sometimes have
| non-sensical dark corners having been extended and patched up for
| the last 40 years. But 99.9%[1] of the time you get what you
| expect.
|
| I big improvement would be making default initialization
| explicit, and otherwise always value initialize. Explicit value
| initialization is so common that the very rare times I want
| default initialization (to avoid expensively zeroing large
| arrays) I need to write a fat comment. Writing "std::array<int,
| 100> = void;" (or whatever the syntax would be) would be much
| better.
|
| [1] I had an extra 9 here... I hedged.
| adrianN wrote:
| Once every thousand lines you don't get what you expect? Rip
| gpderetta wrote:
| Once every 1000 initializations. But hey, I would sign up for
| only one bug every 1000 lines.
| hwc wrote:
| I'm so glad I use Go more than C++ these days. In Go, all values
| are always zero-initialized if you don't explicitly assign a
| value. If you need a constructor, you write a regular function
| that returns an explicitly assigned object.
|
| I like keeping the rules of the language simple enough that there
| is never any confusion.
| javierhonduco wrote:
| Personally I'm not a fan of Go's default zero-initialisation.
| I've seen many bugs caused by adding a new field, forgetting to
| update constructors to intialise these fields to "non-zero"
| values which caused bugs. I prefer Rust's approach where one
| has to be explicit.
|
| That being said it's way less complex than C++'s rules and
| that's welcomef.
| ErikBjare wrote:
| Haven't written Go in a long time, but I do remember being
| bit by this.
| zarathustreal wrote:
| Yea this can be problematic if you don't have sum types, it's
| hard to enforce correct typing while also having correct
| default / uninitialized values.
| maccard wrote:
| I spent a year and a half writing go code, and I found that
| it promised simplicity but there an endless number of these
| kinds of issues where it boils down to "well don't make that
| mistake".
| gizmo686 wrote:
| It turns out that a lot of the complexity of modern
| programming languages come from the language designers
| trying to make misaked harder.
|
| If you want to simplyfing by synthesising decades of
| accumulated knowledge into a coherent language, or to
| remove depreciated ideas (instead of the evolved spaghetti
| you get by decades of updating a language) then fine. If
| your approach to simplicity is to just not include the
| complexity, you will soon disciplinary that the complexity
| was there for a reason.
| crowdyriver wrote:
| You can always use exhaustruct
| https://github.com/GaijinEntertainment/go-exhaustruct
|
| to enforce all fields initialized.
|
| If you care, the linter is there, so this is more of a skill
| issue.
| catlifeonmars wrote:
| FWIW there is a linter that enforces explicit struct field
| initialization.
| dgfitz wrote:
| Wouldn't it just be considered bad practice to add a field
| and not initialize it? That feels strongly like something a
| code review is intended to catch.
| javierhonduco wrote:
| It's easy to miss this in large codebases. Having to check
| every single struct initalisation whenever a field is added
| is not practical. Some folks have mentioned that linters
| exist to catch implicit initialisation but I would argue
| this shouldn't require a 3rd party project which is
| completely opt-in to install and run.
| dieortin wrote:
| All bugs are considered bad practice, yet they keep
| happening :P
| kccqzy wrote:
| The problem you are describing in Go is rarely a problem in
| C++. In my experience, a mature code base rarely has things
| with default constructors, so adding a new field will cause
| the compiler to complain there's no default constructor for
| what you added, therefore avoiding this bug. Primitive types
| like `int` usually have a wrapper around them to clarify what
| kind of integers, and same with standard library containers
| like vector.
|
| However I can't help but think that maybe I'm just so
| fortunate to be able to work in a nice code base optimized
| for developer productivity like this. C++ is really a nice
| language for experts.
| dieortin wrote:
| Why would you have a wrapper around every
| primitive/standard library type?
| thowruasdf wrote:
| The downside is now all types must dogmatically have a nullary
| constructor.
|
| The Default typeclass (or trait) as seen in Haskell and Rust,
| is a far better design, as this makes the feature opt-in for
| data types that truly support them.
| kccqzy wrote:
| Don't even need to go that far. In C++ it is common to delete
| the default constructor anyways. So that achieves the opt-in.
| dieortin wrote:
| Having to delete the default constructor means it's opt-
| out, not opt-in
| kccqzy wrote:
| I don't think you really know what a real-life C++ code
| base looks like. Deleting the default constructor often
| happens implicitly with no syntax needed. This often
| happens when you define a custom constructor or when its
| member doesn't have a default constructor.
| jeffbee wrote:
| Go makes a completely reasonable tradeoff, giving away
| performance to gain ease of use. C++ also makes a tradeoff that
| seems reasonable or necessary to its users, that it makes it
| possible to not be forced to write to the same class member
| twice, in exchange for a more complex language. Any language
| that attempts to offer this property unavoidably adopts the
| complexity as well. See, for example, Java.
| AlexandrB wrote:
| For more C++ wackiness, I recommend the C++ FQA:
| https://yosefk.com/c++fqa/
|
| It's 15 years out of date now, but also timeless since C++
| rarely/never removes old features or behaviours.
| bookofjoe wrote:
| >I Have No Mouth, and I Must Scream (1967)
|
| https://talesofmytery.blogspot.com/2018/10/harlan-ellison-i-...
| jolj wrote:
| Is there a C++ tool that adds/shows all the implicit stuff that
| happens behind the scenes?
|
| Such as all the constructors that are being added, implicit copy
| constructor and all the other surprises?
| fouronnes3 wrote:
| Best you're gonna get is a combination of godbolt and
| cppinsights.
| jolj wrote:
| cppinsights looks like what I was looking for, there's even a
| vscode extension thanks
| sixtram wrote:
| Great link, I'm going to add this to my list of favorite
| interview questions. (^_-)
| jeffbee wrote:
| I agree there is a lot of complexity in C++ in the year 2024,
| however I feel that much of the appearance of complexity around
| initialization is due to the pedantic, dogmatic use of the word
| "default" by the committee to mean "not".
| amluto wrote:
| I'm surprised there were no snarky comments about:
|
| > So, here's the glue between list-initialization and aggregate
| initialization: if list-initialization is performed on an
| aggregate, aggregate initialization is performed _unless_ the
| list has only one argument, of type T or of type derived from T,
| in which case it performs direct-initialization (or copy-
| initialization).
|
| The word "unless" is even bold.
|
| We have fancy syntax: T t{v0};
|
| And we also have: T t{v0, v1};
|
| And so on. But the one-element case does not reliably work like
| the 2+-element case. And this is in a language that increasingly
| works toward making it straightforward to create a struct from a
| parameter pack and has support for variable length array-ish
| things that one can initialize like this. And the types can, of
| course, be templated.
|
| So you can write your own constructors, and you can initialize a
| tuple or array with only one element supplied, and you might trip
| over the _wrong_ constructor being invoked in special cases.
|
| I remember discovering this when C++11 initializer lists were
| brand new and thinking it was nuts.
| TinkersW wrote:
| Initializer lists is irreverent, nobody uses it anyway. Other
| than a few standard containers that use it, you can completely
| ignore the silly thing.
| alex_lav wrote:
| As is the nature of bad design, "nobody uses it other than
| some people sometimes" is a silly sentiment and indicative of
| a problem.
| Maxatar wrote:
| That's the biggest problem with them. Something isn't as
| dangerous when it's in your face and you need to confront it
| on a regular basis. What's dangerous are the things that
| rarely need to think about, except for that very rare moment
| when it bites you in the ass precisely because it's not on
| your mind.
| vsgherzi wrote:
| this has got to be one of my favorite blog names i've seen on
| this site
| pierrebai wrote:
| The article is just plain wrong about classes: if you have
| declared any constructor, then the language will _not_ provide a
| default constructor and default-initialization will fail with a
| compiler diagnostic.
|
| So their claim that "T t;" will "do nothing" is incorrect.
| class T { public: T(int); };
| T t;
|
| Will fail.
| OptionOfT wrote:
| T::T() = default;
|
| > You'd expect the printed result to be 0, right? You poor thing.
| Alas--it will be garbage. Some things can never be perfect, it
| seems. Here's a relevant excerpt from our description of value-
| initialization:
|
| Link:
| https://consteval.ca/2024/07/03/initialization/#:~:text=You%...
|
| That actually isn't that weird, because it would allow any
| consumer of your library to change how your library behaves.
| nxobject wrote:
| As an aside, I see that DEC front panel you've got there in your
| blog header.
___________________________________________________________________
(page generated 2024-07-05 23:01 UTC)