10 ms·
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. Ma
by carom 2y 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.
- kgeist 2y agoMy 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.
- JTyQZSnP3cQGa8B 2y agoThe 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 2y agoIt 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/slang.h https://github.com/shader-slang/slang/blob/master/include/sl...
- JTyQZSnP3cQGa8B 2y agoIt 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 2y 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 2y 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 2y 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 2y agoPragma 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
- cjfd 2y agoI 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.
- deleted 2y ago[deleted]
- Too 2y agoEvery 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.
- dgfitz 2y agoWasn’t typescript created to fix this problem for JS?
- jeremyjh 2y agoUsing `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.
- maccard 2y agoEven for the non ide folks - vim emacs and vs code all have excellent support for that.
- ranger_danger 2y agoHow does vim support this? I thought you had to use custom scripts/extensions to do it?
- maccard 2y agoSorry I wasn’t clear - all those editors have simple (ish) plugins that support it
- UebVar 2y agoIf 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.
- alexvitkov 2y agoYou 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 2y ago> You should never write code that's impossible to understand without fancy IDE features with Rust that ship has sailed
- jeltz 2y agoI 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 2y agoRust 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.
- readyplayernull 2y agoIsn't inline more "undeterministic" than auto? That is way older and used everywhere. I'd like auto functions.
- jayd16 2y agoIsn't it mostly meaningless outside of the syntax sugar of putting code in the header?
- FpUser 2y agoI 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.
- deleted 2y ago[deleted]
- secondcoming 2y agoExcept this makes a copy of each member in set_of_members, which is probably not what you want. https://godbolt.org/z/1YnEs1M34 https://godbolt.org/z/1YnEs1M34
- FpUser 2y agoThis 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.
- zabzonk 2y agoComplicated 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.
- jcelerier 2y agoI 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 2y 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 2y agoPlus 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 2y agoOne approach is use auto while coding, auto convert to full types when finalizing/commiting except where they hurt readability.
- nly 2y agoIt'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.
- AlotOfReading 2y agoEditor type deduction is surprisingly unreliable sometimes.
- ninkendo 2y agoWhat 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 2y agoFwiw, 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.
- ranger_danger 2y agoI 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?
- ogoffart 2y agoEven 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.
- 2y ago
- Koshkin 2y 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 2y agoI’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 2y agoVerbosity is not bad. When it makes the code clearer, it is even a good thing.
- ithkuil 2y agoComplex 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();"
- dataflow 2y 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.
- benreesman 2y agoHerb Sutter has a pretty good explanation: https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style-almost-always-auto/ https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style...
- lairv 2y agoUsing auto in function parameters to have implicit templates is very cursed
- jayd16 2y agoI'm pretty supportive of auto and var, etc. in languages but parameters seem like a step too far.
- cesaref 2y agoI 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.
- MathMonkeyMan 2y agoI 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();
- pjmlp 2y agoProgramming without IDE is so 1970's... Having said this, I usually only use type inference when the types are obvious from context.
- jayd16 2y agoWas 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 2y agoauto 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.
- asveikau 2y agoThere'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.
- secondcoming 2y agoThat 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 2y agoI'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 2y ago> This could be mitigated with the name of foo() being more descriptive. welcome back Hungarian notation
- jeremyjh 2y agoauto conn = createConnection(); What does this have to do with hungarian notation?
- pests 2y agoYou’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!)
- maccard 2y agoIm 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 2y agoif you need tools it just means the code is sub-par
- maccard 2y agoGrep 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 2y agoIt's not perfectly correct, and that actually what makes it dangerous.
- orf 2y agoThat 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.
- nurettin 2y agoint wtf = omgtype(); // and read the compiler error
- ninkendo 2y agoThere’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 2y 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.
- DonHopkins 2y agoSome 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!
- ok123456 2y agoAuto 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.
- nox101 2y agoTypes are not enough to solve this issue https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
- fooker 2y agoLike 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 2y agoOh boy! A vector of tuples of vectors and ints? Crazy
- fooker 2y agoNesting standard library containers can get you neat data structures without much work
- junon 2y agoI don't know why I feel the urge to point this out but you missed an angle bracket :D
- fooker 2y agoThat's exactly why I'd use auto here!
- sour-taste 2y agoOne 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.
- summerlight 2y agoMy 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.
- musicale 2y 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 ;-)
- paulddraper 2y 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.
- RcouF1uZ4gsC 2y agoHonestly, 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.