[HN Gopher] C++ Papercuts
___________________________________________________________________
C++ Papercuts
Author : signa11
Score : 136 points
Date : 2023-08-28 11:06 UTC (11 hours ago)
(HTM) web link (www.thecodedmessage.com)
(TXT) w3m dump (www.thecodedmessage.com)
| zoogeny wrote:
| > There are so many features I miss from Rust ... like sum types
| (called enums in Rust)
|
| I feel the same whenever I have to go to other languages after
| using TypeScript. I want to model all of my data using the
| limited algebraic data type operations that many newer languages
| have (usually sum and product types).
|
| Recently I've been writing some Go for a project that is a tiny
| bit beyond a plaything. I am surprised how much I actually like
| Go and I am very glad to have come to the language to use for
| real after they added generics. But several times I wanted to do
| a union `SomeType | AnotherType` and the fact it is missing from
| Go is like an itch that can't be scratched.
|
| I would also add that discriminated unions alongside type
| narrowing (usually based on branching or escape analysis) just
| seems like something I want everywhere. Add in a powerful `match`
| statement and some kind of destructuring and I start to get very
| interested.
|
| If there is some future where Go picks up sum types, adds some
| kind of support for discriminated unions and type narrowing based
| on branching - then it might just be the best general purpose
| language (although unlikely to be a contender for best low-level
| systems level language).
| Night_Thastus wrote:
| >const is not the default
|
| While I agree to a point, I also understand the argument against
| this. In programs, a lot of state needs to be changing. Which
| means you're going to type mut a LOT over the course of a 100k
| line program. And frankly, that gets tedious really quickly.
|
| If you miss a const in C++, no big deal. The program still works.
| It's mostly a safety net. [with notable exceptions] But if you
| forget a mut in Rust, the program is not going to work.
|
| That's an advantage (you can't write something incorrectly) but
| it's also tedious, imo.
|
| When working on the C++ codebase daily, I occasionally find
| myself going "Hmm, that could be const/I need const here to use
| something" and swap it over. But it's fairly rare, and overall
| less time investment on my end.
|
| Frankly, this explains most differences in Rust and C++. Rust is
| OK with the developer having to do more boilerplate, more verbose
| code, etc. for the sake of ensuring correctness. C++ assumes the
| best and goes with it to save some time in the short run. That's
| neither good nor bad, just preference.
| bombela wrote:
| > That's neither good nor bad, just preference.
|
| I would argue that one of them giving you a better chance at
| producing reliable software should go above and beyond the
| notion of preference.
| Night_Thastus wrote:
| Something const would catch is rarely the cause of broken
| software. In my experience, most issues in software are
| logical and often derived from complex behaviors and
| interactions, not misuse of syntax.
| Measter wrote:
| > While I agree to a point, I also understand the argument
| against this. In programs, a lot of state needs to be changing.
| Which means you're going to type mut a LOT over the course of a
| 100k line program. And frankly, that gets tedious really
| quickly.
|
| It may not be as large a proportion as you think. Doing a quick
| grep on the rustc compiler source (483k SLoC), there are 5431
| matches for "let mut [\w\d_]+ =", and 29520 for "let [\w\d_]+
| =". This is, of course, is only simple bindings and misses out
| on more complex patterns along with if-let and match
| expressions, but even so, about 84% aren't mut bindings.
|
| One of my own codebases (including all its Rust dependencies is
| about 1.5m SLoC) comes to about 80% not being mut. Ripgrep +
| dependencies (718k SLoC) is about 77% not mut.
| Buttons840 wrote:
| > If you miss a const in C++, no big deal. The program still
| works. It's mostly a safety net. [with notable exceptions] But
| if you forget a mut in Rust, the program is not going to work.
|
| I just can't take your argument seriously. One of your
| arguments is "the program will still work, with notable
| exceptions". I'm not persuaded.
|
| You say it's a matter of preference, fair enough. I say let's
| make companies financially liable for the consequences of their
| preferences and see how this shakes out.
| Night_Thastus wrote:
| Every language, every rule, every suggestion has exceptions
| and gotchas. That's just life, and programming in general.
|
| I can't think of anything significant off-hand, it was just
| more to stave off this part from the post:
|
| >If you take a parameter by non-const reference, the caller
| can only use lvalues to call your function. But if you take a
| parameter by const reference, the caller can use lvalues or
| rvalues. So some functions, in order to be used in natural
| ways, must take their parameters by const reference.
|
| >I say let's make companies financially liable for the
| consequences of their preferences and see how this shakes
| out.
|
| This is completely unrelated. It's also a bit of a dangerous
| road to go down and I'd suggest thinking about it a lot more.
| maratc wrote:
| const never really worked with other C++ features[0], so in any
| big pile of code you're better off not using const.
|
| [0] The compiler will gladly pass a non-const pointer to a non-
| const object to a function that expects a const pointer to a
| const object; it all "makes sense". However, a compiler will
| explode when you're trying to pass a non-const vector of non-
| const objects to a function that expects a const vector of
| const objects.
| spacechild1 wrote:
| > a function that expects a const vector of const objects.
|
| The elements of std::vector cannot be const.
| TinkersW wrote:
| The post seems like it is focused on some ancient version of C++,
| multiple of these papercuts aren't even valid today.
|
| * You can just write = default for those methods often enough,
| and having to implement these is extremely rare
|
| * use [[nodiscard]] for your silly bool get_message return
|
| * C++ does in fact support multiple return types via structured
| bindings, or just use a struct
|
| None of this is really what is wrong with C++, the real issues
| are that everyone uses a different build system and a different
| way of sharing code.
| thecodedmessage wrote:
| No, you cannot use '= default' for the assignment operators if
| you have custom copy/move constructors. I thought this was
| clear that this was my complaint in the post. I will make it
| clearer in the post. IF you customize the constructors, THEN
| =default will break your code, even though the correct
| implementation is entirely boilerplate.
|
| And for tuples, you still need to use std::tie or
| std::make_tuple on the other end.
| gituliar wrote:
| > Unfortunately, I am all too well aware of why these decisions
| were made, and it is exactly one reason: Compatibility with
| legacy code. C++ has no editions system, no way to deprecate core
| language features.
|
| Actually, I'm curious if somebody is working on a flavor of the
| modern C++ that abandons backward compatibility ?
|
| The Carbon project feels like a completely new language. What I'd
| expect instead is something that adopts best features and
| practices from modern C++, so that an average C++ project would
| require just minor changes to migrate, in spirit of Python 2 -> 3
| migration.
| omoikane wrote:
| A new language will eventually acquire its own grungy legacy
| just like C++ did, unless that new language aggressively breaks
| backward compatibility.
|
| I think the best practice is for people to stick to a subset of
| safe patterns in mature languages. For C++, that's probably the
| C++ Core Guidelines:
|
| https://isocpp.github.io/CppCoreGuidelines/
| doodpants wrote:
| Have you looked at the CppFront[1] project by Herb Sutter? It's
| less of a completely new language like Carbon. It's meant to be
| C++ with a "nicer" syntax, while providing 100% linking
| compatibility, and with 100% source backward compatibility
| available when desired.
|
| [1] https://github.com/hsutter/cppfront
| [deleted]
| pjc50 wrote:
| > I'm curious if somebody is working on a flavor of the modern
| C++ that abandons backward compatibility ?
|
| This is just Rust. You can't really deprecate bare pointers in
| C++ without completely wrecking the language.
| HALtheWise wrote:
| This... seems false? In particular, the point of an "edition"
| system is that code written for the new edition can
| seamlessly import code written for the old edition, and so a
| hypothetical pointerless "new edition" would simply disallow
| bare pointers in new files, and things like smart pointers
| would continue to be _implemented_ in old edition code.
| pjc50 wrote:
| > would simply disallow bare pointers in new files
|
| And all their header files. That's a real Year Zero moment:
| you've just cut yourself off from the standard library, as
| well as most of the code you might want to link to. I don't
| think there's any "simpler" about it.
| steveklabnik wrote:
| Bringing editions to C++ failed, and I am not aware of
| anyone trying to tackle the issues
| https://github.com/cplusplus/papers/issues/631
|
| (I could be wrong though! I follow the committee more than
| you may guess, but not as much as to think I know
| everything about what's going on.)
| [deleted]
| TillE wrote:
| You can get to a pretty clean modern C++ by convention and
| compiler warnings and static analysis.
|
| Carbon _is_ a completely new language, and that 's the point.
| Part of the language design is making compilation a lot faster,
| for example, as well as features that C++ can't realistically
| implement, while retaining C++ interop. It's an exciting way
| forward if they manage to achieve their goals, and it _would_
| be a way to gradually migrate C++ projects.
| smallstepforman wrote:
| Well, at least with C++ you can write linked lists and other
| algoritms which require multiple references. Not every engineer
| is sloppy with use-after-free, incorrect mutability, leaking
| resources etc. There are correct programs written in C++, the
| developers are not unicorns and it does not require super human
| effort. Kitchen knives are also unsafe and dangerous yet with
| their correct use we can create wonderful meals.
| clnq wrote:
| > Kitchen knives are also unsafe and dangerous yet with their
| correct use we can create wonderful meals.
|
| This is very well put and mirrors my sentiment as a long-term
| C++ swe.
|
| I also think that the following quote is rather
| misrepresentative:
|
| > C++ is a great programming language. The complaints are just
| from people who aren't up to it. If they were better
| programmers, they'd appreciate the C++ way of doing things, and
| they wouldn't need their hand-held. Languages like Rust are not
| helpful for such true professionals.
|
| C++ _is_ a great language and a lot of complaints _do_ come
| from people who aren 't up to learn it properly. This isn't
| elitism, and this state of things has been true for every
| skill-based discipline in history. I am not saying that I am
| better than people who refuse to learn C++, or that C++ is a
| better language than others - I don't think there are many C++
| programmers at all who do, it would be a very ridiculous
| stance.
|
| C++ is a great language, it is also a somewhat dangerous
| language. It is not a language for everyone and every purpose.
| And that is fine. Just like knives are great instruments even
| if they are a bit dangerous and unsafe to those who do not wish
| to learn it properly and where it makes sense.
|
| At the end of the day, it doesn't matter how many people who
| just don't see a problem with C++ one calls "elitist" or other
| things, not everyone is obsessed with micro-improving a
| language that clearly works very well.
| pjc50 wrote:
| > There are correct programs written in C++
|
| How do you know _correct_? Very few pieces of software are
| subject to full theorem-prover correctness, and very few pieces
| of C++ are completely free from ever invoking "undefined
| behavior" at runtime. Because that's extremely hard to do when
| even "x = x + 1" can be UB.
| AnimalMuppet wrote:
| By that standard, how do you know _correct_ programs are
| written in any language? I seem to recall you praising JOVIAL
| a week or two ago; well, how many full theorem-prover correct
| programs were written in JOVIAL? I would guess, zero.
|
| Don't hold C++ programs up to a standard that programs in
| other languages also can't pass.
| pjc50 wrote:
| > I seem to recall you praising JOVIAL a week or two ago
|
| Think you have the wrong person? I have no idea what this
| refers to.
| AnimalMuppet wrote:
| Well, I'll take your word on it. I was working from
| memory, not looking at a particular post. I apologize for
| the inaccurate claim.
|
| Back to the larger point: How many Rust programs meet
| your proposed level of "correctness"? How many Fortran
| programs, Java programs, Python programs? Virtually none
| of our software does. Why hold C++ to a standard that
| nothing else meets either?
| rhn_mk1 wrote:
| IMO not every coder is sloppy with use-after-free. Not everyone
| is slopy with incorrect mutability. [...] Not everyone is
| sloppy with $THING[N]. But it's hard to consistently not be
| sloppy in any one of them, and N are so many that almost
| everyone is sloppy with at least one of them, most of the time.
|
| Each probablility of a mistake may be low on its own, but they
| compound with every avenue to make mistakes.
| evouga wrote:
| I've spent hours helping my students debug their Rust
| programs of incorrect array-indexing logic, incorrectly-
| reasoned loop invariants, incorrect conditional logic, and
| everything in between. They're not double-deleting raw
| pointers, but then again, most C++ programs don't use raw
| pointers these days either...
|
| "Rust makes a few classes of bugs impossible to write by
| construction" is a very nice feature of the language. But I'm
| really turned off by how insufferable the Rust community is
| (which shines through in the OP's blog post and several
| comments elsewhere in the responses): it's never the quote at
| the start of this paragraph; it's always "writing software in
| anything but Rust is fundamentally irresponsible!" or "if a
| Rust program compiles, it must be correct!" No, not even
| close.
| lelanthran wrote:
| Funnily enough, when I joined a C++ team about 4 years ago I
| could never get _any_ senior dev to move away from using
| references instead of const pointers.
|
| Reference parameters are awful; the reader has no idea whether
| the argument will be modified or not _without reading the header
| file_.
|
| With const pointers you never have this problem.
| dureuill wrote:
| with const pointers you have the different problem that you
| need to define what happens when the nullptr is passed.
|
| While I would certainly prefer the reference to be visible at
| the call site (a mistake Rust did not repeat), if I have to
| choose, I prefer the inconvenience of having to use an IDE like
| qtcreator that will display references in a different style, to
| introducing an invalid value that needs to be handled (and will
| be mishandled).
|
| So yeah, as a senior dev, it checks out.
| YesBox wrote:
| I use this solution as a solo dev: #define $
|
| And add the $ in front of all non-const pass by reference
| parameters in the call
| MereInterest wrote:
| With const pointers, you have no idea if the parameter is
| implicitly optional, if it must point to a valid object, if it
| will throw an error when provided with a null pointer, if it
| will segfault when provided with a null pointer. Not even
| reading the header file will help you here.
|
| With const references you never have this problem.
| alexvitkov wrote:
| Yes, but non-const references are utter trash since you can't
| tell you're passing a mutable reference when looking at the
| call site, so for the non-const I'll always pass by pointer.
|
| Const references are less offensive, but I'm not going to
| pass non-const by pointer and const by reference, that's just
| inconsistent for no reason.
|
| If null is not a valid value, throw an assert at the
| beginning of the function. It's not like references can't be
| in a broken state, they're just syntax sugar for pointers
| (that also happens to wildly complicate the language's type
| system)
| ninkendo wrote:
| > Const references are less offensive, but I'm not going to
| pass non-const by pointer and const by reference, that's
| just inconsistent for no reason.
|
| Why use pointers at all? Just use const references for
| immutable stuff, regular references when you want mutation,
| normal values when you want copy semantics, and smart
| pointers for other cases (unique_ptr for move semantics,
| shared_ptr for lack of clear ownership, etc.) If you want
| to represent nullability, std::optional is a good choice.
|
| > If null is not a valid value, throw an assert at the
| beginning of the function
|
| Yikes. This means the compiler will not catch it for you.
| Why make this a runtime issue? Use the type system to your
| advantage.
| alexvitkov wrote:
| If references were guarenteed sane and consistent values
| like in Rust, sure - but it's trivial to get a bogus
| reference in C++, so I don't buy the type safety thing.
| An assert actually catches errors, a reference just
| declares intent.
|
| As for smart pointers there's a lot of domains with tight
| performance requirements where you can't afford them -
| and to be quite frank, if you can afford to use
| shared_ptr you can also afford GC, so just use a sane
| language
| MereInterest wrote:
| Yeah, I'd beg to differ there. Non-const references have
| all the non-nullable benefits over pointer-to-non-const as
| const references have over pointer-to-const. While I'd
| prefer a call-site syntax difference similar to what Rust
| has, the non-null ability of references is well worth it.
| ninepoints wrote:
| IMO read the damn header file and abide by the api contract. A
| const pointer type suggests nullability, and possibly even
| pointer arithmetic is permissible.
| TonyTrapp wrote:
| How does a const pointer express this in a way a const
| reference can't?
| dtho wrote:
| In the absence of IDE features, you can't differentiate
| between value arguments and reference arguments unless you
| view the callee's prototype. Pointers do not have this
| problem.
| TonyTrapp wrote:
| In the absence of IDE features, you also can't
| differentiate between a function taking a pointer and a
| const pointer. You must be aware in _all_ cases that the
| value that you pass to the function may be modified. Yes,
| the function would not be modifying the pointer itself, but
| the outcome is exactly the same. A reference is pretty much
| equal to a non-nullable pointer in this context.
| lelanthran wrote:
| > In the absence of IDE features, you also can't
| differentiate between a function taking a pointer and a
| const pointer.
|
| So? It still helps me with decoding `foo(bar, baz)`, as
| without the `&` I _KNOW_ that bar and baz would not
| change after the call. And since both bar and baz are in
| the local scope, I already _know_ whether they are
| pointers or not.
|
| With pointers, all the information necessary to determine
| if bar and baz would change after a call to foo is in the
| local scope. With references that information is
| elsewhere.
| gumby wrote:
| A pointer can be nullptr while a reference cannot so that would
| be a step backwards.
|
| Also the "problem" you describe is not solved by your proposed
| "solution". A const pointer can point to something that can be
| modified.
|
| You can declare a pointer to a const object, or, you know,
| declare a const ref.
| lelanthran wrote:
| [EDIT: Brainfarted in the last paragraph, read "const ref" as
| "ref"]
|
| > A pointer can be nullptr while a reference cannot so that
| would be a step backwards.
|
| Backwards from what? A reference can't be null, but it can
| still be invalid, which is a more common problem than
| forgetting to check for null-ness.
|
| > You can declare a pointer to a const object,
|
| Yes. I should have said that instead.
|
| > , or, you know, declare a const ref.
|
| That doesn't solve the original problem with references,
| though. I hate reading `foo (bar, baz)` and having to dig
| into the header to find out that bar or baz or both might be
| modified after the call to foo.
|
| When reading code, I want to be able to skip over anything
| that does not modify the state of variables in the current
| scope.
|
| Using references means that I have to know what every single
| call does. Using pointers exclusively, I can simply skip
| calls to functions with arguments that aren't pointers.
| dureuill wrote:
| > Backwards from what? A reference can't be null, but it
| can still be invalid, which is a more common problem than
| forgetting to check for null-ness.
|
| no, a reference cannot be invalid. If you are given an
| invalid reference (such as referring to an object after its
| lifetime ended, or referring to something that is not an
| object of the reference's type), then the fault lies on the
| caller. The callee cannot check the reference's validity,
| nor it is its responsibility to do so.
|
| This is *very* different from the case of a pointer, where
| the caller is not at fault, typesystem wise, for giving a
| nullptr to a function accepting a pointer.
|
| Increasing the probability of runtime errors to gain a
| little bit of readability at the caller's site is not a
| good tradeoff.
| shortrounddev2 wrote:
| Microsoft created SAL so you can annotate pointers to
| instruct the compiler to put up warnings or even errors for
| null required fields: _Success_(return)
| //out parameters should be set if this returns true
| bool tryGetValue( _In_ Map const* map, //pointer is
| for input only and cannot be null _In_ char const*
| name, _Out_opt_ Data* value //pointer is for output
| and can be null );
|
| If you pass null for _In_ params, the compiler will warn or
| error. You return true without setting the _out_opt_
| parameters, the compiler will warn or error. You can pass
| null to _out_opt_, and the compiler will warn or error if the
| function body doesn't properly check if the parameter is null
| fluoridation wrote:
| Of course, that only works if you're passing a literal
| null. If you're passing a variable the compiler will not
| check anything, so this doesn't really solve the problem.
| jprete wrote:
| The annotation does need to be propagated backwards to
| callers and declarers - and there needs to be a way to
| "annotate" an existing pointer in the scopes where you've
| proven that it's not null - but that's better than having
| no annotation at all.
|
| (Although this is something I'd 100% want C++ to do, and
| not with an annotation but with a very short operator or
| reserved word.)
| gpderetta wrote:
| If you pass a pointer (or anything with reference semantics) by
| value you can still get non local mutation through it without
| obvious call site syntax.
|
| There is no perfect solution. Avoid out parameters if possible,
| otherwise make the semantics clear via function naming or at
| least parameter naming conventions.
| fsloth wrote:
| "get any senior dev to move away from using references instead
| of const pointers." ... "the reader has no idea whether the
| argument will be modified or not without reading the header
| file."
|
| It sounds like the problem is not using an IDE.
|
| Use references whenever posssible. Then you don't need to do a
| null pointer check. C++ is a footgun. And like with all guns,
| security first. With guns - put the safety on. With C++ - check
| the pointers are not null.
|
| OFC one can argue that with proper instrumentation invalid
| pointers are captured sooner than later, but the fact is it's
| much easier to represent invalid program state using pointer
| than references.
| thecodedmessage wrote:
| Yes, the "C++ is not usable on its own and needs other tools"
| defence of C++ :-)
| PaulDavisThe1st wrote:
| In my experience (31 years of C++) it is much more likely
| that problematic pointers will be non-null but also invalid.
| ant6n wrote:
| Cant u use a const reference?
| nly wrote:
| Use a decent IDE. Most render & at the call site so you know.
|
| I find this all a bit rich anyway. In languages like C#,
| _everything_ is a bloody reference and this lame concept of
| "reference types" corrupts developer minds.
| tubs wrote:
| Java and c# are both pass by value (c# has optional ref that
| must be annotated at both the call site and definition, it
| also has value structures).
|
| Class types are effectively pointers that are passed by the
| value of the pointer.
|
| You cannot implement swap in Java without eg wrapping the
| params in one element arrays.
| raincole wrote:
| I'm pretty sure one of the biggest differences between C# and
| Java is that in C# you can't assume everything is a
| reference. A strict is passed by value.
| fluoridation wrote:
| No, strings are passed by reference, it's just that the
| string type is immutable. Passing a string to a function
| doesn't create a copy, but there's also no way for the
| callee to modify the object that the caller points to.
|
| It is true that C# has value types that are by default
| passed by copy, though.
| raincole wrote:
| I mistyped struct as strict.
| pjmlp wrote:
| Java or Python would have been a better example, as that
| isn't the case with C#.
| lelanthran wrote:
| > Use a decent IDE.
|
| When I'm navigating code, the references aren't a problem,
| because I am using an IDE of some sort, usually.
|
| The complaint I made was about reading, not navigating, for
| example when reviewing a PR.
| uxp8u61q wrote:
| Use a decent IDE that allows you to review PRs from within
| the IDE.
| pjmlp wrote:
| I do a mouse over and move on.
|
| Hardly any different from "var" parameters in plenty of
| languages since the 1960's.
| shadowgovt wrote:
| It's cool that you're using development tools that
| successfully parse the C++ you're working on.
|
| I found that to be a rare circumstance in any complicated
| code base. And once you lose that capacity, oh boy does this
| language become terrible fast.
| pjmlp wrote:
| VS, QtCreator, Android Studio, KDevelop, C++ Builder,...are
| some of the names that come to mind where this herculean
| task is possible.
| shadowgovt wrote:
| And they are, indeed, very impressive. But the nature of
| the language makes their task extremely difficult, and in
| my experience they aren't reliable.
|
| Besides the issue of C++ being just hard to compile
| (global symbol mutation via the macro system, the way
| templates instantiate, the compilation unit as the
| fundamental element of compilation meaning any individual
| compilation unit can require hundreds to thousands of
| include files as input), the language is rife with
| undefined behavior and assistive tooling is allowed to
| crash on undefined behavior. So, yes, if your tooling
| crashes it may indicate a problem with your code---but
| how are you going to find it now that your tooling has
| crashed?
|
| We've had a couple of initiatives at my organization to
| try and get tooling operational across the code base.
| They haven't stuck. Developers keep having to fall back
| to grep and pray.
|
| I prefer working with languages where there are simply
| fewer features and less undefined behavior. It makes the
| tooling more reliable.
| fluoridation wrote:
| I recently worked in a fairly large Rust project that I
| could simply not load into VS Code. rust-analyze would
| allocate more and more memory until it eventually crashed.
| I have never seen that with C++ code, besides that time I
| was investigating how someone was using CImg and found out
| that the CImg developers thought it was cute to make a
| single 3 MB header, and that brought the debugger to its
| knees. It still didn't crash, though!
|
| So yeah, difficult-to-parse codebases are not an exclusive
| feature of C++.
| shadowgovt wrote:
| Interesting. This is the first I've heard of a Rust
| codebase too big to parse, but I'm not deeply surprised;
| Rust tooling hasn't been hammered on for as many decades
| as the C++ tooling.
|
| I'm medium-level confident there's meat on the bones of
| optimizing it to a point better than the C++ tools
| because they made choices in the language that do some
| amount of compartmentalization, so you don't get that
| "one #define up in this header you've never seen changes
| the meaning of symbols in every other file in this
| compilation unit." Unless that _is_ possible and I simply
| haven 't gotten deep enough into Rust to realize it yet.
| fluoridation wrote:
| Funny you should mention that. I'm pretty sure the reason
| this project was so difficult to process was the (IMO)
| abusive use of macros. I'm talking foo!( in one line, and
| several hundred lines below was the closing parenthesis.
| fsloth wrote:
| I think you need to define what is a complicated code base
| here.
|
| Visual Studio works fine for millions of lines but I am
| sure the difference in experience can vary wildly.
| shadowgovt wrote:
| Visual Studio crashes on the code base I maintain. It's a
| monorepo using bazel to manage it, and between the sheer
| number of includes compilation units take, the hundred
| thousand plus compilation units themselves, and some
| decisions made early on that are hostile to VS code
| tooling because the original developers didn't use VS
| code (such as hiding template implementations in .inl
| files that are included in the corresponding .hh file),
| VS code is functionally unusable for us.
|
| In general, the company moves forward because most of the
| same people who established the code base are still
| working here and they just already know all the quirks
| and can Intuit argument types, often because they wrote
| all the classes in question.
| ftrobro wrote:
| Visual Studio != VS Code. I've always found Visual Studio
| to be great at C++ so I'm interested in knowing which of
| the two you meant?
| shadowgovt wrote:
| VSCode, to be clear. The fact that Microsoft released two
| products in the same domain with almost the same name
| consistently trips me up.
|
| No, we don't spend money on code editors around here; I
| meant VSCode.
| fsloth wrote:
| "No, we don't spend money on code editors around here; I
| meant VSCode."
|
| Not spending money in tools sounds like a very strange
| economics for software development. If interviewing does
| not scare you I warmly suggest finding a new employer.
| TillE wrote:
| Visual Studio Community is free to any company whose
| annual revenue is under $1 million USD. It's fully
| functional, unlike the ancient Express versions.
| CyberDildonics wrote:
| Visual Studio is not visual studio code. Also if you have
| a hundred thousand compilation units, it might be time
| for some shared libraries instead of one monolithic
| program.
| shadowgovt wrote:
| Oh I completely agree, but I am a mere senior software
| engineer and I have not yet figured out how to chisel
| past the corporate cruft of the three folks in charge of
| the codebase who believe monorepos are right because
| Google is doing it, therefore it must be the best way to
| do things.
|
| Nevermind that I have some experience with _how_ Google
| did it, and it turns out there 's a lot of ills you can
| solve with a 25,000+-strong engineering force that you
| can't in a smaller org. VSCode at Google never worked for
| me either, but punching a novel symbol into company-wide
| syntax-intelligent internal code search and glancing at
| the first response, which was likely to be the right one
| because it was a Google search engine so had well-tuned
| signals for "things humans care about," always did.
|
| They're not interested in how Google does it, merely that
| they _do_ it so you can 't get fired for making an
| architectural decision that worked for Google. Nor are
| they really interested in solving the tooling issue
| because it works for them; they just grep-and-pray.
| They're very fast at it because it's all they know so
| they've gotten quite good at it (when they have to do it
| at all; often they just know the types because they wrote
| the classes. ;) ).
| fsloth wrote:
| Ouch, my condolences.
| diath wrote:
| With regards to multiple return values in "By-Reference Parameter
| Papercuts", you can make it more ergonomic with initializer list
| and structured bindings without having to use std::make_tuple and
| std::tie: auto get_multiple_values(const bool
| condition) -> std::tuple<bool, int> {
| if (condition) { return {true, 5}; }
| return {false, 0}; } void foo() {
| auto [status, value] = get_multiple_values(true); }
| lenkite wrote:
| One can use structs too: auto foo() {
| struct Result { int a; int b; int c; }; return
| {1,2,3}; } //.... auto [a,b,c] = foo();
| NotCamelCase wrote:
| What's the rationale for auto return type deduction and ->
| declaration at the same time?
| _proofs wrote:
| herb has a talk where he describes its rationale.
|
| it is known as sticky syntax in relation to auto (but
| specifically when the type on the rhs is explicitly declared
| and not abstracted away with a function signature)
|
| it removes narrowing, inference, while keeping benefits of
| auto related to inits etc.
|
| it's a way of telling the compiler we want this type moving
| forward and adheres to the convention of right-to-left
| reading w.r.t. resource allocation semantics C++ programmers
| are often accustomed to.
| Chabsff wrote:
| Consistency. The rationale is: "always use auto as the return
| type, and add a postfix type if inference can't do the job
| for a reason or another."
| ninkendo wrote:
| > add a postfix type if inference can't do the job for a
| reason or another
|
| Ehh... not putting a return type in at all is a bridge to
| far IMO. Be friendly to the casual reader of the code, and
| help them understand what the function returns. (Yes I know
| IDE's can do this for you, but not everyone uses an IDE,
| and not everyone is reading the code in the context of an
| IDE... for instance code review, etc.)
| unkulunkulu wrote:
| Ehh... not using an IDE is a bridge too far IMO. Be
| friendly to the casual writer of the code and help them
| express themselves without having to repeat the obvious.
| (Yes, I know, we write less time than read, but maybe
| that is what is actually wrong with the tools we use?)
|
| Wrote this for myself, I'm a vim user :)
| gumby wrote:
| Most of the time the compiler can deduce it so why bother
| writing the return type?
| sqeaky wrote:
| So every reader should desuce it too?
|
| Sometimes it deduces "wrong". (As in not the type the
| coder was expecting, so really the dev was wrong and
| missed a possible bug)
| gumby wrote:
| Those cases are the ones for which the explicit return
| type was intended. And if the deduced type is
| counterintuitive you could also use the explicit return
| type (or a comment: there are good arguments for either
| choice).
|
| But if your argument is "this makes the reader do extra
| work" then that's an argument against all uses of `auto`.
| Now I do consider reader clarity a legitimate (and
| important) design criterion (and argument in code
| review), but I don't think it is reasonable in this case.
|
| In fact I consider type deduction with auto to be an
| important element of readability: it tells the reader not
| to worry about the type and focus on the logic. Then the
| cases when a type is explicitly specified it tells the
| reader that it's worth paying attention.
| sqeaky wrote:
| Mandating or expecting tools for others is a problem.
| Many code reviews are done in web settings, and that was
| an example you ignored fromt he person you responded.
|
| And you ignored any value that actually specifying the
| type can have.
|
| You also ignored the age old wisdom that code is written
| once and read many times.
| unkulunkulu wrote:
| Why are you attacking me? I just put some motivation for
| myself and maybe someone else to switch to an IDE. Is
| this mandating tools thing a problem where you are
| working? How did that affect you?
| Chabsff wrote:
| Ideally, functions should be clear at the call site
| without a reader having to jump to the declaration to
| understand what's going on, and you don't get the return
| type there in the first place.
| NotCamelCase wrote:
| This looks like the worse of both worlds to me -- more
| typing, less readability and you'd still need to manually
| change the return type, if need be.
| ninkendo wrote:
| Not OP but I prefer trailing return type syntax if I were
| designing a language from scratch... I sometimes wish C++11
| would have added the `func` keyword as an alias for `auto` in
| function declarations.
| ooterness wrote:
| With macros, anything is possible.
| MereInterest wrote:
| This is a stylistic difference, as there are some places
| where the leading return type is invalid, but a trailing
| return type using the -> is valid. For example, an
| immediately invoked lambda expression in which some of the
| returned values require type conversions.
|
| For this reason, some prefer a "auto almost everywhere"
| style, in which you preferentially use trailing return types.
| gumby wrote:
| Trailing return type declaration (-> type) was needed to
| declare the return tyoe of a lambda -- no other way to get
| that info into the grammar.
|
| Then once that was opened some folks felt it would be better
| to write their regular code that way too.
| thecodedmessage wrote:
| I'm just spoiled from being able to return and consume a tuple
| in Rust without writing a standard library function or type
| name _once_ :-) I 'm glad C++ has got it down to one though!
| Now if only people will start using this instead of out
| parameters (unlikely...)
| antoineMoPa wrote:
| For me, it's the fact that there is no standard package manager
| for the language. Finding the right linker/include args is soooo
| not user-friendly. Also, these `-I` and \-l` flags can differ
| across platforms (and so can the installation procedure for these
| libraries). Yesterday, I tried to run an old project of mine
| developed on linux, but this time on a mac. First, the linker
| complained it could not find -lglm, I had to search a bit to find
| out that this is gl math. Then I searched this in homebrew, I
| also looked at different package managers. The low quantity of
| packages available surprised me. The most interesting package
| manager looked like it required python. Can't the community build
| a package manager in their own language? Anyway, at this point I
| gave up for the day.
|
| I love the language overall. Seems like standard & easier
| management of dependencies and compiler flags would help it
| thrive again.
| ho_schi wrote:
| I suggest changing the build tool. Meson improved C and C++ a
| lot:
|
| https://mesonbuild.com/
|
| The dependency declaration and auto-detection is nice. But the
| hidden extra is WrapDB, built-in package management (if
| wanted): https://mesonbuild.com/Wrap-
| dependency-system-manual.html
|
| https://mesonbuild.com/Wrapdb-projects.html
| boris wrote:
| As the name suggests, this wraps the whatever build system
| that the dependency is using rather than replacing it with
| Meson. Say if you depend on Boost and Qt, you will end up
| using both Boost Build and CMake in addition to Meson (most
| likely there will be a couple of more build systems if you
| are also building Boost's and Qt's own dependencies such as
| ICU). This has two major drawbacks:
|
| 1. The build in step-by-step rather than end-to-end. Meaning
| that you first build Boost completely, then Qt, and then your
| application. With an end-to-end build you would build
| everything with a single build system invocation with the
| build system "seeing" the entire build graph. In particular,
| this would allow you to build only what's necessary and
| faster.
|
| 2. If something goes wrong in one of these dependencies, you
| better be prepare to become an expert in whatever build
| system it uses.
|
| If you want a true Cargo-like experience in C++, a better
| option would be build2, which replaces rather than wrapps the
| build system (and, yes, it has Boost and Qt packages):
| https://build2.org
|
| For more details on what an end-to-end build can give you,
| see: https://build2.org/faq.xhtml#why-package-managers
| PaulDavisThe1st wrote:
| You can't have an effective package manager for a compiled
| language unless the package manager is actually a part of your
| own build system.
|
| The example I always use: you want to use libfftw ("Fastest
| Fourier Transform in the West"). But the library can be
| compiled with (at least) two options: use floats or doubles,
| use threads or not. That creates (at least) four possible
| variants of the final library.
|
| The only way to address this (and IIUC, Cargo for Rust does
| this) is to somehow have the pkg manager be a part of your
| build system, so that you end up with a local copy of the
| library, built as required.
| ho_schi wrote:
| https://mesonbuild.com/Wrapdb-projects.html
|
| Meson did that. You can use system packages, define your own
| dependency, use sub-projects (custom build option a, you
| mentioned) or readily available from WrapDB.
| pjc50 wrote:
| > no standard package manager for the language
|
| Kind of an uphill struggle this one, because there's no
| standard _implementation_ of the language, nor is there a
| standard build system. You have to deal with multiple vendors,
| one of whom is Microsoft and many of whom are unwilling to
| change rapidly.
| xcdzvyn wrote:
| Tbqh after figuring out make + pkg-config, it's kind of zen.
| C/C++'s unique dependence on the system's package manager for
| libraries is _weird_ , but I can't say I hate it.
| usrnm wrote:
| I don't know. I switched to go a year ago after 10+ years of C++
| and, if anything, I realized that C++ was not so bad. Not bad at
| all. It's old and overly complicated, but it's also very powerful
| and even beautiful at times. Go is just bad, the runtime is
| great, but it's attached to a slightly upgraded version of C.
| It's not even much safer, I've seen more leaks in this year than
| probably 5 years of C++ before that.
|
| I know, the post is about C++ and Rust, but I'm tired of this
| "C++ is abandonware, just switch to a modern language" narrative.
| jprete wrote:
| I think this is a fair view, but C++ has a lot of flaws. It's
| good enough that it's very hard to justify switching away from
| it, and it will be a good resume language for quite a long
| time, but I would hesitate to start any new project in it.
| thecodedmessage wrote:
| I never recommended Go :-) I'd personally rather program C++
| than Go, so I can see where you're coming from! That said, C++
| is abandonware, switch to a modern language :-) :-)
| fsloth wrote:
| '"C++ is abandonware, just switch to a modern language"
| narrative.'
|
| I think this narrative is still valid. For the love of god, if
| you don't need to use C++ for a greenfield project, don't. I
| say this as a person who _needs_ to write C++ daily.
|
| Otoh, if you _do_ need to use C++, it 's likely there are no
| good alternatives, so unless you are Microsoft, Google or
| Facebook ready to invest few billions to a new language
| ecosystem, the most pragmatic approach is to, indeed, just use
| C++.
| GoblinSlayer wrote:
| How much of C++ ecosystem Qt uses compared to the size of Qt
| itself? Or Chrome?
| Night_Thastus wrote:
| As a C++ dev, I definitely disagree. C++ has a lot of
| advantages, like an enormous pile of easily-usable existing C
| and C++ code that you can hook in easily into any project.
|
| Chances are if there's a problem to be solved, someone has
| solved it in C or C++ and the code is out there already.
|
| It also has a lot of great support in terms of toolchains.
| Almost everything everywhere supports it out of the box, and
| you have your pick of any tools you want.
|
| It also works on fairly simple principles, so anyone with
| experience in programming can work in it without learning a
| completely new way of thinking. [Even if their code won't be
| amazing at first]
| fsloth wrote:
| I must apologize if the below sounds acerbic. I've used C++
| professionally close to two decades and developed a keen
| feeling of everything that is bad in it. (Still need to use
| it though).
|
| In general I agree with Mark Russinovich. Use a garbage
| colleted language, and if you really want a non-gc language
| choose Rust (which I really should learn).
|
| https://twitter.com/markrussinovich/status/1571995117233504
| 2...
|
| There are cases when one should choose C++, but those are
| the exceptions. Graphics, computational geometry and so on
| are strong reasons to use C++ still. But not everyone needs
| that stuff.
|
| For moving strings and numbers around in a stereotypical
| business domain there are much better languages. C#.
| Python. Etc.
|
| "an enormous pile of easily-usable existing C and C++ code
| that you can hook in easily into any project."
|
| A lot of it is to help with the fact that the standard
| library in C++ is anemic.
|
| This _is_ one of the reasons though why one would want to
| use C++. Some libraries exist only in C++, and yes, it 's a
| good reason to use the language.
|
| "It also has a lot of great support in terms of
| toolchains."
|
| CMake? VCPKG? Conan? MSBuild? Meson? Scons? Bazel? Make?
| Xcode? The-android-thingy? How do you mix and match those?
|
| All of those are bloody horrible. And their combinations to
| the second power so. The only good thing in modern times is
| that most open source projects have picked up CMake with a
| fairly standard way of project configuration, which enables
| actually to reuse other's people code with surprising ease.
|
| The toolchains make a horrible language a doubly terrible.
|
| "It also works on fairly simple principles, so anyone with
| experience in programming can work in it without learning a
| completely new way of thinking. [Even if their code won't
| be amazing at first]"
|
| Calling C++ simple is a new one to me. It's an _industrial
| language_ that is not a _total failure_. Yes, people can
| write programs with it. The problem is there are much safer
| and better languages to write general programs, thus
| selecting C++ is giving yourself an intentional handicap in
| term of value created.
|
| As an example of the complexity choosing C++ over something
| like C# gives you -
|
| To what extent is a C++ codebase cross compilable and
| runnable in say MacOS after you develop it in Visual Studio
| on Windows? That's right, you can't tell, the only way to
| verify your standard C++ has the same runtime behaviour is
| to run it on the said platform. And fix all the bugs. So to
| actually write cross platform code, you need to have some
| proficiency in all of the platforms to have any level of
| guarantee that the code actually works in it's intended
| runtime.
|
| Thus, a C++ codebase needs to come with a warning label
| telling every OS and processor it has been tested in. Most
| popular libraries are tested and run in all of the relevant
| platforms so this is not an issue for users. But I'm pretty
| sure the number of platform specific fixes per codebase is
| not trivial to make something work even remotely similarly.
| Night_Thastus wrote:
| >Make? VCPKG? Conan? MSBuild? Meson? Scons? Bazel? Make?
| Xcode? The-android-thingy? How do you mix and match
| those?
|
| Almost everything I've seen is in Cmake, or can be easily
| interacted with it.
|
| But in general, just pick something you like and stick
| with it. Sure, they're not perfect, but this list is
| actually a point I was making - you have a huge array of
| mature solutions out there already.
|
| >Calling C++ simple is a new one to me. It's an
| industrial language that is not a total failure. Yes,
| people can write programs with it. The problem is there
| are much safer and better languages to write general
| programs, thus selecting C++ is giving yourself an
| intentional handicap in term of value created.
|
| C++ is a simple language with complex things you can
| _choose_ to use. If you understand the basic principles
| of loops, variables, functions, arrays, etc, you can
| write in C++ right away. You can layer on greater
| complexity with libraries and the STL, better patterns
| etc as you go, but you can start simple. That 's a great
| benefit to someone learning, IMO.
|
| C++ is as complex as you make it. I prefer to write
| fairly simple C++ personally and only break out the
| harder parts when absolutely needed. For example, I
| really don't like lambdas, so I just don't use them. And
| I can still solve anything I need to without them.
| wiseowise wrote:
| > Almost everything I've seen is in Cmake, or can be
| easily interacted with it. But in general, just pick
| something you like and stick with it. Sure, they're not
| perfect, but this list is actually a point I was making -
| you have a huge array of mature solutions out there
| already.
|
| Installing library is
|
| cargo add X npm install X implementation("X")
|
| Show me how to import library in CMake. And then also
| show me how to import library that doesn't have
| CMakeLists.txt file.
|
| > C++ is a simple language with complex things you can
| choose to use. If you understand the basic principles of
| loops, variables, functions, arrays, etc, you can write
| in C++ right away. You can layer on greater complexity
| with libraries and the STL, better patterns etc as you
| go, but you can start simple. That's a great benefit to
| someone learning, IMO. C++ is as complex as you make it.
| I prefer to write fairly simple C++ personally and only
| break out the harder parts when absolutely needed. For
| example, I really don't like lambdas, so I just don't use
| them. And I can still solve anything I need to without
| them.
|
| Good luck explaining to team that they can only use
| subset of C++. Also good luck when advanced C++ dev
| advocates for feature X and now whole org has to learn
| about X and its drawbacks. Or when the dev leaves and
| rest of team doesn't know how the hell it works.
|
| Sounds to me like you're writing all of this from hobby
| or hobby OSS project perspective. Which is completely
| fine, but doesn't apply to orgs.
| Night_Thastus wrote:
| I'm writing this from the experiencing of maintaining
| large legacy C++ projects as well as developing new ones.
| I only do this for work, not as a hobby, nor anything OS.
|
| >Show me how to import library in CMake. And then also
| show me how to import library that doesn't have
| CMakeLists.txt file.
|
| I'm not sure how this is a gotcha. I'm not that familiar
| with Cargo, but I think the equivalent would just be
| something like:
|
| TARGET_LINK_LIBRARIES(myProgramName Eigen3::Eigen)
|
| in cmake. Not very hard.
|
| Also...why does it matter if there's a cmakelists.txt
| file? How is that a bad thing?
|
| >Good luck explaining to team that they can only use
| subset of C++
|
| You learn as you go, like literally any other language.
| You don't need to understand every single line and
| function call in a program to make changes or add things
| to it. As you come across something you need to modify,
| you learn a bit about the features being used.
|
| Now, if you have a real go-getter on the team who has
| covered the entire project in the most advanced features
| used in the most obscure ways, sure, it's going to suck
| for anyone just starting. But that's a problem again, in
| literally any language. And not a fault of C++, frankly.
| wiseowise wrote:
| > I'm not sure how this is a gotcha. I'm not that
| familiar with Cargo, but I think the equivalent would
| just be something like:
|
| > TARGET_LINK_LIBRARIES(myProgramName Eigen3::Eigen)
|
| Include how the library gets in your build, not how you
| link it.
|
| > Also...why does it matter if there's a cmakelists.txt
| file? How is that a bad thing?
|
| Maybe because it gets dramatically harder than having
| `cargo install x`? Or did they solve it recently where
| any autotools/meson/whatever gets pulled into project
| without any blood sacrifices to pass all compiler flags
| properly?
|
| > You learn as you go, like literally any other language.
| You don't need to understand every single line and
| function call in a program to make changes or add things
| to it. As you come across something you need to modify,
| you learn a bit about the features being used.
|
| How can you make you changes to something you don't
| understand and make sure that it still works? Also, this
| is absolute nightmare from perspective of team and org
| cohesion.
|
| > But that's a problem again, in literally any language.
| And not a fault of C++, frankly.
|
| No, it's not. Aside from maybe Scala, I can't think of
| any mainstream modern programming language where you have
| to actively create your own sublanguage to make it
| bearable.
| Night_Thastus wrote:
| >Include how the library gets in your build, not how you
| link it.
|
| Kind of depends. If you're in a Linux environment or
| something like MSYS, you'd just need the relevant Eigen
| package (in MSYS: mingw-w64-eigen3), which then you can
| link against. You could build it from source instead I
| suppose, and it has its own cmakelists which you just add
| as a subproject if you want to go that route.
|
| This isn't rocket science. Could it be easier? Sure. But
| it's not terrible either.
|
| >How can you make you changes to something you don't
| understand and make sure that it still works? Also, this
| is absolute nightmare from perspective of team and org
| cohesion.
|
| You learn about how _the part you 're modifying_ works.
| Ask for some assistance from the team members. Read the
| docs. Look up anything from libraries/stdlib that you
| don't understand, go into the debugger and watch as the
| state changes. Build the knowledge gradually.
|
| The next thing won't be as difficult. Don't try to take
| in the entire project at once, that's an overload of
| information for any non-trivial project. Again, that's
| true in literally any language.
| wiseowise wrote:
| Everything that you've listed also applies to any modern
| mainstream language.
| Night_Thastus wrote:
| Rust doesn't have those decades worth of libraries and
| tool development baked into it. Nor does any fairly new
| language.
| wiseowise wrote:
| Java has incredible tooling, far more advanced than
| whatever exists in C++ world. If you're looking
| specifically for "fairly new" language then Kotlin is
| your bet. Tooling is almost on par with Java. Can utilize
| ALL of Java ecosystem on JVM. Multiplatform (JVM, JS,
| native).
|
| C#, TS if you're looking outside of JVM.
| stackedinserter wrote:
| Interesting, it's quite the opposite to me. I've been in C++
| programming since TurboVision times (don't miss them), built
| many projects in C++, but Golang feels like fresh air to me, at
| least for server applications.
|
| Probably it's mostly about runtime/libraries than language
| itself.
|
| Aside of embedded applications and hardcore number crunching
| (core part of it) I can't find a single use for C++ in 2023.
| linhns wrote:
| Games come to mind and anything that needs performance.
| BlarfMcFlarf wrote:
| Starting from scratch, Rust is a fine option there, but it
| lacks publicly available platform integrations, or any
| engines as powerful as Unreal. It's to be seen if that
| momentum advantage can be overcome anytime soon.
| pjmlp wrote:
| Yeah, Go is a better C alternative in terms of language space.
|
| If one cares about language design beyond the ideas explored in
| Oberon and Limbo, not so much.
| uxp8u61q wrote:
| Can I use Go to program my STM32 MCU?
| zare_st wrote:
| If you mean Go is closer to C than Rust is to C, I guess
| that's correct. But neither are alternatives to C.
| pjmlp wrote:
| They certainly are, outside the religious UNIX and embedded
| groups that cannot grasp anything beyond C.
| zare_st wrote:
| Then those outside groups should make a software
| foundation that's attractive enough to replace UNIX.
|
| I see Debian today tinkering with two additional kernels
| - FreeBSD and Hurd, and both are written in C.
|
| Until some kernel 100% written in Rust/Go/modern C++
| starts being attractive for OS integration there is
| absolutely no point in claiming it's possible and even a
| better choice.
|
| C has lost a lot of ground since 30 years ago,
| rightfully. User applications with GUI used to be written
| in something like C89. Games too. It's some people that
| just cannot grasp that it and its ecosystem have a huge
| merit over 'alternatives' when it comes to the ground it
| retained and still holds today.
| BlarfMcFlarf wrote:
| Doing a top down rewrite of an OS is an absurd task, so
| regrardless of merit, C is going to retain its place
| there by momentum. If it's going to be replaced at all,
| it will be incrementally, and until recently, the powers
| that be have kept other languages out of that space (and
| for good reason, since multiple languages interacting
| have complexity costs, again regardless of individual
| language merits).
|
| But we have started seeing just a bit of Rust support in
| Linux now...
| lelanthran wrote:
| You keep going on as if C programmers only use it because
| they are not as smart as you, who punts C++ all the time.
|
| I wonder if you are unable to understand that for some
| people and some problems, having fewer footguns is a
| benefit.
| nwallin wrote:
| > Side note: Someone brought up structured bindings in a comment,
| as if this fixed the issue. Structured bindings are a great
| example of the half-way fixes that proponents of modern C++ love
| to cite. Structured bindings help some, but if you think they
| make returning by tuple ergonomic, you're mistaken. You still
| need to write std::pair or std::make_tuple in the function return
| statement.
|
| No you don't. A tuple needs to be declared once. Then everything
| else is sugared. #include <string>
| #include <tuple> using Foo = std::tuple<int,
| std::string, float>; Foo foo(int a, const char* b,
| double c) { return {a,b,c}; }
| Foo bar(long); double baz(long x) {
| const auto [a, b, c] = bar(x); return c; }
|
| godbolt: https://godbolt.org/z/exdsb4hqb
|
| Note that the return part of this (foo()) worked as far back as
| C++11. Only the structured bindings on the receiving side (baz)
| requires C++17.
| thecodedmessage wrote:
| Thanks! It's still not as ergonomic as full first class
| support, but I did have the situation in my head as worse than
| it was. This has been fixed :)
| andsmedeiros wrote:
| I just don't use out parameters and avoid bare references
| altogether, const lvalue and rvalue references express
| idiomatically whether a parameter is to be copied or moved.
| Structured binding makes it trivial to consume returned tuples,
| so I don't find this a big issue.
| thecodedmessage wrote:
| You still have to write boilerplate to return them, though :-(
| But I agree it's better :-) Unfortunately, I'm on C++11 for
| this project, will be on C++03 for others :-(
| meindnoch wrote:
| >There are so many features I miss from Rust, not only the
| obvious safety features, or even primarily those, but also
| features that C++ could easily add, like sum types (called enums
| in Rust), or first-class support for tuples.
|
| Stopped reading here. std::variant and std::tuple.
| thecodedmessage wrote:
| What part of "first-class" don't you understand??
|
| ETA: std::variant is one of the least ergonomic user interfaces
| I've ever seen. std::tuple seems great until you realize that
| most PLs that support tuples just do "(,)"s for them, in
| creating, binding, and naming the type. C++'s versions are just
| unacceptable, and structured bindings only help on the binding
| side.
|
| First-class support for these is important. There's no reason
| they should be in the standard library rather than built into
| the language itself, besides historical mistakes.
| nwallin wrote:
| > std::tuple seems great until you realize that most PLs that
| support tuples just do "(,)"s for them, in creating, binding,
| and naming the type.
|
| This C++ code compiles and does what a casual reader would
| expect it to do: #include <string>
| #include <tuple> using Foo = std::tuple<int,
| std::string, float>; Foo foo(int a, const char*
| b, double c) { return {a,b,c}; }
|
| godbolt: https://godbolt.org/z/Koa4zYT99
|
| I gotta be honest, this interface is exactly what I would
| like a tuple API to look like. I _want_ to declare my tuple
| as a `tuple`, I _want_ to give it a friendly name, and I
| _want_ to explicitly declare the types in the tuple, and I
| want to all of that at compile time. This API is exactly the
| verbosity that I want; I would be unhappy with either more or
| less boilerplate than this.
|
| > First-class support for these is important.
|
| Agree to disagree.
| jprete wrote:
| std::variant is really cumbersome to use.
|
| When people talk about first-class support for tuples,
| std::tuple does not fit that bill.
| gwbas1c wrote:
| > It can be done, but the calls to std::tie and std::make_tuple
| are long-winded and distracting
|
| Edit: It's really important to read criticisms of your favorite
| language. Often, it can help you find a better language for the
| task you're trying to accomplish.
| mempko wrote:
| You don't need to use tie and make_tuple. Another person
| posted a nice example.
| j1elo wrote:
| Back in 2015 I read _Effective Modern C++_ by Scott Meyers [1],
| which is his latest entry in the saga of "Effective C++" books.
| It covers all the new stuff that got into the language with C++11
| and C++14, and shows how modern C++ can be written.
|
| My feeling during the read, and my definite conclusion
| afterwards, is that I didn't read a collection of new nice
| additions to the language, but a list of minefields and new fancy
| ways to crash your program. That there is no chapter which
| doesn't end up being a list of gotchas. Seemingly every new
| feature was added as an extension of the language's reputation of
| being a shotgun that loves your feet. "Oh, now we have lambdas!
| here are the 32 ways you can fail while using them, and the
| language will do nothing to help you prevent".
|
| _Effective Modern C++_ is a very well written book and very
| instructive. Its flaws are none of the book or writer, but of the
| language itself.
|
| [1]: https://www.aristeia.com/books.html
| bowsamic wrote:
| Yeah, Effective Modern C++ has always read like a list of
| warnings. C++ is kind of like Python in that the design of the
| language does not steer you into making good, idiomatic
| decisions. No one is going to guess most of the stuff that is
| taught in that book without reading it first from working with
| the language or reading other people's code, and really a full
| list of such things for C++ could be many hundreds or even
| thousands.
|
| I also agree that the new features seem to embrace and extend
| the "footgun-ness" of C++, rather than attempt to fix it.
| PaulDavisThe1st wrote:
| > the design of the language does not steer you into making
| good, idiomatic decisions.
|
| That's much easier to do when the tasks that the language is
| suitable for are bounded in some way.
|
| There are not many common idioms that are going to be shared
| (beyong libstdc++) between a realtime audio processing
| application and a data visualization backend for the web and
| an embedded system control app and a payroll processing
| backend.
| bowsamic wrote:
| I don't agree. I can think of many languages that obfuscate
| their idioms that have bounded applicability. Obviously I
| already mentioned Python, which is obviously bounded to
| less performant applications (unless you call C code), but
| another one is SQL. For example, Azure SQL is extremely
| slow when using sub queries compared to CTEs, but the
| language does not make this apparent in its design.
|
| An example of a language with a smaller domain which makes
| its idioms obvious through its design is Ruby.
|
| An example of a high-performance language that can be used
| for all those things that makes its idioms obvious through
| its design is Rust. Another would be, imo, C.
|
| > There are not many common idioms that are going to be
| shared (beyong libstdc++) between a realtime audio
| processing application and a data visualization backend for
| the web and an embedded system control app and a payroll
| processing backend.
|
| I also just generally have to disagree with it, but you
| seem to be using a different definition of idiom to me.
| From what you said here, you seem to take idiom to be
| synonymous with "design decision". For me, an idiom is a
| specific semantic construct, possibly associated with
| specific syntax, that achieves a specific basic programming
| task. For example, the idiomatic way to loop with an index
| in Python is to use enumerate.
|
| It's merely the way that most people do the basic things,
| in a way that is actually good to do. C++ is infamous for a
| huge number of people using the language dangerously, to
| the point where there are effectively no idioms outside of
| specialist communities, and to find them out you need to
| read books. A significant amount of the basic design of the
| language needs to be ignored for most purposes.
| PaulDavisThe1st wrote:
| One of the main places I see idioms in other languages is
| in dealing with containers (and there are some very nice
| ones). Python in particular, but others too. Slicing,
| splicing, iterating, mutating, map-reduce etc. etc.
|
| While I wouldn't say no to having such idioms available
| in C++ as language constructs, it is important that C++
| continues to provide the lowest level that it can for
| such tasks (e.g. pointers into arrays or other buffers),
| and probably the level right above that (libstdc++).
|
| Similarly for threads (or more generally, parallel and
| asynchronous programming) - some other languages make
| available some really nice idioms for expressing these
| things, but again it is important for performance and
| control reasons that C++ continues to provide the current
| lowest level of access for this (basically a wrapper
| around pthreads). While things like promises, futures and
| coprocessing are really useful, they are often
| inappropriate for highly performant code.
| bowsamic wrote:
| If rust can do it so well, I see no remaining argument
| about performance and control. It was long believed that
| C++ had to be bad in this way because such languages must
| be. Rust was the counter example that ended this myth
| PaulDavisThe1st wrote:
| That's not clear to me. The examples I've seen from
| anywhere that Rust has to deal with hardware suggest that
| you have to throw out most of the safety guarantees of
| the language, and this applies also to dealing with OS-
| provided abstractions of hardware (like MMU-mapped
| registers and mmap-ed memory regions).
|
| I don't have the impression that Rust's container idioms
| match those of, say, Python, but I may just not know Rust
| well enough.
| bowsamic wrote:
| You're mistaken then, using unsafe does not mean throwing
| away the safety guarantees. This is a common
| misconception though, even among Rust users
| PaulDavisThe1st wrote:
| OK, let me put it differently: you cannot reason about
| safety in those circumstances in the way you can when
| "unsafe" has not been used. And since reasoning about
| safety (or perhaps more accurately, not needing to) is
| one of the raison d'etres for Rust, that's a bit of a
| hit. Not huge, but for those of us close to metal of some
| sort, it's a bit of a hit.
| bowsamic wrote:
| Yes, you can reason about safety in just the same way, as
| long as a safe API is built around the unsafe usage.
| That's why you can have safe OpenGL bindings even though
| the underlying raw C calls are unsafe
|
| E.g. https://github.com/glium/glium
|
| Rust would be useless if you couldn't have safety if you
| had any unsafe at any point. That's the whole point of
| rust: you can build safe interfaces to unsafe actions
| shadowgovt wrote:
| One gap in my knowledge here is how well Rust can take
| advantage of per-architecture optimizations that can only
| be seen in the large.
|
| One of the sources of complexity in the C++ I work with
| is that a lot of it is using templates to try to maximize
| the size of individual expressions. Consider, for
| example, the Eigen library
| (https://eigen.tuxfamily.org/index.php), which gains most
| of its magic in using compile-time template
| specialization to re-group logical operations so that the
| compiler can realize "Oh, this is really looping over
| dozens of memory cells to do the same operation... I
| should compile it using SSE instructions." I haven't seen
| yet whether / how Rust pulls off similar tricks or
| whether doing so in Rust requires a developer to write
| n-ary asm bindings, which would actually make Rust less
| expressive than C++ if the goal is maximizing performance
| with minimum code.
|
| (Of course, the flip side of that is that there's a lot
| of Eigen that's unsafe behavior; hold the library
| _slightly_ wrong, and you 're operating on deallocated
| memory. Oops. ;) ).
| DougBTX wrote:
| Which book would be the equivalent to an Effective Modern
| Python?
| mixedmath wrote:
| Probably _Fluent Python_ comes the closest, I would say.
| bowsamic wrote:
| I'm not aware of one, since Python changes quite a bit more
| quickly than C++.
| sn9 wrote:
| _Effective Python_ probably: https://effectivepython.com/
| raincole wrote:
| No kidding. Effective Modern C++ was what got me to actually
| start learning Rust.
|
| That being said I feel Rust has a lot of paper cuts that slow
| people down too. Perhaps the silver lining is that they are
| more like barricades than minefields.
| PennRobotics wrote:
| Rust would be so much easier for me if it didn't feel like
| every. single. keyword. was different than my daily drivers,
| Python and C---from type names to standard library functions,
| containers to punctuation. Even "void" isn't safe (hehe pun)
| from this keyword purge.
|
| Beginners, count your blessings. You don't need to unlearn
| other languages before learning Rust.
|
| I sincerely believe the only keywords common to Rust and C
| are a few control flow keywords (for, if, while; but not
| switch, goto, or do-while) and "bool"---the latter only
| because of C99 and stdbool.h
| silvestrov wrote:
| readability is so underrated.
|
| I think readability is a major part why java was hugely
| successful: C programmers could read java code and
| immediately understand what the code did and able to make
| minor modifications to the code.
|
| This is very difficult with Rust code. Rust "learned" too
| much from Perl in this regard.
| raincole wrote:
| > C programmers could read java code and immediately
| understand
|
| Uh... maybe? But Rust is more like a replacement to
| C/C++. So a better question is that whether C#/Java
| programmers could read C/C++ code and immediately
| understand those & and *.
| silvestrov wrote:
| No. C existed long time before java, so the natural
| career progression was for C programmers to become java
| programmers.
|
| It is not at all as easy for C programmers to become Rust
| programmers as you need to learn a lot about Rust before
| you are able to understand the Rust code.
| Const-me wrote:
| > whether C#/Java programmers could read C/C++ code and
| immediately understand those & and *.
|
| Just like Rust, C# has an unsafe superset of the
| language. The meaning of all these * in unsafe C# exactly
| matches C.
| tialaramex wrote:
| Do you think so ? Maybe I've been immersed in Rust for
| too long but it doesn't seem difficult to read to me.
|
| Here's Barry Revzin, a C++ programmer, explaining what he
| wants with a Rust example
|
| https://brevzin.github.io/c++/2020/12/01/tag-
| invoke/#this-is...
|
| Now like I said, I'm a Rust programmer, so of course I
| understand PartialEq's definition there, but, is it
| _really_ hard to see what 's going on as a C programmer?
| There's a lot of magic you don't have, you don't have
| traits, or references, or the Self type or the self
| keyword, or really any of the mechanics here, and yet it
| seems pretty obvious what's going on, doesn't it?
|
| I literally don't remember any unpleasant surprises of
| this form when learning Rust. Actually mostly the
| opposite, especially for != I thought, from experience
| with other languages like Java, C++ or Python, OK
| obviously at some point the other shoe drops and they
| show me that I need a deep comparison feature. Nope,
| Rust's comparison operators are for comparing things, it
| isn't used to ask about some surface programmer
| implementation detail like the address of an object in
| memory unless you specifically ask for that. If Goose
| implements PartialEq, so that we can ask if one Goose is
| the same as another Goose, then HashSet<Goose> also
| implements PartialEq, so we can ask if this set of geese
| is the same as another, and HashMap<Goose,String>
| likewise, so we can ask if these two maps from geese to
| strings are mapping the same geese to the same strings.
| fauigerzigerk wrote:
| _> I literally don't remember any unpleasant surprises of
| this form when learning Rust_
|
| I can't say I find Rust's pattern matching rules
| particularly pleasant. The rules are convoluted and
| arbitrary
|
| https://doc.rust-lang.org/stable/reference/patterns.html
|
| Also, it has often been surprising to me how code that
| looks like it's entirely read-only will try to move
| stuff.
|
| E.g, this works: let numbers = [1, 2,
| 3]; for n in numbers {
| println!("{}", n); } for n in
| numbers { println!("{}", n); }
|
| This doesn't work: let numbers2 =
| vec![1, 2, 3]; for n in numbers2 {
| println!("{}", n); } for n in
| numbers2 { println!("{}", n); }
|
| I understand why that is and I know how to fix it, but I
| don't like it. There is a long list of things in Rust
| that I find understandable but also unpleasant. In that
| sense it really is a worthy successor to C++. Smart
| people making unpleasant decisions for good reasons.
| tialaramex wrote:
| I think your mental model is wrong if you thought a
| consuming operation like IntoIterator::into_iter is read
| only.
|
| The reason the first one works is that [T; N] is Copy if
| T is Copy, and i32 is Copy so therefore [i32; 3] is Copy.
| So it's actually consuming _two_ arrays, each of those
| for loops consumes the array to make an iterator, but
| since it 's Copy it just leaves a perfectly good copy of
| the array behind in the variable. The compiler can see
| what we're doing here and won't pointlessly duplicate the
| array (presumably) but that's conceptually what's
| happening.
|
| The second one doesn't work because the Vec<i32> isn't
| Copy, so, we consume it and now it's gone, when we reach
| the second for loop the variable numbers2 is gone
| already.
| fauigerzigerk wrote:
| As I said, I understand what's going on here. I just
| don't like it.
| eddd-ddde wrote:
| Being read only and move semantics are orthogonal, you
| can read and write with or without moving.
|
| So you shouldn't make assumptions whether something will
| be moved or not based on read only preconditions.
| fauigerzigerk wrote:
| Moving out of a variable changes it's state. That's not
| read-only.
| eddd-ddde wrote:
| There is a difference between a variable and a value. The
| value is definitely read only or you would need a mut
| modifier. The variable binding changes in a similar way
| to shadowing it with a new 'let' on the same name.
| fauigerzigerk wrote:
| This would imply that the variable can get its value back
| once the new binding is out of scope. But that is not the
| case as this doesn't compile: let s1 =
| String::from("abc"); { let s2 =
| s1; } println!("{}", s1); //borrow
| of moved value: `s1`
|
| But I do understand what you're getting at. In a sense, a
| move is not a runtime concept at all. The compiler simply
| considers the variable as no longer readable unless and
| until a new value is actually written to it.
| PennRobotics wrote:
| I find Rust extremely unreadable and can detail exactly
| how:
|
| I know ripgrep is written in Rust and works really well
| and "does one thing", so I'll go to its repo (
| https://github.com/BurntSushi/ripgrep ) and read through
| a bit. First, I'm looking for a "src" folder, but that
| does not exist, so right off the bat I am a little
| uncomfortable. Nothing in the root folder looks like it
| would be the source. What are "complete" and "scripts"
| and "pkg" folders? Because those (in that order) would be
| what I check.
|
| "complete" looks like command line completion. The
| "scripts" directory has one file, "copy-examples". "pkg"
| contains folders "brew" and "windows". Still lost...
|
| I thought "crates" was like modules for Python, so I
| think that would only contain dependencies and stay out
| of there.
|
| Finally, I relent and open "build.rs" which I suspect is
| something like "build.ninja" and I can figure out which
| node has source files. Stupid me. "build.rs" IS the
| source file.
|
| Oh. No, actually, it's not all of ripgrep, in fact. It's
| the tip of the iceberg. The source is in
| crates/core/app.rs, and build does manpage compilation,
| registers shell completions, etc.
|
| So, line one. I don't know what the return value
| App<'static, 'static> is. I understand it's an App
| object, and the tick (no idea what it's called; this is
| starting to feel like a fracture mechanics lecture) I
| know has to do with ownership. It's tough to see how
| there are two subtypes in App<> when the assignment of
| app has ten functions that assign attributes. I can
| certainly READ what is being assigned to the App object.
| I wouldn't be able to WRITE any of this so far.
| Unimportant, it's not the meat and potatoes of ripgrep.
|
| Now I'm scrolling, looking for something cool to analyze
| and run across Vec<&'static str>. Okay, I thought tick
| was ownership, but I also thought ampersand was
| ownership-related. Maybe one is mutability? (This is like
| knowing how to play music really well but now learning a
| totally foreign instrument.)
|
| Skimming, it looks like this whole file is the argc/argv
| parser. I'll look for something interesting in main.rs,
| search.rs, and subject.rs (the last because it's an
| unusual name). struct Config {
| strip_dot_prefix: bool, }
|
| Well. I can read that! Next line...
| impl Default for Config { ...
|
| ...not that. It's probably something like a class method.
|
| As I'm reading through, it feels like a LOT of kicking
| the can down the road and verbosity. There's a function
| binary_detection_explicit(self, detection) that just
| assigns detection to self.config.binary_explicit and
| returns self. binary_detection_implicit() does basically
| the same with a different assignment member. getters and
| setters, roadblocking readability since the dawn of
| computer science... (a few lines later, the function
| has_match() returns the value of has_match. ugh. This is
| why I prefer crudely written C to textbook C++.)
|
| I see .unwrap() in a line. This tripped me up during the
| tutorial; still no idea what it does. Sure I can look it
| up, but there are a hundred other terms to learn: unwind,
| map, Result (OH! The two App return types are probably Ok
| and Err ... maybe?), convert, concat, const, continue,
| ...
|
| subject.rs, btw, can probably be written in three lines
| of really dense Python or ten lines of really well-
| written Python with a few other lines of Doxygen.
| Instead, it's about 90 lines of Rust with another 50
| lines of comments.
|
| Finally, I find something noteworthy.
| fn search(...) ... fn iter(...) ...
| for subject in subjects { searched =
| true; let search_result = match
| searcher.search(&subject) { ....
|
| This is all extremely readable and just feels like a
| standard queue in any language. But then there are lines
| like: if let Some(ref mut stats) =
| stats { *stats +=
| search_result.stats().unwrap(); }
|
| I give up. Are you assigning the variable stats to
| itself? by reference but mutable? If Rust doesn't have
| pointers, what is *stats? unwrap() is no longer the most
| confusing part of this.
|
| -----
|
| Postface, I'm originally a mechanical engineer who
| eventually got roped into writing driver software, so C
| is my comfort zone and I don't need anything much more
| complicated than "set bits here, read registers, use a
| 40-year-old communication protocol, handle errors".
|
| There's simply no easy analog between Rust and Python ...
| or Rust and C ... or Rust and SQL ... or Rust and
| PRACTICE ... or Rust and any other language I've learned.
| I understand a lot of the CWE Top 25 software errors are
| mitigated by Rust and it's not just a theoretically
| correct but unusable language, but there hasn't been a
| strong reason to learn it, and the learning curve is made
| steeper by preconceived notions of every keyword.
|
| -----
|
| I forgot to compare with grep.c
|
| Extremely readable. I know right away which part is args,
| where memory allocation happens, where file handling
| occurs, and then the "hard part"---where the magic
| happens---is the last page on my monitor. I can just
| stare at that and mentally deconstruct until pieces fall
| into place... Look up regcomp()? check. Look up
| grep_tree()? check. Read the kernel.org discussion on why
| grep_tree() was written and how it relates to
| ensure_full_index(), which explains some of the other
| variables.
|
| The whole thing sits nicely in a few pages with terse but
| clear comments (unlike this post) and looks familiar even
| though I've never seen the source before.
|
| -----
|
| Last edit. I tried just now to refresh on .unwrap().
| https://doc.rust-lang.org/rust-by-
| example/error/option_unwra...
|
| Only because of the comments did I realize that calling
| drink.unwrap() will panic (throw an error?) if that
| argument is empty. So, unwrap is just the "if (... ==
| nullptr) { return ...; }" of Rust, it seems.
|
| But it's somehow an alternative to .expect() and has its
| own alternatives,
| unwrap_or/unwrap_or_else/unwrap_or_default, and it also
| seems optional. And my time in the rabbit hole is over;
| my children need to go to bed.
| rcxdude wrote:
| Do you expect there to be an easy analog between any two
| random languages? Even two languages as similar as
| javascript and python I would not expect to immediately
| jump in and understand something written in one by just
| kinda guessing as to what something I didn't recognise
| meant, or assuming that just because something is written
| the same as in one language it means the same as in the
| other.
| PennRobotics wrote:
| Yep. Honestly, I don't find it too difficult to parse new
| languages even if they aren't C-like or Python-like (or
| Matlab-like or BASIC-like). I don't know Java, but I can
| read the Falstad circuit simulator source. It's just...
| very recognizable code patterns---almost a dialect of
| C++.
|
| I'm not a database expert, but I became comfortable with
| SQL this past year so I could better understand how my
| company's office software is structured. I can cobble
| together enough Javascript to create an own online sheet
| music book using abcjs, a directory full of ABC files,
| and jquery. I was able to barge through enough C# to
| write a crude 2D game during a game hackathon in college.
|
| In fact, AFTER learning Python, a lot of C became easier
| because I knew HOW a data structure should behave, which
| then influenced how I would create it from structs and
| functions.
|
| However.
|
| I get hung up on Kotlin. Kotlin reminds me a lot of Rust
| in its syntax, and Android has the same habit of renaming
| every single concept.
|
| In general, the more keywords and syntaxes two languages
| have in common, the easier to read. (In SQL's case, I
| think the relative lack of keywords and rigid query
| structure made this a nonissue.)
|
| So, mixed bag.
| inferiorhuman wrote:
| Well there it is. Rust is difficult not because it's
| inherently difficult but because it's not the spitting
| image of the languages you've learned and you're not
| interested learning (which is totally fine). Things like
| putting dependencies (instead of program source) in
| 'modules' seem intuitive not because they're inherently
| intuitive or common but because you've taken the time to
| learn Python.
|
| IMO ripgrep is a poor example of project layout both
| because it does "non-standard" things and because it
| encompasses more than the C-based grep you're comparing
| it to. A simple project will almost always have its
| source in a directory named "src", and a project with
| multiple subprojects (like ripgrep) will typically not
| shove them into a "crates" directory.
|
| Compared to GNU grep, the ripgrep project serves as the
| repository for a bunch of libraries as well as the
| ripgrep binary. So there's already a lot more moving
| parts than the name "ripgrep" might otherwise suggest.
| I don't know Java, but I can read the Falstad circuit
| simulator source.
|
| If you can read Java, I'm surprised impl blocks threw you
| for a loop as the first comparison that comes to mind is
| that with Java interfaces. A quick look at the Falstead
| simulator suggests it's using a pretty small subset of
| the Java language (e.g. no generics, interfaces, or
| exceptions) which would certainly make it seem a lot like
| C. Not all Java is like that.
|
| & and *? Akin to reference and dereference in C, and
| given that you can overload both the comparison to C++
| seems pretty apt.
|
| In any case, for more direct explanations the API
| reference is a better place to look. Two short sentences
| explain what unwrap and explain do, and what the
| differences are.
| diarrhea wrote:
| Not sure I follow. How did you ever read or learn
| anything more than pseudo code or, at best, Python? Any
| language at all will have hurdles like those.
| burntsushi wrote:
| Author of ripgrep here.
|
| ripgrep is way more abstracted than most greps because
| ripgrep splits a whole bunch of its functionality into
| crates. The idea being that others can then re-use the
| reasonably sophisticated infrastructure that ripgrep uses
| to write their own bespoke grep tools. ripgrep internals
| are more like a bare-bones and under-developed grep
| framework. If you go back to the initial version of
| ripgrep (0.2.0), you'll probably find it smaller and
| significantly easier to read. There's a lot less
| abstraction. FWIW, I generally regard my abstraction
| attempts here to be a partial failure. The hit to code
| readability has been quite large. I also fucked up at
| least one abstraction boundary. On the other hand, it has
| enabled people to maintain very small patches to make
| ripgrep work with other regex engines.[1] (And of course,
| ripgrep uses the abstraction to make it work with both
| Rust's regex crate and PCRE2.)
|
| I wouldn't call Rust an easy language to learn. It could
| be easier depending on your background. For example, if
| you have an ML/Haskell and C++ background, then Rust will
| probably introduce very few things you haven't seen
| before (that being the borrow checker). But if your
| background is, say, Python, Java and C, then there are
| going to be oodles of things in Rust that will be novel
| to you. That basic vocabulary will be more difficult to
| acquire.
|
| I'm somewhat surprised you feel confident enough in your
| understanding of Rust to declare you could replace 50
| lines with 2 or 3 lines in Python though. Meh.
|
| > getters and setters, roadblocking readability since the
| dawn of computer science...
|
| They are tools of encapsulation. I don't treat them as
| boiler-plate. I treat them as things that I use when I
| care about encapsulation. And when I don't care about
| encapsulation, I don't use them. My personal style is to
| lean heavily on encapsulation.
|
| [1]: https://sr.ht/~pierrenn/ripgrep/
| BlarfMcFlarf wrote:
| This is really helpful to understanding what you mean. If
| you would be interested, I could go through all that and
| explain each piece. But the normal answer of "spend a few
| hours reading the rust book, it will be faster then
| trying to muddle through" is fine, and misses the point.
|
| You are absolutely right. The foreign-ness you are seeing
| is the ML side of Rust's roots. Rebinding, restructuring,
| small wrapper types, and of course all the functional
| programming bits and bobs that people coming from, say,
| Haskell might see as being quaintly simple, but arcane to
| anyone else.
| thenewwazoo wrote:
| I've been leaning Spanish for about the last six years.
| I'm reasonably effective at it. Not fluent, but I can
| speak and understand it well enough that I often don't
| notice how easy it's gotten for me. A while back, I tried
| reading something written in German and was actually
| surprised at how little I understood. Clearly I can
| understand not-English, why was German so hard? I spent a
| little while trying to parse out each word, guess common
| roots, vaguely remember the little bits of German grammar
| I've absorbed over the years, and so on. It was
| illuminating. I could not just force myself to understand
| German by relying on my success learning Spanish. (This
| is a real story, btw. I really did this.)
|
| This comment reminds me very strongly of myself, trying
| to read German. You know C, why shouldn't you be able to
| understand Rust? But they're not the same thing, and they
| communicate different things in different ways. There are
| concepts that simply do not map directly. Someone could
| _very_ easily write the exact same post from the
| perspective of a Rust programmer starting with C. Where
| is the equivalent to Cargo.toml? What is this Makefile
| thing, and why doesn 't it look like a configuration
| file? Etc. No amount of just forcing yourself to try is
| going to provide clarity unless you already understand
| the idioms and structure at play.
|
| With that said, I have written embedded Rust and it is an
| _amazingly_ freeing experience. Writing C right now feels
| like trying to balance a knife on my finger. With Rust I
| can just get work done. I strongly recommend you spend
| the time to learn it. Even if it doesn 't convince you
| that C's days are numbered, it will make you a better
| programmer by training you to think about safety and
| correctness up front.
| Gibbon1 wrote:
| > Clearly I can understand not-English, why was German so
| hard?
|
| I'm reminded of a Mexican friends mother, she and her
| aunts went to Europe. They loved loved Italy. Partly
| because if an Italian spoke slow and clearly they could
| understand what the person was saying.
|
| My experience with C# for instance was it was really easy
| to pickup. Because snippets of code are generally C like
| and procedural.
|
| Heard the above about said about go. If you know Java and
| JavaScript you probably know go already.
|
| I found python not too hard because I knew perl sort of.
| Mostly enough experience with it to avoid it.
|
| I suspect if you know C++ and a ML language Rust is a
| breath of fresh air. But if you don't it's not. It's
| gross. And very very slow iteration times.
| PennRobotics wrote:
| My mom was a Spanish teacher in a reasonably hispanic
| part of Florida. I'm now a permanent resident of Germany.
| Your example resonates.
|
| -----
|
| I tried Embedded Rust about 4 to 6 years ago and found
| the experience underwhelming, as I was installing a TON
| of packages just to get Blinky and seeming to bypass a
| lot of standard Rust (no_std, no_main, use panic_halt as
| _, everything GPIO is unsafe, etc). The last straw was
| that imported Cargo packages had their absolute path
| somehow hardcoded in the symbol table, so my debugger
| would try to load, like... C:\Users\jacob\stm32-rust-
| thingy\app\solve.rs (and fail, because I'm not jacob and
| don't have his source code)
|
| I'll give it another shot. I'm sure the "many eyes"
| principle (and better/more tutorials in the past few
| years) make the process easier now than then.
| cesarb wrote:
| > I spent a little while trying to parse out each word,
| guess common roots, vaguely remember the little bits of
| German grammar I've absorbed over the years, and so on.
|
| And German has a particularly special trap for "trying to
| parse out each word": trennbare Verben (separable verbs).
| Unless you know enough of the grammar to know when a
| piece of the verb has been unceremoniously punted to the
| end of the sentence, trying to use a dictionary to find
| the meaning of the verb of a sentence can be an exercise
| in futility.
| pjc50 wrote:
| > C programmers could read java code
|
| This isn't some abstract "readability", though, this is
| "how close are your langauges in the evolutionary tree".
| Where ALGOL is the proto-indo-european of quite a lot of
| langauges, but not all.
| mr_00ff00 wrote:
| I feel like this is a bit unfair. Rust takes most of its
| names from C++ or OCaml.
|
| You just are exposed to different languages than what was
| used as the base.
| tialaramex wrote:
| Conveniently we can actually compare:
|
| https://doc.rust-lang.org/reference/keywords.html
| https://en.cppreference.com/w/cpp/keyword
|
| And they're even both provided in (mostly) alphabetical
| order, which makes this easier for humans
|
| Rust doesn't reserve type names as keywords, which seems
| like an eccentric choice in C++ (e.g. wchar_t is a
| _keyword_!) although perhaps given how fraught parsing is
| in C++ they had no choice.
|
| The common keywords are: break, const, continue, else,
| enum, extern, false, for, if, return, static, struct, true,
| union and while.
|
| true and false are just boolean values, although given C++
| like many languages considers "false" to be true, and 0 to
| be false, I guess it's a surprise they bothered making
| these keywords.
|
| const, enum, union, static, and struct are about types and
| values. The choice to have "const" mean "immutable" not
| "constant" in C++ is hilarious, yeah that's going to cause
| wider issues in how your programmers understand software. I
| think C++ enum is rather sad, here's a whole kind of type
| and it's basically abandoned, it's not allowed to have
| features the other types have, for no discernible reason.
| Rust's enum really shows how much opportunity was wasted
| there.
|
| break, continue, else, for, if, return and while are indeed
| control flow keywords, although what they do in Rust varies
| quite a lot from C++. Rust's for is a for-each, it consumes
| an Iterator (literally, it's a syntax sugar for a loop
| which uses IntoInterator::into_iter and breaks when the
| iterator is exhausted) and Rust's break can break-label-
| value, which is a violently different thing than the C++
| break even though the obvious beginner syntax looks
| identical.
|
| try, do and virtual are reserved in Rust but are not
| currently used (in stable Rust) to mean anything, we can
| expect that try is likely to some day be used for a related
| but different purpose to its cousin in C++.
| hardlianotion wrote:
| What's the difference between constant and immutable?
| tialaramex wrote:
| An example of a constant would be a literal, such as
| "Hello, World!" or 4 or false
|
| You can see that not only can't you change these values,
| it doesn't even mean anything to speak about doing so,
| they're not variables which _have_ values, they 're the
| values themselves.
|
| Whereas an example of an immutable variable would be the
| std::vector we're being asked to check the length of in a
| call to size() - this certainly is a variable, somebody
| _else_ can change it, but we must not.
|
| If we name a constant in Rust like { const TIMEOUT: u32 =
| 1234; }, we're not saying we want a variable with this
| name TIMEOUT and then we mustn't change it - instead we
| are giving a name to this arbitrary constant TIMEOUT (and
| it has to be constant, Rust won't let us make constants
| unless they actually are) and then any time we say that
| name, we get the same value, not the same variable, there
| is no variable, the same value, the constant one, as if
| we'd written it here.
|
| So for example the C++ trick where you "cast away" the
| const-ness doesn't make any sense in Rust because those
| aren't immutable variables, we can't even _try_ to make
| them mutable, they 're not variables. It's not Undefined
| Behaviour, it's gibberish, even C++ won't let you write
| false = true; for example, that's just clearly nonsense.
| layer8 wrote:
| "Const" doesn't mean immutable in C++, in my book. It
| means unmodifiable or read-only. Immutable means the
| value won't ever change, whereas unmodifiable means that
| the value can't be modified via that type (but it might
| be modified some other way).
| raincole wrote:
| Compile time vs runtime.
| GolDDranks wrote:
| Constant is determined at compile time. It's constant
| over the every run of the same binary.
|
| Immutable is immutable for some specific span of time. In
| a simple case, like with Python immutable objects, it is
| constructed once, and after that, it never changes. With
| Rust, it's also possible for an object to be immutable
| while a reference to it exists and is passed to some
| function, but after that function call returns and the
| reference ceases existing, immutability ends.
| estebank wrote:
| To add to this, the following is valid:
| fn take_foo(x: Foo) -> Foo { let mut x = x;
| x.field = 0; x }
|
| The ownership semantics ensure that because there's a
| single owner of Foo at all times, it is always safe to
| make its binding mutable. This is different than trying
| to turn a &Foo into a &mut Foo, that's not allowed by
| safe Rust (and an undefined behavior minefield in unsafe
| Rust).
|
| For constants, you can think of them as a "stamp",
| whatever the value within the const gets inlined in the
| usage place in your code, every time. Immutability is
| about whether the value can be changed. To stretch the
| analogy, you can stamp a pattern on paper (const) but
| later doodle over it (mutability).
| layer8 wrote:
| > wchar_t is a _keyword_!
|
| In C, wchar_t is a typedef, which in C++ would cause the
| problem that overloads could non-portably conflict with
| one of the builtin integer types. That's why wchar_t was
| made a fundamental type, and thus a keyword like all the
| other integer types.
| nayuki wrote:
| Void is not a good example for you to point out. Rust's
| interpretation is correct: The unit type () is what most
| functions should return. The void type has no valid values
| at all, which means it cannot be returned. It is other
| languages that are wrong for using the term void. The
| actual void in Rust is called never: https://doc.rust-
| lang.org/std/primitive.never.html .
| saurik wrote:
| > The void type has no valid values at all, which means
| it cannot be returned.
|
| In C/C++, any value can be cast to void, which should be
| sensible as any pointer can decay to a pointer to void.
| Thereby, the Wikipedia definition of the void type even
| says it is like a unit type, and the page for the unit
| type notes 1) the void keyword simulates a unit type and
| 2) that--and I think this is very important, to get into
| the mindset of this term--that the actual unit object
| type in Java is named Void.
|
| It does really really suck that you can't declare a
| variable of type void and that some compilers decided the
| size was 1 for long enough that the size is now undefined
| (instead of 0), as these mistakes lead to a ton of
| ridiculous code duplication in C++ templates. (This would
| be the first thing on my list of things to fix if I were
| allowed to make any arbitrary breaking change to C++.)
|
| But like, it seems very wrong to claim it has no values
| at all: in C++, if you have a function that returns void,
| you can even call another function that returns void and
| use the return keyword oh whatever you consider it to
| have returned. It clearly has some kind of value in many
| contexts--and, despite having a size that is undefined
| (and potentially 1), that value carries no state--so
| there is only one possible value: it is merely the term
| people use for unit in this kind of language.
|
| (To be clear, though: I am not at all claiming that Rust
| is wrong for using () or unit or whatever, as there is a
| ton of history of using such in other safe academic
| languages and it certainly doesn't confuse someone like
| me. I do, though, think that its mission isn't well
| served by not at least trying to look as much like the
| specific languages that need to be replaced--C and
| C++--as possible.)
| KineticLensman wrote:
| > Perhaps the silver lining is that they are more like
| barricades then minefields
|
| As a Rust newby I think they are more like achievements that
| unlock new capabilities.
| moonchrome wrote:
| There's a name for this feeling [1]
|
| [1] https://en.wikipedia.org/wiki/Stockholm_syndrome
| Verdex wrote:
| From your wikipedia link:
|
| "and, in fact, it is a "contested illness" due to doubts
| about the legitimacy of the condition."
|
| AND
|
| "It was noted that in this case, however, the police were
| perceived to have acted with little care for the
| hostages' safety,[6] providing an alternative reason for
| their unwillingness to testify."
|
| Somehow appropriate considering this thread is about how
| someone's bad experience with C++ has driven them into
| learning rust.
| spoiler wrote:
| So learning any new skill is a manifestation of Stockholm
| syndrome?
| linhns wrote:
| I love Rust but it's not the time for it yet, especially with
| that enormous build time. That's the biggest paper cut.
| FpUser wrote:
| >"...they are more like barricades than minefields"
|
| This is a nice one ;)
| npalli wrote:
| Scott Meyers was the go-to reference for "expert" C++ knowledge
| for over twenty years, he retired after his C++14 books came
| out and a mere two years later he couldn't even keep up with
| the language to make technical corrections.
|
| _C++ is a large, intricate language with features that
| interact in complex and subtle ways, and I no longer trust
| myself to keep all the relevant facts in mind. As a result, all
| I can do is thank you for your bug report, because I no longer
| plan to update my books to incorporate technical corrections.
| Lacking the ability to fairly evaluate whether a bug report is
| valid, I think this is the only responsible course of action._
|
| https://scottmeyers.blogspot.com/2018/09/the-errata-evaluati...
| googlryas wrote:
| Heck, even C++ is getting out of hand for Herb Sutter. He
| might say "ISO C++ is the best tool in the world today to
| write the programs I want and need", but then he also says
| "My goal (with cppfront) is to explore whether there's a way
| we can evolve C++ itself to become 10x simpler, safer, and
| more toolable."
|
| https://github.com/hsutter/cppfront
| darknavi wrote:
| As a C++ fan his cppfront talk was excellent. I'd love to
| see this work get wider adoption.
| cassepipe wrote:
| I am really sold on cppfront but I have not had the
| occasion to use it yet.
|
| How usable is it ? Is it closer to a a Proof of concept or
| a finished tool ?
| rewmie wrote:
| > My feeling during the read, and my definite conclusion
| afterwards, is that I didn't read a collection of new nice
| additions to the language, but a list of minefields and new
| fancy ways to crash your program.
|
| I don't think that's a reasonable take on both the book and
| C++11/c++14. `Effective Modern C++` is not an intro tutorial,
| but a book dedicated to trivial and nontrivial gotchas, none of
| which leads your program to crash. Worst case scenario you just
| get a compiler error of your own doing, and that's it. I mean,
| the book covers stuff like the importance of using nullptr
| instead of NULL, why braced initialization is nice, why and how
| smart pointers should be used to implement a pimpl, etc. This
| is hardly mine field territory, and it makes absolutely no
| sense at all to use these tidbits of all things to justify
| switching to an entirely new programming language.
| limaoscarjuliet wrote:
| Agreed 100% The last time C++ "made sense" to me was 1998
| reading and practicing Bjarne Strostrup's C++ book. It was
| better C then and a lot of these improvements made sense.
| nayuki wrote:
| I agree with the blog post, also having learned C++ followed by
| Rust. Only in the context of saner modern languages like Rust did
| I see C++'s footguns in retrospect.
|
| Probably my top footgun for C++ is implicit copy construction by
| default. Every class gets a copy constructor by default unless it
| opts out. When a copy constructor exists, it can be used
| implicitly and silently for casting and other contexts.
| Implicitly copying big objects like std::string or std::vector
| can be a huge, silent waste of time - whereas in Rust you must
| explicitly call `.clone()`.
|
| > const is not the default
|
| Agreed with this footgun. The old C and C++ ways are to be
| permissive by default, to be strict after adding more words.
|
| As another example, top-level variables and functions are
| exported by default unless prefixed with `static`. Whereas in
| Java, Rust, etc., you need `public`/`pub` to export, nothing to
| keep private.
|
| Another huge footgun is the collection of all the undefined
| behaviors from integer overflow to null dereferencing to creating
| out-of-bounds pointers to buffer overflows.
| 1n3nt0r wrote:
| I've used C++ from its inception (when it was cfront C++ -> C
| translator) to modern C++, not to mention many other languages
| over the years. Totally agree with the author that C++ manages to
| accumulate many bad decisions over time, leaving a legacy of
| overly complex or under-powered features.
|
| I suspect a certain laziness in not tackling some of the harder
| problems in the compiler, for example: type inference, improving
| the grammar to disambiguate new keywords from variables (for
| example co_yield). Many features could have been improved with
| more effort and willingness to tackle hard problems.
|
| Perhaps if Sean Baxter's Circle (C++ language extensions) gains
| traction, there will be hope to modernize C++ syntax and
| features.
| [deleted]
| RcouF1uZ4gsC wrote:
| > In C++11, there is no ergonomic way to do a lambda capture by
| move - which is usually how I want to capture variables into a
| closure
|
| > It is unergonomic to return multiple values by tuple in C++. It
| can be done, but the calls to std::tie and std::make_tuple are
| long-winded and distracting, not to mention that you'll be
| writing unidiomatically, which is always bad for people who are
| reading and debugging your code.
|
| C++14 allows you to move capture in lambdas. C++17 has structured
| bindings that help with returning multiple values.
|
| If you are claiming to an expert in C++ talking about paper cuts,
| at least be aware of things that have happened in C++ in the last
| decade.
| fsloth wrote:
| Let the holy wars begin.
|
| "Lambda capture" sounds like "my favourite way to juggle
| chainsaws".
|
| The correct answer to "I don't like lambda syntax..." is not
| "learn lambda syntax" but "do not use lambdas unless you really
| need them, and then think twice".
|
| Honestly, C++ is a massive footgun. Write the most simple,
| inelegant C++ you possibly can. The coming generations who need
| to maintain your code for the next 200 years will be thankfull
| for it.
|
| Don't pretend C++ is something more elegant like Ocaml that the
| compiler sugars you into believing. It's not! It's a horrible
| pile of ... things ... piled .. on top of .. things .. on top
| of ...(etc).
|
| And when something goes sideways at any point in that pile of
| templated tower of abstractions, the compiler will gift you
| with an outpout that is closer to a mix of toenail clippings
| and dog poo than an output from an industrial level programming
| tool. After which you need a heavy drink and wish there was a
| better language out there. And then you realize there isn't,
| for the specific task, and you adjust by reducing the
| complexity of the abstractions you use and prefer to have a
| codebase that has more lines of code and fever chances of
| irritating the compiler.
| gpderetta wrote:
| I don't care if you do not like the lambda syntax (there is
| plenty of syntax of C++ that I dislike), but lambdas are now
| a pretty core feature of the language, so you better learn it
| or switch to another language.
| fsloth wrote:
| Strong disagree.
|
| It's not about the syntax, it's about understanding the
| resource management model lambdas add on top of the
| existing mess.
|
| There is no good reason to use lambdas except
| parametrization of stl algorithms.
|
| Don't use them as part of api design. The only thing you
| gain is one more level of complexity on reasoning resource
| management.
|
| Yes, to be specific, one should know how they work, and
| _then_ not use them.
|
| This is in the context of C++ being a minefield of
| practically infinite complexity, in which the only way to
| survive is to pick the language subset you know you are
| able to handle, and stick with it.
|
| Of course, every party picks their own subset :)
| AnimalMuppet wrote:
| > There is no good reason to use lambdas except
| parametrization of stl algorithms.
|
| IIRC, there are usually several alternate ways to
| parameterize STL algorithms. If lambdas don't add enough
| value to be worth the additional complexity in other
| places, then they don't as STL arguments either.
| fluoridation wrote:
| Would you mind being a little less vague about what's so
| bad about lambdas?
| fsloth wrote:
| Lambda-the-cs-concept is ofc beautiful.
|
| Lambda-the-c++-language-feature is not. The purpose of
| programming languages in an industrial context is to make
| implementations of programs simple. When they utilize
| complex abstractions, the abstraction should simplify
| overall architecture. The way to measure the
| 'simplification' is how much reasoning a programmer needs
| to do to understand what their code does in the context
| of the language constraints and runtime.
|
| In the context of C++ this includes runtime memory use
| and execution speed. The latter requirement means C++
| code must be such that it's amenable to performance
| analysis and when hotspots arise, one should have an
| obvious strategy how to continue.
|
| C++ Lambdas make this reasoning more complex (in my
| experience).
|
| So the main problem is the added complexity to reasoning
| about runtime behaviour, resource use and performance.
|
| And this is not complexity that would add value by
| removing that complexity from some other area of the
| program.
|
| Lambdas in C++ start by looking cute and innocent. Then,
| when the first problems arise, you realize that by using
| a lambda instead of just an in-place class to capture the
| context, which you can reason using the same bysantine
| set of rules, you actually need to grok a whole new set
| of rules on top of that:
| https://en.cppreference.com/w/cpp/language/lambda
|
| That's a huge mental cost in general what is a saving of
| few lines of code. Hence, don't use lambdas in api
| design.
|
| The only way I guess to realize why the lambdas are in
| such bad taste is to use a programming language where
| they are part of the core language syntax, like python,
| scheme, F#... where you can use them without each time
| double checking that you are not accidentally shooting
| your foot off.
| fluoridation wrote:
| >Then, when the first problems arise, you realize that by
| using a lambda instead of just an in-place class to
| capture the context, which you can reason using the same
| bysantine set of rules, you actually need to grok a whole
| new set of rules on top of that
|
| No, I don't agree at all. Unless the callee accepts an
| std::function, passing a lambda is exactly equivalent to
| passing an ad hoc functor. There's no problem you'll run
| into with one that you wouldn't have run into with the
| other.
| gpderetta wrote:
| Lambdas are just very thin sugar over local classes. I'm
| not sure what do you find so complex.
| fsloth wrote:
| Exactly, but using a different set of syntax, plus a new
| ruleset of capture semantics. The capture syntax
| especially is a minefield. And are the runtime guarantees
| _exactly_ the same as that of a local class instance?
|
| The question is - what does this extra complexity buy us?
| Is it worth it?
| fluoridation wrote:
| >The capture syntax especially is a minefield.
|
| Functors are no easier to use. Either you initialize
| captured values through a constructor or by manually
| setting each member. In both cases you have to name the
| same values several times and ensure that you're doing it
| correctly. With lambdas, if capture by value or by
| reference is enough for everything you need, the code is
| _much_ more succinct and readable. It seriously reduces
| useless, error-prone boilerplate.
|
| >And are the runtime guarantees exactly the same as that
| of a local class instance?
|
| Yes.
|
| >The question is - what does this extra complexity buy
| us? Is it worth it?
|
| It buys us more readable and straightforward code. Yeah,
| I'd say it's worth it. I haven't written a functor in
| years.
| thecodedmessage wrote:
| I said "In C++11" because I am aware that it has been fixed
| later. But I'm stuck in C++11 for platform reasons and so I get
| to complain about its problems too. But of course, it is
| because I am aware that this has been fixed -- crappily -- that
| I qualified it. I'll add more qualifications for you :-)
|
| And I have now addressed structured bindings in the article
| itself for what they are: a halfway solution, unacceptable to
| anyone used to real tuples.
| hardware2win wrote:
| >C++14 allows you to move capture in lambdas.
|
| Your quote says cpp11 and youre arguing with 14? Wtf?
| leni536 wrote:
| The limitations of C++11 shouldn't really be relevant today.
| [deleted]
| Night_Thastus wrote:
| Hahahaha. Oh that's a good one.
|
| Source: Someone who was, until recently, limited to C++03.
| Luckily we're up to 17 now, but occasionally 11 limitations
| creep in.
| thecodedmessage wrote:
| Author of the blog post here. I am limited to C++11 for
| this, and will be limited to C++03 for some related
| projects. I did say C++11 in that comment, as I am of
| course _aware_ that C++ has "fixed" that issue, but I'm
| still entitled to my gripes. I find it odd that someone
| claimed I was not aware the issue has been fixed in later
| versions, when I specifically said a version. People seem
| to be very motivated to assume I'm wrong about C++...
| because otherwise they'd have to admit that their
| favorite language has flaws.
|
| In any case, I revised that section to explain how even
| the "fixed" version in C++14 is still a paper-cut, and
| make the section hopefully flow a little better.
|
| ETA: I replied to the right comment. I'm agreeing with
| you :-)
| Night_Thastus wrote:
| Did you reply to the wrong comment?
|
| I was just saying that being stuck on older versions is
| more common that most people think.
| FpUser wrote:
| All valid points. I agree that C++ as a whole is insanely big and
| complex and I can't even dream nor that I want to know about
| every nook and cranny.
|
| None of this however precludes me for writing well behaved
| software using subset of modern C++ that I actually need. The
| good thing is that when I need some esoteric feature that will
| help me to to this and that - it is always there and is quickly
| searchable thanks the the Internet.
|
| I prefer wide array of C++ choices especially when it comes to
| supporting various paradigms and techniques to a stricter set in
| Rust for example.
|
| I do see that real C++ experts (I am not the one) can get
| frustrated with the language but I think we have different goals
| in general. Being a programmer I do run my own business and I
| believe ROI wise C++ is more beneficial for my situation (I do
| use multiple languages when needed / requested by clients).
| Night_Thastus wrote:
| Exactly. Just use what you need. Only use the big hammers when
| absolutely needed. That's the power of C++ IMO. Lots of big
| hammers out there, but lots of smaller ones for when you don't!
| kajaktum wrote:
| I started writing C++ to do some JSON at work and it is
| absolutely horrible piece of shit language (even with nlohmann's
| and simdjson). I cannot believe people live like this.
|
| between figuring out CMake scripts, std::optional being basically
| useless. I never feel done writing code because I don't feel like
| I have:
|
| 1. Checked all the exceptions
|
| 2. Checked all the places where my std::optional instance is null
| (the checks doesn't propagate their information)
|
| 3. Checked that I am not doing any implicit conversion.
|
| 4. Really understand what happens at overflow?
|
| 5. Really understand if my code is even UB free?
|
| 6. Debugging is a mess, I can't step through code because the
| smartass compiler removes an entire segment of code even in debug
| mode.
|
| 7. I wish this garbage is written in C instead. At least its
| honest that its primitive and sinful, unlike this LARPING high
| level language.
|
| Only 2 things need to be true for this language to be permanently
| horrible: Hyrum's Law and backward compability. If it is possible
| to write bad code, then there will be bad code. Simple as.
| Doesn't matter how many guidelines you write or how many times
| you need to "teach" programmers or how many times you said people
| just need to be "better mkayyy?"
| jalino23 wrote:
| i was thinking of learning cpp for webgpu, this is discouraging
| adwn wrote:
| Consider learning Rust instead, and use wgpu [1].
|
| [1] https://github.com/gfx-rs/wgpu/
| kajaktum wrote:
| You can do it using whatever you want. I hope I don't
| discourage you from discovering C++. You might enjoy it, you
| might not, who cares. Go do it and make up your own opinion.
| pjc50 wrote:
| Good. C++ is discouraging. It combines huge complexity with
| readily available footguns, and the prevailing attitude is
| that all developers must be able to write perfect code with a
| full understanding of the language. Otherwise any security
| holes or runtime crashes are their fault.
| fsloth wrote:
| You are absolutely correct.
|
| Computer graphics, though, is one of the few sane reasons
| left to learn C++.
| fsloth wrote:
| "I started writing C++ to do some JSON at work and it is
| absolutely horrible piece of shit language"
|
| Congratulations! That is the correct answer. Welcome to the
| language.
|
| If you don't need to use C++, don't.
|
| You need C++ for stuff like computer graphics, computational
| geometry, plausibly scientific computing, games and so on.
|
| "6. Debugging is a mess, I can't step through code because the
| smartass compiler removes an entire segment of code even in
| debug mode."
|
| Visual Studio is brilliant compared to anything else. If you
| really need to use C++, I would warmly suggest it.
___________________________________________________________________
(page generated 2023-08-28 23:02 UTC)