7 ms·
I don't really use auto unless I'm interfacing with some templatized nightmare body of code where the typename is very difficult for my tiny human brain to inte
by jschwartzi 8y ago
I don't really use auto unless I'm interfacing with some templatized nightmare body of code where the typename is very difficult for my tiny human brain to interpret. Using "auto" is usually a code smell, because it means your type system is too complex for you to reason about.
- scarface74 8y agoThis is a valid, strongly typed C# object: var foo = {bar = 1, baz = “Hello”, boo = “World”}; You get auto complete help and compile time type checking. foo.bar = “Goodbye”; Won’t compile. What would it buy you to not use ‘var’ and create a one time use class/struct?
- maxxxxx 8y agoI use auto almost always. Makes the language "feel" more dynamic but you still have type safety.
- gmueckl 8y agoIt would make me ask why you need a one time use struct at all and probably remove it.
- scarface74 8y agoMore complicated example: var seniorMales = from c in customer where c.age > 65 && c.Sex == “male” select new {c.FirstName, c.Lastname, c.Age} foreach(var customer in seniorMales) { Console.WriteLine(customer.Firstname + “ “ + customer.Lastname); } Why would I create a class/struct for that use case? Side note: this is why I find ORMs in most languages besides C# useless. Here, “customers” can represent an in memory List, a Sql table or a MongoDB collection and the LINQ expression will be translated appropriately to the underlying query syntax. The “ORM” is integrated into the language and yes anyone can write a LINQ provider.
- gmueckl 8y agoThis us one of the cases where I would want you to write an explicit type for seniorMales. Reasoning about the LINQ expression is just complex enough that by not constraining its type to your expectations you can easily obscure a mistake in your thinking that would otherwise show up in the data types.
- scarface74 8y agoHow so? You couldn't pass the anonymous type to another method or return it so the locality would be strong and the anonymous type is just a strongly typed POCO. Creating a class doesn't add anything semantically. How do you feel about deconstructuring that is available in most languages?
- maxxxxx 8y agoI think the anonymous type is much better. It's type safe, you can easily see how it's defined but you don't pollute the rest of your code with one-off classes that make only sense within the function. If I had to review the code and saw an explicit type I would recommend an anonymous type.
- gmueckl 8y agoIt is not better. I don't know what type FirstName or Age is. Can Age be negative? Is FirstName an array of char or a string? Can FirstName be more than 10 characters long? It could be a double value for all I can tell from that line of code!
- scarface74 8y agoThe select statement is projecting the Customer type from either an external data source or an in memory source. That information wouldn’t be encoded into the POCO whether or not it was anonymous. Changing select new {...} to Select new SeniorPeople {...} wouldn’t give you any more information. At most if I was writing that as part of a repository class I would be sending you back an IEnumerable<SeniorPeople>. If you were to send me an expression to use in the where clause you would send me an <Expression<Func<SeniorPeople,bool>> You have no idea what that expression is going to be translated to until runtime. Either way, you are just working with non concrete Expression Trees that could be transformed into IL, SQL, a MongoQuery etc. All of the constrainsts would be handled by your data store. You don’t even know before hand whether you are iterating over an in memory list, or streaming from an external data source. I could switch out Sql Server for Mongo and you as the client wouldn’t be any the wiser. And we haven’t even gotten to the complication if the result set was the result of a LINQ grouping operation.
- maxxxxx 8y agoNot necessarily. The types may just have very long names. In C++ for iterating through STL container auto is a godsend. The types are very straightforward and easy to reason about but just long. for (auto it = s.begin(); it != s.end(); it++) { is much easier to write than for (vector<int>::iterator it = s.begin(); it!=s.end(); it++) {
- jschwartzi 8y agoI try to avoid using STL because it A) throws exceptions, B) has really convoluted type names, and C) dynamically allocates memory. These are all things you avoid in the embedded space.
- maxxxxx 8y agoMakes sense for embedded.
- gowld 8y agoAny use of templates has the same problem, including templates that are used to generate highly efficient static constants and non-branching-at-runtime code.
- llukas 8y agoExample? Templates (template metaprogramming) help to avoid exceptions. You can check invariants first and jump into efficient code.
- llukas 8y agoor almost like python: for (auto &element: s){ even better with structured bindings: for (auto [key, value]: map){
- jcelerier 8y agowhy we can't have nice things, in one comment. auto is not a code smell on the contrary, it is used when your type system is easy enough to reason about that you don't need to write the actual type.
- jschwartzi 8y agoIf it's so easy to reason about, why can't you just state the type of the variable? Doing so helps me understand what's popping out from the rvalue in assignment so that I can follow what your code is doing. If you're worried about spending time changing type names during a refactor, look at it instead as an opportunity to evaluate the correctness of the code in the context of your replacement type. Use of the auto keyword avoids doing that and as a result enables you to create new and exciting bugs in your code.
- jcelerier 8y ago> If it's so easy to reason about, why can't you just state the type of the variable? because : - easy to reason about and easy to type are two differents things - naming everything increases mental load > Use of the auto keyword avoids doing that and as a result enables you to create new and exciting bugs in your code. to the contrary, porting a lot of my code to use almost-always-auto did actually remove bugs in the form of silent type conversions happening - e.g. std::pair<std::string, int> instead of std::pair<const std::string, int> (yay memory allocations), bad fp conversions...