• carom 4 days ago

    I am so shocked at how many people use `auto` in C++. I can not think of a worse thing to do to your code in terms of readability and future maintainability. Maybe it is OK if you use an IDE to identify types for you but I still hate it. I am trying to learn a new library right now with light documentation which means reading the code, and between typedefs, auto, and technical debt, it is a tedious exercise to figure out something's type, to go look up its function, to see what type that is returning.

    • jcelerier 4 days ago

      I have never seen anyone come back to typing types everywhere after using auto for more than a couple months.

      Use types when they are needed and use the tools at your disposal (IDEs BT every text editor has clang language server integration nowadays)

      > with light documentation which means reading the code,

      You have to read the code anyways, documentation is impossible to trust. There isn't one big library for which I didn't have to go read the code at some point. Two weeks ago I had to go read the internals of msvcrt, Microsoft's C runtime, to understand undocumented features of process setup on windows. I had to go read standard library code thousands of times, and let's not talk about UI libraries.

      • coffeeaddict1 4 days ago

        > Use types when they are needed and use the tools at your disposal (IDEs BT every text editor has clang language server integration nowadays)

        While I agree that auto is helpful, the amount of times I had to wait for clangd (or whatever the IDE is using) to parse a .cpp file and deduce the underlying type is frustrating. It happens too often with every IDE (Qt Creator, CLion, VS Studio, VS Code, etc...) I've tried whenever I'm programming with a non-desktop machine that's not super beefy.

        Plus I often use Github to search for code when I'm trying out a new lib so having the type spelled out is extremely helpful.

        • menaerus 3 days ago

          Plus assuming that your codebase is clangd parseable. Many aren't out of the box.

          Plus assuming that you're not reading/modifying code on a (remote) machine where you don't have access to IDEs but simple editors only.

          Otherwise, I also find auto helpful but I use it sparingly, mostly where type is obvious, e.g. can be easily deducted from the local scope.

          • cma 3 days ago

            One approach is use auto while coding, auto convert to full types when finalizing/commiting except where they hurt readability.

        • asveikau 4 days ago

          There's so much redundancy built into the language if you don't. Imagine:

              std::shared_ptr<T> p = std::make_shared<T>();
          
          Then replace T with a very long type. And that's not the most verbose example, just an early one that popped into mind.

          Then you have lambdas. Imagine assigning a lambda into a stack variable without auto, also keeping in mind that std::function adds overhead.

          • another2another 2 days ago

            Lambdas I would agree with and iterators, but in many other situations, e.g. templated collections it's easy enough to make a descriptive typedef.

            And... I have seen this in the wild: 'auto isFalse = true;'

            • secondcoming 4 days ago

              That example isn't what OP is talking about, because it's obvious what the type of p is because it's on the same line:

                  auto p = std::make_shared<T>();
              
              whereas the following isn't clear and isn't necessarily correct without looking up what the return type of foo() actually is:

                  auto p = foo();
              • asveikau 4 days ago

                I'll agree that your second example is less readable than the first..

                This could be mitigated with the name of foo() being more descriptive.

                If the return type is particularly wordy, auto could still be appropriate.

                • unleaded 4 days ago

                  > This could be mitigated with the name of foo() being more descriptive.

                  welcome back Hungarian notation

                  • jeremyjh 4 days ago

                    auto conn = createConnection();

                    What does this have to do with hungarian notation?

                    • powercf 4 days ago

                      Alone this looks like a reasonable use of auto. In a real codebase, there may be two (or twenty) different connection-like things, multiple of which may be reasonably to call in this context.

                      The "Hungarian notation" comment is correct - it's not strictly Hungarian notation, but annotating function (or variable) names when the language has a type system representing this same information is the same idea with the same problems as Hungarian notation.

                      • pests 4 days ago

                        You’re thinking of it wrong.

                        This works better:

                        auto uasStudents = getClassList()

                        In this case, “uas” prefix standing for an unsafe array of strings.

                        Then say you validate the list

                        auto sasStudents = validate(uasStudents)

                        (Now it’s a safe array of students!)

                        • dullcrisp 4 days ago

                          I feel like I’m missing a joke.

                      • asveikau 4 days ago

                        lpwszThanks.

                        In seriousness, no, that's not what I'm suggesting, and I find it an unusual thing to read from my comment. I'm saying a descriptive name for foo() can give you a hint about what the type is, even if it doesn't literally and directly tell you what the type is.

                    • shaklee3 4 days ago

                      this is required for writing generic code when the function may return different types

                  • JTyQZSnP3cQGa8B 4 days ago

                    The auto keyword should not go in a public API, but internally it's very useful especially when you create objects like `auto ob = make_unique<VeryLongClassName>(...);` or any other kind of function call where the type is obvious and would be identical on both sides of an assignment.

                    As for your particular issue, using an IDE is essential, and the typedef keyword is almost obsolete, so I guess you stumbled upon a strange project. I would be curious to know what it is if it's open-source.

                    • carom 4 days ago

                      It is Slang. A very cool project and it only got its public release relatively recently, so some sins are forgiven but there are so many typedefs.

                          typedef struct ShaderReflection ProgramLayout;
                          typedef enum SlangReflectionGenericArgType GenericArgType;
                      
                      https://github.com/shader-slang/slang/blob/master/include/sl...
                      • JTyQZSnP3cQGa8B 4 days ago

                        It looks like C++98 to me: no `pragma once`, `typedef uint32_t SlangUInt32` seems strange, `typedef bool SlangBool` is definitely useless. The auto keyword is the least of my problems here.

                        > years of collaboration between researchers at NVIDIA, Carnegie Mellon University, Stanford, MIT, UCSD and the University of Washington

                        Now I understand why, it's the kind of project that you can't upgrade easily.

                        • flohofwoe 4 days ago

                          `#pragma once` is not a panacea, it can still lead to double inclusion in scenarios where the same include file is accessible under different path names (granted, that's a very esoteric scenario). Besides, `#pragma once` is neither part of the C nor C++ standard. It's just a common convention between compiler vendors - so technically any code that uses pragme once as the only include guard is not standard C or standard C++ (but tbf, hardly any real-world code is fully standard compliant).

                          Typedef'ing common types to your own type names is absolutely fine as long as it is unlikely to collide with the typedefs of other libraries in the same project.

                          • vitus 4 days ago

                            > Typedef'ing common types to your own type names is absolutely fine as long as it is unlikely to collide with the typedefs of other libraries in the same project.

                            I read the parent post as indicating that "this is C++; we spell this as `using Foo = Bar;` now." Type aliases (or namespace aliases, or using-declarations) are not dead, but the typedef keyword in C++ is largely only retained for backwards compatibility.

                            The core issue here is that type aliases add a layer of indirection. That can be useful if the user shouldn't need to know the implementation details and can interact with said type purely through the API -- do I care if a returned Handle is a pointer, an int, or some weird custom class? Everyone is used to file descriptors being ints, but you aren't going to do math on them.

                            • elteto 4 days ago

                              #pragma once is a de-facto standard now, and if it’s not in the actual standard then that says more about the failings of the standard writers than anything else.

                              And there’s absolutely no reason to typedef _standard_ int types anymore. Not in C, and definitely not in C++. That’s just crusty old practices. Maybe if you want to have nice short types like u8, i8, etc, I can understand that. But SlangUint32 is just ugly.

                              • bluGill 4 days ago

                                Pragma once isn't in the standard because there are cases where it doesn't work and to standardize it means making the standard significantly longer to catorgize when the compiler is allowed to not work. I've been in discussions and they all conclude it is not worth the effort

                              • maccard 4 days ago

                                Pragma once is widely enough accepted that anyone who argues against its use for that purpose better either be able to tell me the compilers it doesn’t work on, or I’m going to assume they’re being pedantic for the hell of it.

                                And honestly, anyone who relies on the scenarios Pragma once fails in (Compiling off network shared and symlinks) should really fix those monstrous issues instead. The places Pragma once trips up in are likely to be issues for detecting modifications in incremental builds anyway.

                                • throw16180339 4 days ago

                                  There used to be a couple holdouts, but all major C++ compilers have supported it for years (https://en.wikipedia.org/wiki/Pragma_once).

                                  • bluGill 4 days ago

                                    Prarma once works in the vast majority of cases. However there are some rare ones where it fails. Every attempt to fix those last ones breaks some other rare case or profilings shows significant compile time increases.

                                    use pragma once where it works in internal code but never in headers you ship to someone else is a simple rule that should work well enough.

                                    • maccard 4 days ago

                                      > However there are some rare ones where it fails.

                                      As I said in my previous comment, those cases are very very often cases where the compialtion model is broken, and it's held together by luck.

                                      > Every attempt to fix those last ones breaks some other rare case

                                      My experience (and I have experiences of this) have been that the cases where pragma once fails, other tools (source control, built tools) cause "random" problems that usually are hand waved away with "oh that problem, just run this other makefile target that someone has put together to clear that file and rebuild".

                                      > or profilings shows significant compile time increases.

                                      Again, my experience here has been that the compile time change is usually a result of a broken project model, and that there are other gotchas like "oh you can only include files a.h and c.h but if you include b.h then you'll break the internal build tool". Also, that taking the hit to make your build correct unlocks optimisations that weren't possible before.

                                      Also, the projects that have these kinds of warts are usually allergic to doing anything new whatsoever, making any changes or improvements, upgrading compilers and libraries. I suspect using C++17 is enough to scare them off in many cases.

                                      If it's good enough for QT or LLVM, it's good enough for me.

                                      • bluGill 4 days ago

                                        It isn't luck - I know exactly what I did to my package manage to get that file installed into two different locatian. I know exactly which -I options I passed to the compiler causes that one file to be found in different locations depending on quotes or brackets to be used. And it works great if I don't use pragma.

                                        i also know why I had to do that aweful abuse to what anyone sane would call wholesome. I don't like it but there are other things going on and I don't want to talk about it anymore.

                                  • ogoffart 4 days ago

                                    I've been using #pragma once in my C++ libraries for a decade and nobody ever reported any problem with that. I did get bug report about using perfectly standard C++ features that were not properly implemented in some compilers.

                                    > the same include file is accessible under different path names (granted, that's a very esoteric scenario)

                                    And most likely a build system problem anyway if, say, different versions of the same library get included in your build.

                                    • bluGill 4 days ago

                                      I use it and ran into issuses when I put a file into two different locations using my package manager. The reason I wanted a file in two different locations is something I don't want to talk about.

                              • cjfd 4 days ago

                                I agree that the auto keyword should be used sparingly. Things you mention like the output of make_unique and make_shared are a good exception since it is very clear what the resulting type is. Also, one might use auto to store a lambda in a local variable because it does not have a type that you can type.

                                • undefined 4 days ago
                                  [deleted]
                                • MathMonkeyMan 4 days ago

                                  I write my code with the assumption that the reader does _not_ have access to a "smart" IDE.

                                  I use `auto` when the type is obvious or doesn't really matter, and I seldom create aliases for types.

                                  I feel like having verbose type names at function boundaries and using `auto` for dependent types is the sweet spot. I'll often avoid `auto` when referring to a class data member, so the reader doesn't have to refer to the definition.

                                      void foo(const std::multimap<double, Order>& sells) {
                                          for (const auto& [price, order] : sells) {
                                              // ...
                                          }
                                      }
                                  
                                  but also

                                      void foo(const OrderBook& book) {
                                          const std::multimap<double, Order>& sells = book.sells;
                                          for (const auto& [price, order] : sells) {
                                              // ...
                                          }
                                      }
                                  
                                  `auto` is convenient for iterators. Which of the following is better?

                                      auto iter = sells.begin();
                                      std::multimap<double, Order>::const_iterator iter = sells.begin();
                                  • Koshkin 4 days ago

                                    Off-topic, but just wanted to note that using floating-point numbers as keys may be generally a bad idea (unless you use a custom comparator that takes into account the error that can accumulate during calculations).

                                    • mgaunard 4 days ago

                                      especially for an order book...

                                  • Too 4 days ago

                                    Every other language does that by default with "var", "let", or in some languages nothing at all. Within functions it doesn't matter that much and using an IDE takes care of quick lookups anyway.

                                    • maccard 4 days ago

                                      Even for the non ide folks - vim emacs and vs code all have excellent support for that.

                                      • ranger_danger 4 days ago

                                        How does vim support this? I thought you had to use custom scripts/extensions to do it?

                                        • maccard 4 days ago

                                          Sorry I wasn’t clear - all those editors have simple (ish) plugins that support it

                                      • dgfitz 4 days ago

                                        Wasn’t typescript created to fix this problem for JS?

                                        • jeremyjh 4 days ago

                                          Using `let` does not make the expression un-typed in Typescript. It means the type is inferred, and you'll get type warnings if you use it where a different type is expected.

                                      • ninkendo 4 days ago

                                        There’s a lot of arguments here where people are saying basically, “auto is bad because you can …” it “auto is great because you can …”, as if the two are mutually exclusive or something.

                                        It’s like saying “knives are bad because you can kill someone” vs “knives are good because they can help make food”… nobody thinks of knives as being an exclusively good or exclusively bad thing; we all understand that context is key, and without context it’s meaningless.

                                        Instead I feel it would be a lot more illuminating if the discussion centered around rules of thumb… which contexts auto is good, vs when it’s bad. There’s probably no complete list, but a few heuristics would be great.

                                        My 2¢:

                                        Explicit type declaration is a form of documentation, used to tell the casual reader (ie. Often in a web browser, code review, or someone seeing it copy/pasted as a snippet[0]) the meaning of a piece of code. It’s even better than comments: it’s guaranteed not to be a lie, or the code wouldn’t compile.

                                        I’ve seen this all the time working in Rust, Swift, typescript, etc… sometimes an expression is super complicated, and the type checker can infer the type just fine, and my IDE even shows the type in an inlay… but I still worry that if these weren’t available, the expression would look super confusing to a reader. So I make the type explicit to aid in overall readability.

                                        When to do this or not is a judgement call… different people will come to different conclusions. But it’s like any other form of line-level documentation. Sometimes the code is self explanatory, and sometimes it’s not. But be kind to the casual reader and use explicit types when it’s very non-obvious what the type would be.

                                        [0] ie. Anyone without immediate access to an IDE or something else that would show the type.

                                        • ranger_danger 4 days ago

                                          > we all understand that context is key

                                          Unfortunately I think this either this isn't actually the case for many people, or too often they just never even stop to consider that other perspectives might be possible, better or even more common than their own.

                                          In chatting with technical people online for the last 30 years, the biggest issue I have always had is their attitude. IRC seems the worst for it but every platform has this problem in my experience.

                                          God complexes visible from space run rampant, people always speaking in absolutes and seeing things as black and white, complete lack of empathy and humility etc.

                                          I think most arguments in the world, and even other things like crime, might actually just stem from people's inability to communicate with each other effectively.

                                        • nly 4 days ago

                                          It's not 1993. IDEs tell you the type if you hover over the auto. Or control and click takes you to the type definition.

                                          You have to weigh up the cost of going through the code and changing all the type declarations

                                              auto x = foo();
                                          
                                          If you change the return type of foo here you don't have to change 300 call sites. Personally i'd rather change it in one place than 300.
                                          • ninkendo 4 days ago

                                            What about code reviewers? Show me a code review system that lets you hover over the value to see the type… none of the ones I’ve used can do it.

                                            For that matter anyone reading the code from a web browser in any other context.

                                            • dgfitz 4 days ago

                                              Fwiw, I agree. I also pull down the branch under review in parallel to the web code review. You’d (probably) not be surprised by the number of times I’ve done this and the code doesn’t even build.

                                              • ogoffart 4 days ago

                                                Even without auto you have the problem.

                                                    return foo().bar();
                                                
                                                No `auto` and you still don't know the return type of foo. And knowing the type might not be the only reason you'd want an IDE anyway. What is `foo()` doing? I want to be able to easily jump to the definition of that function to verify that the assumption taken by the calling function are correct.
                                                • ranger_danger 4 days ago

                                                  I wonder if most of the reason people use auto is just to save time when typing... if the IDE could auto-resolve the type in the source code when they use auto... would that be a better compromise?

                                                  • ch33zer 4 days ago

                                                    This was probably rhetorical but metas code review tool runs LSP and gives you clickable types where clicking takes you to the definition.

                                                  • AlotOfReading 4 days ago

                                                    Editor type deduction is surprisingly unreliable sometimes.

                                                  • benreesman 4 days ago

                                                    Herb Sutter has a pretty good explanation: https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style...

                                                    • Koshkin 4 days ago

                                                      ‘auto’ (in C++) and ‘var’ (in C# and Java) is a blessing, makes code much less verbose. Also good for refactoring - less code to change.

                                                      • BalinKing 4 days ago

                                                        I’m only a C++ amateur, but IMHO C++ vs C#/Java isn’t really a fair comparison here—the latter doesn’t have template shenanigans and so types are much more transparent to the reader (by which I mean that you don’t have to execute a dynamically-typed program in your head to get from the term on the right-hand side to the type on the left).

                                                        • bigstrat2003 4 days ago

                                                          Verbosity is not bad. When it makes the code clearer, it is even a good thing.

                                                          • ithkuil 4 days ago

                                                            Complex type parameters make explicit typing highly impractical to be used all the times

                                                            I like rust's approach in that it allows a mixture of explicit types and type inference using placeholders

                                                            For example: "let x : Result<Foo<int, _>, _> = make_foo();"

                                                        • zabzonk 4 days ago

                                                          Complicated template types, where you have a general idea of the type but you don't want or need to spell it all out (it might be very long) when the compiler can easily do it for you.

                                                          • FpUser 4 days ago

                                                            I am in a middle ground. Usually do not use auto but in the cases like:

                                                               for (auto member : set_of_members)
                                                            
                                                            and some other that are similar by nature auto is a god blessing.
                                                            • secondcoming 4 days ago

                                                              Except this makes a copy of each member in set_of_members, which is probably not what you want.

                                                              https://godbolt.org/z/1YnEs1M34

                                                              • FpUser 4 days ago

                                                                This was to illustrate a point of auto rather than intricacies of copying, referencing. I know what I want and am familiar with auto&, const auto&, auto&& etc. etc.

                                                              • undefined 4 days ago
                                                                [deleted]
                                                              • cesaref 4 days ago

                                                                I can certainly relate to this experience. I remember when it was introduced, I was very wary of getting too much 'auto' into the codebase, certainly as the team could be a bit 'gung-ho' adopting stuff just because it was there.

                                                                However, in hindsight, I think I was being overly conservative, and it worked out well, and adoption didn't cause any obvious problems.

                                                                Your concerns about learning a new library are valid, but the problem is the library if it's not clear, or well documented. To lay responsibility for this at the door of auto is a stretch. You can write great and terrible code with a number of language features (dubious use of goto is the classic example), and it sounds like you are tackling a library which could do with some love, either in documentation, or to clarify it's conventions.

                                                                • ok123456 4 days ago

                                                                  Auto is preferred for assignment because it eliminates a whole class of errors involving unintentional construction. Dropping a const is the conanical example.

                                                                  Auto in a function signature is syntactic sugar for introducing a template parameter. It needs to be monomorphized at some point to generate code.

                                                                  • kgeist 4 days ago

                                                                    My rule of thumb is to use auto only when the type is obvious from the context. I think it's a sane compromise between readability and non-verbosity.

                                                                    • pjmlp 4 days ago

                                                                      Programming without IDE is so 1970's...

                                                                      Having said this, I usually only use type inference when the types are obvious from context.

                                                                      • jayd16 4 days ago

                                                                        Was this tongue in cheek? If you _can_ use inference it was at least obvious enough to the compiler. Otherwise you're just saying "I use it when I feel like it."

                                                                        • pjmlp 4 days ago

                                                                             auto x = func(); // no idea about func return type
                                                                          
                                                                             auto x = new Widget(); // DRY
                                                                          
                                                                             auto sum (auto a, auto b); //  template function without boilerplate 
                                                                          
                                                                          Use the same principle in other contexts.
                                                                      • maccard 4 days ago

                                                                        Im as shocked as you are that people rely on textual representations and ignore all the powerful tooling available to them for understanding code.

                                                                        Every editor I use has tools that will provide this information in a single keystroke, macro or cluck. If you actively choose to avoid using tools to read code, I shouldn’t suffer for it.

                                                                        • mgaunard 4 days ago

                                                                          if you need tools it just means the code is sub-par

                                                                          • orf 4 days ago

                                                                            That take is so comically nonsensical I question why you’d even contribute it.

                                                                            I have no doubt you read and write code without any tools.

                                                                            • maccard 4 days ago

                                                                              Grep is a tool. But if I grep foo, it can’t tell me the difference between a function called foo, a variable called foo, or any other types that may have a foo, or a comment with foo in it. Even vscode can do “show me all uses of foo” in a single click, and be perfectly correct,

                                                                              • mgaunard 4 days ago

                                                                                It's not perfectly correct, and that actually what makes it dangerous.

                                                                          • ch33zer 4 days ago

                                                                            One area where auto is necessary is in coroutines. The types are so hideous and abstract that writing them out is guaranteed to be less readable than using auto and accepting the your types are some blend of compiler derived and coroutine library magic.

                                                                            • musicale 4 days ago

                                                                              > I am so shocked at how many people use `auto` in C++

                                                                              Well I blame C++ for calling it "auto" in the first place. Fortunately this is easily fixed:

                                                                                  #define let auto
                                                                                  #define var auto
                                                                              
                                                                              ;-)
                                                                              • lairv 4 days ago

                                                                                Using auto in function parameters to have implicit templates is very cursed

                                                                                • jayd16 4 days ago

                                                                                  I'm pretty supportive of auto and var, etc. in languages but parameters seem like a step too far.

                                                                                • dataflow 4 days ago

                                                                                  > I am so shocked at how many people use `auto` in C++.

                                                                                  I agree with you! But:

                                                                                  > I can not think of a worse thing to do to your code in terms of readability and future maintainability.

                                                                                  Well, I definitely can. Using macros is one ;)

                                                                                  > I am trying to learn a new library right now with light documentation which means reading the code, and between typedefs, auto

                                                                                  I disagree with you on the typedefs. They're much better than auto. Auto doesn't provide any type checking, it works whatever the type is. Typedef tell you what the expected type actually is.

                                                                                  • fooker 4 days ago

                                                                                    Like everything in life, it has to be used in moderation.

                                                                                    auto it = data.begin();

                                                                                    Is a lot more readable than

                                                                                    std::vector<std::pair<std::vector<foo>, int>::iterator it = ....

                                                                                    • gigatexal 4 days ago

                                                                                      Oh boy! A vector of tuples of vectors and ints? Crazy

                                                                                      • fooker 2 days ago

                                                                                        Nesting standard library containers can get you neat data structures without much work

                                                                                      • junon 4 days ago

                                                                                        I don't know why I feel the urge to point this out but you missed an angle bracket :D

                                                                                        • fooker 2 days ago

                                                                                          That's exactly why I'd use auto here!

                                                                                      • readyplayernull 4 days ago

                                                                                        Isn't inline more "undeterministic" than auto? That is way older and used everywhere.

                                                                                        I'd like auto functions.

                                                                                        • jayd16 4 days ago

                                                                                          Isn't it mostly meaningless outside of the syntax sugar of putting code in the header?

                                                                                        • summerlight 4 days ago

                                                                                          My take is that `auto` is basically a tool to reduce local redundancies rather than typing convenience. Rule of thumb: you should avoid `auto` unless it actually improves readability (e.g. significant reductions of syntactic redundancies), or there is no other option.

                                                                                          • nox101 4 days ago
                                                                                            • DonHopkins 4 days ago

                                                                                              Some kinky C++ programmers have such a sexual fetish for using `auto` that they enjoy holding their breath as long as possible while writing code, before ever declaring any explicit type names. That's called auto-erotic asphyxiation!

                                                                                              • paulddraper 4 days ago

                                                                                                > it is a tedious exercise to figure out something's type, to go look up its function, to see what type that is returning

                                                                                                To cite your previous sentence, why don't you use your IDE?

                                                                                                Or is this a magnetized needle sort of situation.

                                                                                                • nurettin 4 days ago

                                                                                                     int wtf = omgtype(); // and read the compiler error
                                                                                                  • RcouF1uZ4gsC 4 days ago

                                                                                                    Honestly, use a good IDE.

                                                                                                    Jetbrains can annotate your source with what the actual type is.

                                                                                                    and auto can help future maintainability if you need to change concrete types that have the same API surface.

                                                                                                    • UebVar 4 days ago

                                                                                                      If you don't use an IDE, you are doing it wrong, plain and simple.

                                                                                                      Editing png with a text editor is also much harder than editing ppm. But there is no reason to consider this usecase when defining a image format.

                                                                                                      • foooorsyth 4 days ago

                                                                                                        Not everyone reading your code will be using an IDE. People may be passively searching your code on GitHub/gerrit/codesearch.

                                                                                                        val/var/let/auto declarations destroy the locality of understanding of a variable declaration without an IDE + a required jump-to-definition of a naive code reader. Also, a corollary of this problem also exists: if you don’t have an explicit type hint in a variable declaration, even readers that are using an IDE have to do TWO jump-to-definition actions to read the source of the variable type.

                                                                                                        eg.

                                                                                                        val foo = generateFoo()

                                                                                                        Where generateFoo() has the signature fun generateFoo(): Foo

                                                                                                        With the above code one would have to jump to definition on generateFoo, then jump to definition on Foo to understand what Foo is. In a language that requires the explicit type hint at declaration, this is only one step.

                                                                                                        There’s a tradeoff here between pleasantries while writing the code vs less immediate local understanding of future readers / maintainers. It really bothers me when a ktlint plugin actually fails a compilation because a code author threw in an “unnecessary” type hint for clarity.

                                                                                                        Related (but not directly addressing auto declarations): “Greppability is an underrated code metric”: https://morizbuesing.com/blog/greppability-code-metric/

                                                                                                        • edflsafoiewq 4 days ago

                                                                                                          If you accept f(g()), you've already accepted that the type of every expression is not written down.

                                                                                                          • foooorsyth 4 days ago

                                                                                                            I don’t particularly accept f(g()). I like languages that require argument labels (obj-c, swift). I would welcome a language that required them for return values as well. I’d even enjoy a compiler that injected omitted ones on each build, so you can opt to type quickly while leaning on the compiler for clarity beyond build time.

                                                                                                            • gpderetta 4 days ago

                                                                                                              Argument labels are equivalent to variable names. You still have them with auto. In either case you don't see the actual type.

                                                                                                          • adrian_b 4 days ago

                                                                                                            I do not agree that using an IDE matters.

                                                                                                            If you cannot recognize the type of an expression that is assigned to a variable, you do not understand the program you are reading, so you must search its symbols anyway.

                                                                                                            Writing redundantly the type when declaring the variable is of no help when you do not know whether the left hand side expression has the same type.

                                                                                                            When reading any code base with which you are not familiar, you must not use a bad text editor, but either a good text editor designed for programmers or any other tool that allows fast searching for the definitions of any symbols encountered in the source text.

                                                                                                            Adding useless redundancy to the source text only bloats it, making reading more difficult, not easier.

                                                                                                            I never use an IDE, but I always use good programming language aware text editors.

                                                                                                            • UebVar 4 days ago

                                                                                                              The argument is tautological.

                                                                                                              I want to use a text editor => This is the wrong tool => Yes, but I want to use a text editor.

                                                                                                              These people do use the wrong tooling. The only way to cure this grievance is to use proper tooling.

                                                                                                              The github webui has some ide features, such as symbol search. I don't see any reason why not use a proper ide. github.dev is a simple click in the ui away. When you use gerrit, do a local checkout, that's one git command.

                                                                                                              If you refuse to use the correct tools for the job, your experience is degraded. I don't see a reason to consider this case when writing code.

                                                                                                              • foooorsyth 4 days ago

                                                                                                                Have you ever worked in a large organization with many environments? You may find yourself with a particular interface that you don’t know how to use. You search the central code search tool for usages. Some other team IS using the API, but in a completely different environment and programming language, and they require special hardware in their test loop, and they’re located in Shanghai. It will take you weeks to months to replicate their setup. But your goal is to just understand how to use your version of the same API. This is incredibly common in big companies. If you’re in a small org with limited environments it’s less of an issue.

                                                                                                                • UebVar 4 days ago

                                                                                                                  I have worked in big environments. My idea about "big" might be naive, environments spanning different Oses and different, including old languages like fortran and pascal. But I never been in a situation where I couldn't check out said code, and open it in my ide and build it. If you can't that sounds like a another case of deficient tooling. Justifying deficient tooling.

                                                                                                                  These where not some SWE wonderlands either. The code was truly awful at times.

                                                                                                                  The Joel test is 25 years old. It's a industry standard. I, and many other people consider it a minimum requirement for software engineering. If code the "2. Can you make a build in one step?" requirement i should be ide-browsable in one step.

                                                                                                                  If it takes weeks to replicate a setup the whole environment is deeply flawed. The one-step build is the second point on the list because Joel considered it the second most important thing, out of 12.

                                                                                                                  • foooorsyth 4 days ago

                                                                                                                    My situation: hardware company, over 100 years old. I’ve found useful usage examples of pieces of software I need to use, but only on an OS we no longer ship, from a supplier we no longer have a relationship with, that runs on hardware that we no longer have. The people that know how to get the dev environment up are retired.

                                                                                                                    In those cases, I’m grateful for mildly less concise languages that are more explicit at call and declaration sites.

                                                                                                                  • adrian_b 4 days ago

                                                                                                                    If you are unable to find the type of a right-hand-side expression that appears in an assignment or initialization, then the environment does not allow you to work and it must be changed.

                                                                                                                    The redundant writing of the type on the left-hand side does not help you, because without knowing the type of the right-hand side you cannot recognize a bug. Not specifying the type on the left-hand side can actually avoid many bugs in complex environments, because there is no need to update the code that uses some API, whenever someone changes the type of the result, unless the new type causes some type mismatch error elsewhere, where it would be reported, allowing to make fixes at the right locations in the source code, not at the spurious locations of variable definitions, where updating the type will not prevent the real bugs to occur at the points of use of that variable.

                                                                                                                    The only programming languages that could be used without the ability of searching the definition of any symbol, were the early versions of FORTRAN and BASIC, where the type of a symbol was encoded in the name of the symbol, by using a one-letter prefix in FORTRAN (like IVAR vs. XVAR) and a one-symbol suffix in BASIC (like X vs. X$ vs. X%).

                                                                                                                    The "Hungarian" convention for names used in early Microsoft Windows has been another attempt of encoding the types of the symbols in their names, following the early FORTRAN and BASIC style, but most software developers have disliked this verbosity.

                                                                                                                • chrisoverzero 4 days ago

                                                                                                                  > if you don’t have an explicit type hint in a variable declaration, even readers that are using an IDE have to do TWO jump-to-definition actions to read the source of the variable type.

                                                                                                                  This isn’t necessarily the case. “Go to Definition” on the `val` goes to the definition of the deduced type in the IDEs and IDE-alikes I’ve ever used.

                                                                                                                • alexvitkov 4 days ago

                                                                                                                  You should never write code that's impossible to understand without fancy IDE features. If you're writing such code, the best thing you can do for yourself long term is switch to a text editor without LSP (read Notepad) right now, which will force you to start writing sane code.

                                                                                                                  This is true for any language, but it's especially true for C++, where most large codebases have tons of invisible code flying around - implicit casts, weird overloads, destructors, all of these possibly virtual calls, possibly over type-erased objects accessed accessed via smart pointers, possibly over many threads - if you want to stand any chance of even beginning to reason about all that you NEED to see the actual, concrete, scientific types of things.

                                                                                                                  • Jyaif 4 days ago

                                                                                                                    > You should never write code that's impossible to understand without fancy IDE features

                                                                                                                    with Rust that ship has sailed

                                                                                                                    • jeltz 4 days ago

                                                                                                                      I code Rust just fine without any fancy IDE you should give it a shot. The languages I find hardest to code without fancy IDE features are C and C++ due to their implicit casts. Rust is typically easy to code without IDE features due to its strong type system, lifetimes and few implicit casts.

                                                                                                                      • zbentley 4 days ago

                                                                                                                        Rust is one of my favorite new languages, but this is just wrong.

                                                                                                                        > few implicit casts

                                                                                                                        Just because it doesn't (often) implicitly convert/pun raw types doesn't mean it has "few implicit casts". Rust has large amounts implicit conversion behavior (e.g. deref coercion, implicit into), and semi-implicit behavior (e.g. even regular explicit ".into()" distances conversion behavior and the target type in code). The affordances offered by these features are significant--I like using them in many cases--but it's not exactly turning over a new leaf re: explicitness.

                                                                                                                        Without good editor support for e.g. figuring out which "into" implementation is being called by a "return x.into()" statement, working in large and unfamiliar Rust codebases can be just as much of a chore as rawdogging C++ in no-plugins vim.

                                                                                                                        Like so many Rust features, it's not breaking with specific semantics available in prior languages in its niche (C++); rather, it's providing the same or similar semantics in a much more consciously designed and user focused way.

                                                                                                                        > lifetimes

                                                                                                                        How do lifetimes help (or interact with) IDE-less coding friendliness? These seem orthogonal to me.

                                                                                                                        Lastly, I think Rust macros are the best pro-IDE argument here. Compared to C/C++, the lower effort required (and higher quality of tooling available) to quickly expand or parse Rust macros means that IDE support for macro-heavy code tends to be much better, and much better out of the box without editor customization, in Rust. That's not an endorsement of macro-everything-all-the-time, just an observation re: IDE support.

                                                                                                                        • jeltz 4 days ago

                                                                                                                          Have you actually tried coding Rust without IDE support? I have. I code C and Rust professionally with basically only syntax highlighting.

                                                                                                                          As for how lifetimes help? One of the more annoying parts of coding C is to constantly have to look up who owns a returned pointer. Should it be freed or not?

                                                                                                                          And I do not find into() to be an issue in practice.

                                                                                                                    • adrian_b 4 days ago

                                                                                                                      While the C language has a lot of bad implicit casts that should have never been allowed, mainly those involving unsigned types, and which have been inherited by its derivatives, implicit casts as a programming language feature are extremely useful when used in the right way.

                                                                                                                      Implicit casts are the only reason for the existence of the object-oriented programming languages, where any object can be implicitly cast to any type from which it inherits, so it can be passed as an argument to any function that expects an argument of that type, including member functions.

                                                                                                                      The whole purpose of inheritance is to allow the programmer to use implicit casts. Otherwise, one would just declare a structure member of the class from which one would inherit in the OOP style and a virtual function table pointer, and one could write an identical program with the OOP program, but in a much more verbose way.

                                                                                                                      (In the C language, not only the implicit mixed signed-unsigned casts are bad, but also any implicit unsigned-unsigned casts are bad, because there are 2 interpretations of "unsigned" frequently used in programs, as either non-negative numbers or as modular numbers, and the direction of the casts that do not lose information is reversed for the 2 interpretations, i.e. for non-negative numbers it is safe to cast only to a wider type, but for modular numbers it is safe to cast only to a narrower type. Moreover, there are also other interpretations of "unsigned", i.e. as binary polynomials or as binary polynomial residues, which cannot be inter-converted with numbers. For all these 4 interpretations, there are distinct machine instructions in the instruction sets of popular CPUs, e.g. in the x86-64 and Aarch64 ISAs, which may be used in C programs through compiler intrinsics. Even worse is that the latest C standards specify that the overflow behavior of "unsigned" is that of modular numbers, while the implicit casts of "unsigned" are those of non-negative numbers. This inconsistency guarantees the existence of perfectly legal C programs, without any undefined behavior, but which nonetheless compute incorrect "unsigned" values, regardless which interpretation was intended for "unsigned".)

                                                                                                                      • alexvitkov 4 days ago

                                                                                                                        > Otherwise, one would just declare a structure member of the class from which one would inherit in the OOP style and a virtual function table pointer, and one could write an identical program with the OOP program, but in a much more verbose way.

                                                                                                                        No, you don't have to do that. Once you start thinking about memory and manually managing it, it you'll figure out there's simpler, better ways to structure your program, rather than having a deep class hierarchy with a gazillion heap-allocated objects, each with distinct lifetime, all pointing at each other.

                                                                                                                        Here's a trivial example. Say you're writing a JSON parser - if you approach it with an OOP mindset, you would probably make a JSONValue class, maybe subclass it with JSONNumber/String/Object/Array. You would walk over the input string and heap allocate JSONValues as you go. The problems with this are:

                                                                                                                            1. Each allocation can be very slow as it can enter the kernel
                                                                                                                            2. Each allocation is a possible failure point, so the number of failure points scales linearly with input size.
                                                                                                                            3. When you free the structure, you must walk over the entire tree and free each obejct one by one.
                                                                                                                            4. The output of this function is suboptimal as the memory allocator can return values that are far away in memory.
                                                                                                                        
                                                                                                                        There's an alternate approach that solves all these problems. If you're thinking about the lifetimes of your data, you would notice that this entire data structure is used and discarded at once, so you allocate a single big buffer for all the nodes. You keep a pointer to the head of that buffer, and when you need a new node, you stick it in there and advance the pointer by its size. When you're done you return the first node, which also happens to be the start of the buffer.

                                                                                                                        Now you have a single point of failure - the buffer allocation, your program is way faster, you only need to free one thing when you're done, and your values are tightly packed in memory, so whatever is using its output will be faster as well. You've spent just a little time thinking about memory and now you have a vastly superior program in every single aspect, and you're happy.

                                                                                                                        • usrnm 4 days ago

                                                                                                                          Memory arenas are a nice concept but I wouldn't say they're necessarily an improvement in every possible situation. They increase complexity, make reasoning about the code and lifetimes harder and can lead to very nasty memory bugs. Definitely something to use with caution and not just blindly by default.

                                                                                                                          • alexvitkov 3 days ago

                                                                                                                            Reasoning about the lifetimes of objects in an arena is as simple as it gets - there's only one lifetime, and pointers between everything allocated on the arena are perfectly safe. The complexity of figuring out what's going on, with with respect to the number of objects and links between is O(1).

                                                                                                                            There's no universal "God pattern" that you can throw at every problem. I used arenas as an example as I didn't want to write a zero-substance "OOP bad" post, but my point wasn't that instead of always using OOP+inheritance you should always use an arena, it was that if you think about your memory, more often than not there's a vastly superior layout than a bunch of heap objects glued together by prayers and smart pointers.

                                                                                                                            • usrnm 3 days ago

                                                                                                                              That's all nice and fun until you want to pass stuff around and some objects might outlive the arena. Do you keep the whole arena around, do you copy, do you forget to do anything at all and spend a few days debugging weird memory bugs in prod?

                                                                                                                        • AlotOfReading 4 days ago

                                                                                                                          "Non-negative" unsigneds can be validly cast to smaller types. That's why saturating_cast() exists. There are modular numbers where casting to a smaller value is likewise unsafe at a logical level. Your LCRNG won't give you the right period when downcast, even if the modulus value is unchanged.

                                                                                                                          • knome 4 days ago

                                                                                                                            inheritance isn't required for object oriented programming. the primary facet of oop is hiding implementation details behind functions that manipulate that data.

                                                                                                                            adding values to a dict via add() and removing them via remove() should not expose to the caller if the underlying implementation is an array of hash indexed linked lists or what. the implementation can be changed safely.

                                                                                                                            inheritance is orthogonal to object orientation. or rather, inheritance requires oop, but oop does not require inheritance.

                                                                                                                            golang lacks inheritance while remaining oop, for instance, instead using interfaces that allows any type implicitly defining the specified interface to be used the.

                                                                                                                            • adrian_b 4 days ago

                                                                                                                              "Hiding implementation details" means the same as "hiding the actual data type of an object", which means the same as "performing an implicit cast whenever the object is passed as an argument to a function".

                                                                                                                              Using different words does not necessarily designate different things. Most things that are promoted at a certain time by fashions, like OOP, abuse terminology by giving new names to old things in the attempt of appearing more revolutionary than they really are.

                                                                                                                              Most classic works about OOP define OOP by the use of inheritance and of virtual functions a.k.a. dynamic polymorphism. Both features have been introduced by SIMULA 67 and popularized by Smalltalk, the grandparents of all OOP languages.

                                                                                                                              When these 2 features are removed, what remains from OOP are the so-called abstract data types, like in CLU or Alphard, where you have data types that are defined by the list of functions that can process values of that type, but without inheritance and with only static polymorphism (a.k.a. overloading).

                                                                                                                              The example given by you for hiding an implementation is not OOP, but it is just the plain use of modules, like in the early versions of Ada, Mesa or Modula, which did not have any OOP features, but they had modules, which can export types or functions whose implementations are hidden.

                                                                                                                              Because all 3 programming language concepts, modules, abstract data types and OOP have as an important goal preventing the access to implementation details, there is some overlap between them, but they are nonetheless distinct enough so that they should not be confused.

                                                                                                                              Modules are the most general mechanism for hiding implementation details, so they should have been included in any programming language, but the authors of most OOP languages, especially in the past, have believed that the hiding provided by granting access to private structure a.k.a. class members only to member functions is good enough for this purpose. However this leads sometimes to awkward programs where some classes are defined only for the purpose of hiding things, for which real modules would have been more convenient, so many more recent versions of OOP languages have added modules in some form or another.

                                                                                                                              • knome 4 days ago

                                                                                                                                I'll readily admit the languages were marketed that way, but would argue inheritance was a functional, but poor, imitation of dynamic message dispatch. Interfaces, structural typing, or even simply swapping out object types in a language with dynamic types does better for enabling function-based message passing than inheritance does, as they avoid the myriad pitfalls and limitations associated with the technique.

                                                                                                                                Dynamic dispatch can be accomplished in any language with a function type by using a structure full of functions to dispatch the incoming invocations, as Linux does in C to implement its file systems.

                                                                                                                                • igouy 3 days ago

                                                                                                                                  1994 "Object-Oriented Programming in Oberon-2" seems to cover what you discuss.

                                                                                                                                  https://ssw.jku.at/Research/Books/Oberon2.pdf

                                                                                                                              • uecker 4 days ago

                                                                                                                                I am actually ok with the conversions and C and think they are quite convenient. Unsigned in C is modular. I am not sure what you mean by the "latest C standards specify". This did not change. I also do not understand what you mean by the "implicit cast of unsigned are those of non-negative numbers". This seems wrong. If you convert to a larger unsigned type, the value is unchanged and if you convert to a smaller, it is reduced modulo.

                                                                                                                                • adrian_b 4 days ago

                                                                                                                                  In older C standards, the overflow of unsigned numbers was undefined.

                                                                                                                                  In recent C standards, it has been defined that unsigned numbers behave with respect to the arithmetic operations as modular numbers, which never overflow.

                                                                                                                                  The implicit casts of C unsigned numbers are from narrower to wider types, e.g. from "unsigned short" to "unsigned" or from "unsigned" to "unsigned long".

                                                                                                                                  These implicit casts are correct for non-negative numbers, because all values that can be represented as e.g. "unsigned short" are included among those represented by "unsigned" and they are preserved by the implicit casts.

                                                                                                                                  However, these implicit casts are incorrect for modular numbers, because they attempt to compute the inverse of a non-invertible function.

                                                                                                                                  For instance, if you have an "unsigned char" that is a modular number with the value "3", it is incorrect to convert it to an "unsigned short" modular number with the value "3", because the same "unsigned char" "3" corresponds also to 255 other "unsigned short" values, i.e. to 259, 515, 781, 1027 and so on.

                                                                                                                                  If you have some very weird reason when you want to convert a number modulo 256 to a number modulo 65536 by choosing a certain number among those with the same residue modulo 256, then you must do this explicitly, because it is not an information-preserving conversion.

                                                                                                                                  If on the other hand you interpret a C "unsigned" as a non-negative number, then the implicit casts are OK, but you must add everywhere explicit checks for unsigned overflow around the arithmetic operations, otherwise you will obtain erroneous results.

                                                                                                                                  • uecker 4 days ago

                                                                                                                                    The C89 standard has "A computation involving unsigned operands can never overflou. because a result that cannot be represented b! the resulting unsigned integer type is reduced modulo the number that is one greater thnn the largest value that can be represented by the resulting unsipned integer type" (OCR errors) You can finde a copy here: https://web.archive.org/web/20200909074736if_/https://www.pd...

                                                                                                                                    Mathematically, there is no clearly defined way how one would have to map from one residue system in modular arithmetic to the next, so there is no "correct" or "incorrect" way. Mapping to the smallest integer in the equivalency class makes a lot of sense though, as it maps corresponding integers to itself when going to a larger type and and the reverse operation is then the inverse, and this is exactly what C does.

                                                                                                                              • undefined 4 days ago
                                                                                                                                [deleted]
                                                                                                                              • ranger_danger 4 days ago

                                                                                                                                Can we turn down the dogmatism please? I think you will find that there are other equally valid perspectives if you look around, and that the world is not so black and white.

                                                                                                                            • SideburnsOfDoom 5 days ago

                                                                                                                              See c#:

                                                                                                                              "A discard communicates intent to the compiler and others that read your code: You intended to ignore it.

                                                                                                                              You indicate that a variable is a discard by assigning it the underscore (_) as its name."

                                                                                                                              https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals...

                                                                                                                              2020: http://dontcodetired.com/blog/post/Variables-We-Dont-Need-No...

                                                                                                                              • tempodox 4 days ago

                                                                                                                                Yep, Microsoft took only almost 50 years to do what Prolog could do in 1971, and the C++ standards committee took ~5 years longer.

                                                                                                                              • agumonkey 5 days ago

                                                                                                                                Makes me wonder when '_' was first used as a token to denote unused information. Prolog ? ML ?

                                                                                                                                • lieks 5 days ago

                                                                                                                                  If we're counting only programming languages (and not fill-out forms), Prolog had it in 1971, before ML. ASCII didn't include _ until its 1963 draft, so it's probably somewhere in that time.

                                                                                                                                  I'll guess it's probably Prolog, but maybe Planner (Prolog's predecessor) had it too.

                                                                                                                                • nicoburns 5 days ago

                                                                                                                                  I think this predates computers entirely.

                                                                                                                                  • SideburnsOfDoom 5 days ago

                                                                                                                                    I think so, yes. English novels written in the 1800s would reference "Mr A------ from ------shire". As if they were redacting personally identifying information. (1)

                                                                                                                                    Underscores and dashes are not that different - especially as this is not just pre-computer but pre-typewriter.

                                                                                                                                    And now, underscores are a logical choice when the dash is already in use as a minus sign.

                                                                                                                                    1) https://literature.stackexchange.com/questions/1944/why-are-...

                                                                                                                                    https://forums.welltrainedmind.com/topic/141704-jane-austens...

                                                                                                                                    • adrian_b 4 days ago

                                                                                                                                      Underscore has been used in programming for the first time by the language IBM PL/I, in 1964-12, where it replaced the hyphen/minus character that was used by COBOL to make more readable the long identifiers.

                                                                                                                                      Replacing hyphen/minus with underscore has been done precisely for removing the ambiguity with the minus operator (In COBOL the ambiguity was less annoying, because the arithmetic operations were usually written with words, e.g. ADD, SUBTRACT, MULTIPLY and so on).

                                                                                                                                    • agumonkey 5 days ago

                                                                                                                                      Good point, this is clearly something that could go back centuries.. if not all the way back to clay tablets.

                                                                                                                                    • undefined 4 days ago
                                                                                                                                      [deleted]
                                                                                                                                    • kookamamie 5 days ago

                                                                                                                                      What a convoluted mess.

                                                                                                                                      • jayd16 4 days ago

                                                                                                                                        Seems pretty clean to me? Do you mean the current state of affairs is a mess?

                                                                                                                                        • devnullbrain 4 days ago

                                                                                                                                          I don't think the one character solution introduced at the bottom of TFA is convoluted. Could you explain why you think the solution - introduced at the bottom of TFA - is convoluted?

                                                                                                                                          • asah 4 days ago

                                                                                                                                            My thought exactly. But that's C++, a bolted-on mess of crap whose redeeming features are (a) roughly the same execution performance as C and assembly, and (b) it's safer and higher productivity than C or assembly.

                                                                                                                                            At this point, it feels like a matter of time before Rust replaces C/C++.

                                                                                                                                            • dgfitz 4 days ago

                                                                                                                                              There are decades and decades of code written in cobol that run the modern banking system.

                                                                                                                                              Multiply that code base size by like, 78.3, and you’re possibly in the same galaxy as the all the c++ codebases out there that will be maintained for the next 50 years.

                                                                                                                                              Rust may eat the lunch of c++ moving forward, the language will never go away.

                                                                                                                                              • DowsingSpoon 4 days ago

                                                                                                                                                >the language will never go away

                                                                                                                                                Just like COBOL! Seriously, _just like COBOL_. The language will fade in importance over time. C++ will be relegated to increasingly narrow niches. It will eventually only be found in "legacy" systems that no one wants to spend to rewrite. No one young will bother at all to learn C++ at all. Then, in a few decades, they'll be pulling folks like you and me out of retirement to maintain old systems for big bucks.

                                                                                                                                                • timewizard 4 days ago

                                                                                                                                                  I doubt this analysis. The base of computing where C++ is used is exponentially larger than the base where COBOL was used. In particular the compilers we currently use are written in it.

                                                                                                                                                  • DowsingSpoon 2 days ago

                                                                                                                                                    You definitely make a good point. My thought was that large legacy projects would slowly migrate to a different language. The news of the recent introduction of Rust in Linux has me optimistic something similar will eventually happen in other places too. (not necessarily with Rust, specifically) The keyword here is Eventually. I’m thinking this is years away for GCC and LLVM.

                                                                                                                                                    If the new language has good interop with the old then this doesn’t have to be painful either. A while back, I was working on a large Objective-C code base which was slowly moving to Swift. We quickly got to a point where new code was written in Swift by default. In only a couple of years, we had a code base which used Objective-C pretty much only in the dark corners where code churns slowly.

                                                                                                                                                • larodi 4 days ago

                                                                                                                                                  Abso-fkn-lutely! Stable computing protocols of all sorts don’t go away overnight and that is something everyone in IT should absolutely get used to. I expect C/C++ to live long beyond 2050.

                                                                                                                                                • flohofwoe 4 days ago

                                                                                                                                                  Tbf, Rust is catching up fast to become the same mess (especially in the stdlib).

                                                                                                                                                  > it's safer and higher productivity than C or assembly

                                                                                                                                                  Debatable - in C and even more so in assembly, the unsafety is at least directly in your face, while in C++ it's cleverly diguised under C++ stdlib interfaces (like dangling std::string_views, all the iterator invalidation scenarios etc... meaning that memory corruption bugs may be much harder to investigate in C++ than in C (or even assembly) - which in turn affects productivty (e.g. what's the point in writing higher level buggy code faster when debugging takes much longer).

                                                                                                                                                  > it feels like a matter of time before Rust replaces C/C++

                                                                                                                                                  It may replace C++, but C will most likely outlive at least C++, and I wouldn't be surprised if Rust too - even if just as C API wrappers to allow code written in different modern languages to talk to each other ;)

                                                                                                                                                  • kibwen 4 days ago

                                                                                                                                                    > Tbf, Rust is catching up fast to become the same mess (especially in the stdlib).

                                                                                                                                                    I've never seen any users who avoid using Rust's stdlib on principle. The closest thing is the use of the parking_lot crate over the standard Mutex types, but that's getting better over time, not worse, as the stdlib moves closer to parking_lot in both implementation and API. Other than that, there's only been one "wrong" API that needed to be deprecated with a vengeance (mem::uninitialized, replaced by mem::MaybeUninit). Especially compared to C++, the fact that Rust doesn't have a frozen ABI means it's free to improve the stdlib in ways that C++ can only dream of. While I do wish that the Rust stdlib contained some more things (e.g. a standard interface to system entropy, rather than making me pull in the getrandom crate), for what it provides the Rust stdlib is quite good.

                                                                                                                                                    • accelbred 4 days ago

                                                                                                                                                      I avoid the Rust stdlib. The stdlib uses panics and dynamic memory allocation, neither of which are great for embedded usecases or writing software adhering to safety-critical coding practices. no_std is common for embedded targets, and IIRC the linux kernel couldn't use stdlib because of panics.

                                                                                                                                                      • vlovich123 4 days ago

                                                                                                                                                        Ironically c++ as well refused to define an ABI. That’s not why the language is bad. It’s the lack of editorial tools within the language the standard body has so it has no evolution path and thus ossifies under its own inertia. It’s amazing they still haven’t done anything about it.

                                                                                                                                                      • vlovich123 4 days ago

                                                                                                                                                        > Rust is catching up fast to become the same mess (especially in the stdlib)

                                                                                                                                                        Care to provide examples?

                                                                                                                                                        I think they generally do a very good job at curating the APIs to feel very consistent. And with editions, they can fix almost any mistakes they make whereas c++ doesn’t have that. In fact, the situation in c++ is so bad that they can’t fix any number of issues in basic containers and refuse to introduce updated fixes because “it’s confusing”. The things they keep adding to the stdlib aren’t even core useful things that come out of the box. Like missing a networking API in 2025. The reason is they have to get it perfect because otherwise they can’t fix issues and they can’t get it perfect because networking is a continuously moving target. Indeed we managed to get a new tcp standard before c++ even though it had even worse ossification issues. Or not caring about the ecosystem enough to define a single dependency management system because the vendors can’t get agreement or a usable module system. Or macros being a hot mess in c++ some 20 years after it was already known to really suck.

                                                                                                                                                        Now it’s possible given enough time rust will acquire inconsistent warts over time similar to c++, but I just don’t think it’ll ever be as bad in the standard library due to editions and automated migration tools being easier against rust. Similarly, I think editions give them the flexibility to address even many language level issues. Inertia behind ways of doing things are the harder challenges that are shared between languages (eg adoption of Unsend might prevent the simpler Move trait from being explored and migrated to), but c++ is getting buried under its own weight because it’s not a maintainable language in terms of the standard because the stewards refuse to realize they don’t have the necessary editorial tools and keep not building themselves such tools (even namespace versions ended up being aborted and largely unused).

                                                                                                                                                        • flohofwoe 4 days ago

                                                                                                                                                          Just look at the Option type and all the methods on it, the whole concept of optionals should be built into the language, not stdlib:

                                                                                                                                                          https://doc.rust-lang.org/std/option/enum.Option.html

                                                                                                                                                          Same with Result, Box, Rc, Arc, Cell, RefCell, (plus even more *Cells), Iter, ... the resulting 'bread crumbs syntax' is IMHO the main reason why typical Rust code is so hard to read. This philosophy to push what should be language features into the stdlib is the same as in C++ (and IMHO one of the main problems of C++), it's probably also a reason why both languages are so slow to compile.

                                                                                                                                                      • justin66 4 days ago

                                                                                                                                                        > At this point, it feels like a matter of time before Rust replaces C/C++.

                                                                                                                                                        I expect Rust's successor might have a shot at replacing C++.

                                                                                                                                                        By the time C++ was as old as Rust, it had conquered the world. If Rust coulda, it woulda.

                                                                                                                                                        • caspper69 4 days ago

                                                                                                                                                          I think you're right.

                                                                                                                                                          As soon as you start writing big(ger) software in Rust, its lacking ergonomics really become apparent.

                                                                                                                                                          .as_mut().unwrap().unwrap().as_mut().do_stuff() gets really old after a while.

                                                                                                                                                          And I am not convinced that borrow checking is the panacea that it's made out to be. Region-based memory management can accomplish the same safety goals (provided there's a sane concurrency model), without forcing people into manually opting into boxing and/or reference counting on a per-reference basis.

                                                                                                                                                          Throw into that the pain of manual lifetime management (it's not always elided, and when it needs to change, it's painful), I honestly believe it's far more reasonable to ask programmers to throw shit into two or three arenas and then go hog-wild with references than it is to expect them to deal with the tediousness of the way Rust does things.

                                                                                                                                                          We are just cargo-culters (no pun intended).

                                                                                                                                                          • jayd16 3 days ago

                                                                                                                                                            I don't think that's fair. There's a lot less blue ocean these days. C++ could expand into virgin territory where Rust (or any new language) needs to fight against momentum.

                                                                                                                                                            • undefined 2 days ago
                                                                                                                                                              [deleted]
                                                                                                                                                          • readyplayernull 4 days ago

                                                                                                                                                            I find the C vs C++ battle amusing after having lived in the 90s and the Pascal/Delphi vs C/C++ holy wars.

                                                                                                                                                            • poincaredisk 4 days ago

                                                                                                                                                              Rust is a C++ replacement, but not a C replacement, for many C use cases. Language that may replace C is Zig.

                                                                                                                                                              • pwdisswordfishz 4 days ago

                                                                                                                                                                What are those use cases?

                                                                                                                                                              • undefined 4 days ago
                                                                                                                                                                [deleted]
                                                                                                                                                                • akkad33 4 days ago

                                                                                                                                                                  C++ is safer than C? How?

                                                                                                                                                                  • JTyQZSnP3cQGa8B 4 days ago

                                                                                                                                                                    You can write whole applications that compiles to the same assembly code without using any kind of memory management thanks to the destructors, smart pointers, and all the objects of the STL.

                                                                                                                                                                    • flohofwoe 4 days ago

                                                                                                                                                                      This just pushes the problem into the C++ stdlib, which has plenty of memory-corruption issues too but just calls it 'undefined behaviour' (see things like dangling std::string_view, missing range checks in containers or iterator invalidation). In C you avoid those issues by reducing dynamic memory allocations to a minimum, prefering value types over reference types and using function APIs as 'safety boundaries' (instead of directly poking around in random data). Different approach, but not any less safe than C++.

                                                                                                                                                                      • vlovich123 4 days ago

                                                                                                                                                                        > In C you avoid those issues by reducing dynamic memory allocations to a minimum, prefering value types over reference types and using function APIs as 'safety boundaries'

                                                                                                                                                                        "In Rust that's just pushing the problem to the borrow checker and codegen which has plenty of memory corruption issues too but just calls it "bugs". In C++ you avoid those issues by reducing dynamic memory allocations to a minimum, and using checked APIs as 'safety boundaries' instead of directly poking around random arrays. Different approach but not any less safe than C++".

                                                                                                                                                                        Both statements are pretty ridiculous. It's pretty clear that moving up in terms of the safe abstractions that are possible makes your code safer because the safety is there when you reach for that kind of programming paradigm & the programming paradigms you need are typically a property of the problem domain rather than the language (it's it's the intersection of "how is this problem solved" and "what tools does the language give you"). In C it gives you few tools and you either twist into a pretzel trying to stick to that or you write our own tools from scratch every time and make the same but different mistakes over and over. No language is perfect and all will guide you to different takes on the same problem that better suit to its paradigm, but there are intractable parts that will force you to do things (e.g. heap allocation and more involved ownership semantics are not uncommon). Moreover C very limited ability to manage your own codebase to define API boundaries - the only tool is opaque types with a defined set of functions declared in 2 different files.

                                                                                                                                                                        • uecker 4 days ago

                                                                                                                                                                          The opaque types in C are great though. And because no info leaks via header, you have very fast compilation. The y"ou write from scratch every time" is a weird statement. I do not delete my own code after each project and there exist plenty of libraries.

                                                                                                                                                                    • UebVar 4 days ago

                                                                                                                                                                      Somewhat separating owning and non owning memory in the type system goes a long way. Also a much better standard library and a stricter typing discipline.

                                                                                                                                                                      The fact that it's mostly backwards compatible means you can reproduce almost all issues of c in c++ awell, but the average case fares much better. Real world C++ does not have double-frees, for example. (As real world C++ does not have free() calls).

                                                                                                                                                                • wild_pointer 4 days ago

                                                                                                                                                                  "In addition, there are some variables such as locks and scope_guards that are only used for their side effects"

                                                                                                                                                                  ...

                                                                                                                                                                  "This solution is also similar to other languages’ features or conventions"

                                                                                                                                                                  As far as I know, in Rust you can't use "_" for that, as the value will be dropped right away, so the mutex/resource/etc. won't live for the scope.

                                                                                                                                                                  • awestroke 4 days ago

                                                                                                                                                                    No, it lives until the end of its last scope regardless of name

                                                                                                                                                                    • tialaramex 4 days ago

                                                                                                                                                                      This is not a name, it's the specific choice not to assign it to any name, and so your parent was correct that it's dropped immediately.

                                                                                                                                                                      https://rust.godbolt.org/z/P1z7YeP4Y

                                                                                                                                                                      As you see, Rust specifically rejects this code because it's never what you meant, either write explicitly "I want to take and then immediately give away the lock" via drop(LOCK.lock()) (this really might be what you wanted, the Linux kernel does this in a few places) or write an actual named placeholder variable like in my third example function.

                                                                                                                                                                      • vlovich123 4 days ago

                                                                                                                                                                        But on the other hand the motivating problems noted in C++ don't exist. It is 100% legal to completely rebind a variable in the same scope, it never warns that `_` variables are unused nor about unused `_` prefixed variables. I think `_` being immediately dropped is maybe one of those unfortunate decisions we'll look back in 20 years and regret.

                                                                                                                                                                        • tempodox 4 days ago

                                                                                                                                                                          Ever heard of `-Wunused-variable`?

                                                                                                                                                                          > rebind a variable in the same scope

                                                                                                                                                                          But only re-assigning values of the same type. Otherwise:

                                                                                                                                                                            int x = foo();
                                                                                                                                                                            int x = bar();
                                                                                                                                                                            error: redefinition of 'x'
                                                                                                                                                                          and,

                                                                                                                                                                            int x = foo();
                                                                                                                                                                            long x = bar();
                                                                                                                                                                            error: redefinition of 'x'
                                                                                                                                                                          
                                                                                                                                                                          What are you talking about?
                                                                                                                                                                          • vlovich123 2 days ago

                                                                                                                                                                            In rust it’s perfectly legal to do

                                                                                                                                                                                let x = foo()
                                                                                                                                                                                let x = bar()
                                                                                                                                                                            
                                                                                                                                                                            Regardless of the return types. That obviates a lot of the motivating problem that the c++ paper is contorting itself to fix
                                                                                                                                                                            • tempodox a day ago

                                                                                                                                                                              Yes, borrowing some stuff from functional languages (like the ability to shadow variables) gave Rust a good boost in ergonomics.

                                                                                                                                                                        • SideburnsOfDoom 4 days ago

                                                                                                                                                                          > This is not a name, it's the specific choice not to assign it to any name

                                                                                                                                                                          Yeah, it's the same in c#. This is noticeable when in the same scope you can have multlple "_" vars. If these were actual names, they would be a name clash.

                                                                                                                                                                          One of the uses is take some parts of a tuple return and ignore the others.

                                                                                                                                                                          e.g.

                                                                                                                                                                          var (thingIwant, _, _, _) = FunctionThaReturnsATupleOfFourThings();

                                                                                                                                                                          There are three "_" in that expression, and they are different vars with different types. They don't really have the same name, they don't have names at all.

                                                                                                                                                                    • emcell 4 days ago

                                                                                                                                                                      every time i see stuff like this, I hope I never have to work on c++ projects again.

                                                                                                                                                                      • Kenji 5 days ago

                                                                                                                                                                        [dead]

                                                                                                                                                                        • ulbu 4 days ago
                                                                                                                                                                          • wiseowise 4 days ago

                                                                                                                                                                            Not every "problem" needs a solution.

                                                                                                                                                                            At this point only LLMs will be able to decipher every intricacy of C++.

                                                                                                                                                                            • devnullbrain 4 days ago

                                                                                                                                                                              I swear some of you read 'C++' in the submission title and immediately assume it's tagging on inscrutable, additional ways of doing things. This is making C++ code _less_ intricate.

                                                                                                                                                                              • lionkor 4 days ago

                                                                                                                                                                                No, they cannot, they are word prediction machines.

                                                                                                                                                                                • tempodox 4 days ago

                                                                                                                                                                                  What a wise display of complete ignorance.