16 ms·
One thing that really annoyed me about D is that its documentation lists basically every function with an 'auto' return type. Auto should be completely banned f
by F-0X 6y ago
One thing that really annoyed me about D is that its documentation lists basically every function with an 'auto' return type. Auto should be completely banned from documentation, it's a complete hindrance. It's the single biggest contributor to why I stopped using D for personal projects - I was so tired of having to hunt down what functions are going to return, sometimes having to resort to just using it and looking at what the compiler complains about.
And that's a huge shame. Because in general I really liked using D.
- WalterBright 6y agoYou don't have to wait for the compiler to complain. Using: pragma(msg, T); where T is any type will print the type to the screen during compilation. pragma(msg) will print all kinds of things, making it a very handy tool to visualize what is happening while compiling. I use it all the time.
- slezyr 6y agoPrint-debug you program before it's even compiled and even have a bug is a bag idea.
- arunc 6y agoWhy so?
- entropicdrifter 6y agoYou shouldn't need to reverse-engineer your own program just to understand the code you wrote yourself.
- pjmlp 6y agoApparently it is a common Go pattern to discover which interfaces a type implements.
- WalterBright 6y agoI salute those who never have to debug their own code :-)
- ahartmetz 6y agoUgh, that is even more ill-advised than using auto without good reason in C++.
- MaxBarraclough 6y agoIn the interests of perpetuating this endless flamewar, here's Herb Sutter saying C++ programmers should use auto 'by default'. (I see my snarky comment there got no reply.) https://softwareengineering.stackexchange.com/a/180616/ https://softwareengineering.stackexchange.com/a/180616/
- jfkebwjsbx 6y agoHerb Sutter is biased. He works on C++ language lawyering, he works on new features, he works in the STL, etc. People like him tend to be biased about using auto because they write mostly libraries and generic ones at that (data structures, for instance). In most code out there you actively avoid templates if possible, so that code is concrete, compiles faster and is easier to debug.
- dirtydroog 6y agoBingo! Writing a template library is totally different to writing an application.
- Koshkin 6y agoWell, there's two ways to write an application, analogous to two styles in mathematics as described by A. Grothendieck. http://www.landsburg.com/grothendieck/mclarty1.pdf http://www.landsburg.com/grothendieck/mclarty1.pdf
- Koshkin 6y agoIn the context of C++, the use of auto allows to avoid unintended type conversions during initialization.
- GoblinSlayer 6y agoAnother reason for C/C++ is that they are very permissive with implicit lossy conversions. If you specified explicit type, chances are the compiler helpfully made a lossy conversion for you.
- JoeAltmaier 6y agoMore a failure of documentation/tools? We've been content for a decade to just name the arguments and return without any context. Like the old joke "Where am I?" answered by "In a hot air balloon!". Correct but useless. I wonder if the document could describe (in some regular way) how those auto types are constructed...from what input, with what operations?
- WalterBright 6y agoThey already do.
- acehreli 6y agoI've been using D since 2009 both personally and professionally. 'auto' return did bother me in a few places but it never came close to being a deal breaker.
- WalterBright 6y agoIt's helpful to bring up issues you are encountering in the D forums. This is the first I've heard of this particular one.
- anaphor 6y agoI had this issue last year when I started learning D. I eventually got used to it, but it was a stumbling block at first. The #d IRC channel helped me out.
- bachmeier 6y agoIt's been raised many times before. By me and numerous others. The standard library is generic, which isn't the end of the world, but you can't tell from the documentation how you can work with the output. It's common for someone to ask a question and be told "add .array to the output". They'd never know that after reading the documentation.
- WalterBright 6y agoReading the example code in the documentation is very helpful with this.
- aldacron 6y agoAnd the "Returns:" section!
- p0nce 6y agoIt's often because these functions have unnamed types. Chain of lazy computations in D often return unnamed types (so called "Voldemort" types) because finding good names for those inner structs is a challenge, they have a single use (which is to have a particular signature).
- Konohamaru 6y ago> Chain of lazy computations in D often return unnamed types (so called "Voldemort" types) because finding good names for those inner structs is a challenge There is something so absurd about having "unnamed types" as an antipattern!
- p0nce 6y agoNot everything is worth naming, if there isn't an obvious good name for somethink (like say, a Java Anonymous Classes) then why not allow it to have no name?
- Konohamaru 6y agoJava's objects aren't types even though they're mixed up with its type system. Objects are supposed to represent units of computation so anonymous classes aren't absurd. But the reason why it seems that types without names are absurd is that types are only real for the interpreter or compiler. At runtime they aren't used anymore. So it's absurd that a construct made for humans to understand and describe code starts to become something opaque to human understanding because they're impossible to be named.
- atilaneves 6y agoNot really - the concrete type isn't important, but what you can do with it is. One could argue that instead we'd use a concept in place of `auto`, and Bjarne has argued exactly that for C++.
- masklinn 6y ago> Not really - the concrete type isn't important, but what you can do with it is. Then surely that's what should be shown? Rust uses `impl <Trait>` for that, the actual return type is opaque but you know it implements the specified trait.
- pansa2 6y agoI think it’s really interesting that as dynamically-typed languages increasingly encourage explicit type hints, statically-typed languages are recommending “almost always auto”.
- logicchains 6y agoIn dynamically typed languages, adding types can stop things blowing up at runtime. In compiled languages, all the type-inference is still done at compile time, so if it compiles than you're not going to get a crash from accidentally adding a string to an integer at runtime.
- Koshkin 6y agoThe template language is weakly typed and code written in it, too, can “crash” when it runs (which is the compilation time) for the same reasons.
- gmueckl 6y agoThe use of Auto is requires in some places because the standard library returns types that cannot be named in the context of the calling function. This happens for example with algortihms that return a custom Range implementation that is declared within the scope of the function implementing the algorithm. I am not sure what to make of this pattern. At least the documentation should be more explicit about these Voldemort types. Documentation has other issues as well. The standard documentation generator doesn't cope well with version statements (conditional compilation), potentially skipping docs for stuff that wouldn't be compiled into a particular build variant.
- fluffything 6y agoI'm glad that Rust has no `auto`. I find this: fn map<U, T, F, I>(it: I) -> impl Iterator<Item=U> where I: Iterator<Item=T>, U: From<T> { it.map(|t| From::from(t)) } infinitely more readable than fn map<U, T, F, I>(it: I) -> auto where I: Iterator<Item=T>, U: From<T> { it.map(|t| From::from(t)) } The type signature of the first one clearly tells me that the return type is an `Iterator<U>`, even though the actual type cannot be named because of the anonymous closure. The second one leaves me guessing what the return type is. If the actual type cannot be named, it is rarely the case that this is all there is to it. Usually, users are expected to use that type "somehow" (it is a `Range`?), and that means that there are some interfaces that these types implement.
- EvenThisAcronym 6y agoRust does have auto; "let" and function literal parameter type inference, for a start. It just doesn't let you use it in the return type position.
- kibwen 6y agoThat's the salient point of this thread though; Rust doesn't have type inference in any position that shows up in API documentation. (The closest thing Rust has is return types of `impl Trait`, but even that imposes a contract that the caller must adhere to and that the callee cannot see through.)
- logicchains 6y ago>so tired of having to hunt down what functions are going to return, sometimes having to resort to just using it With highly generic functions, it's often not possible to know what they'll return without knowing what you'll call them with. Especially given that D functions like "map" and "reduce" tend to return special iterator types so that the compiler is able to smarty fuse them where possible. If D had concepts like C++20, you could probably describe them with something looking like: template<class R> concept __SimpleView = // exposition only ranges::view<R> && ranges::range<const R> && std::same_as<std::ranges::iterator_t<R>, std::ranges::iterator_t<const R>> && std::same_as<std::ranges::sentinel_t<R>, std::ranges::sentinel_t<const R>>; But at least for me that doesn't seem like it would be much more helpful than just reading the documentation, which states what the function returns, if not necessarily the type.
- rowanG077 6y agoSo you still can see that it depends on some input. That is hugely more useful then auto.
- asdkjh345fd 6y ago>With highly generic functions, it's often not possible to know what they'll return without knowing what you'll call them with. Of course it is. Map's type is "(a -> b) -> [a] -> [b]". D just absolutely and completely failed here, despite this being a solved problem 40 years ago.
- neutronicus 6y agoIt doesn't have to be specialized to []
- asdkjh345fd 6y agoOf course not. But it still has a type. Functor f => (a -> b) -> f a -> f b
- jcelerier 6y ago
- skocznymroczny 6y agoPersonally I dislike var/auto in languages because I like having types explicitly written. But in case of languages like Java or Kotlin you can move the cursor over the variable name and you will see the type, also you can right-click and select "replace with explicit type" and it will work. In D, IDEs struggle with templates and can rarely index templated code (no wonder, because most of the code doesn't exist until build time). Most people will tell you, "oh just use auto, it makes the code more generic". That's sweet, except as soon as I want to pass it to another function, I need to have the concrete type. Like you, I usually just copy-paste the full type from the error message and move on.
- stcredzero 6y agoPersonally I dislike var/auto in languages because I like having types explicitly written. But in case of languages like Java or Kotlin you can move the cursor over the variable name and you will see the type, also you can right-click and select "replace with explicit type" and it will work. In D, IDEs struggle with templates and can rarely index templated code (no wonder, because most of the code doesn't exist until build time). It's 2020. Why couldn't things work like this, where one can open a window for a concrete type using templates, and it shows the code?
- kevin_thibedeau 6y agoA well designed language should be usable from a text editor. Even in 2020.
- qqssccfftt 6y agoA good dev uses an IDE. In 2020.
- snazz 6y agoThis is a really tired argument that we don't need to get into right now. Different things appeal to different people.
- arunc 6y agoVim vs emacs, auto inference vs explicit, I don't think it will ever end. :)
- jbverschoor 6y agoAren't there any type synthesizers which modify your code based on inferenced types?
- thesuperbigfrog 6y agoIsn't that called weak typing? (https://en.wikipedia.org/wiki/Strong_and_weak_typing#Definitions_of_%22strong%22_or_%22weak%22 https://en.wikipedia.org/wiki/Strong_and_weak_typing#Definit...)
- jbverschoor 6y agoNo. I mean altering code to strong typing using type inference. So that auto becomes int, or MyClass*.
- lostmsu 6y agoIt already ended. VSCode and auto inference.
- takeda 6y agoI don't know D, but after reading more comments looks like auto is also compensating for poor type system. For example functions that accept arguments of many types apparently need to be declared that are returning auto. At least that's what I understood.
- jane_red 6y agoScala has a strong type system and when working with it on a daily basis I was not programming, I was thinking about types and fighting with the compiler. And that is the language which has a pretty decent IDE plugin. When I moved to D, it felt like a breathe of fresh air to me. Therefore, the whole talk above about auto and types looks like subjective nitpicking. In practice though, D codes fast and runs fast, as promised on the official site.
- dirtydroog 6y ago+1, I cringed when Herb Sutter released the 'Almost Always Auto' C++ presentation on YouTube. Sure, auto has its place, and I personally use it, but I just knew that less experience devs would go nuts with it, and it'd only make their lives easier for a short time.
- Koshkin 6y agoPlus, seeing the word 'auto' all over the place leaves a weird impression.
- thesuperbigfrog 6y agoIt lets C++ almost return to C-style duck typing. Whether that's really what you want and whether that is the best approach to solve the problem at hand is a matter of preference and the problem space. It is also allows for a "gradual typing" approach that Dart 1 had.
- self_awareness 6y agoI've never programmed in D so I don't know, but from curiosity I wanted to check if what you write is true. However, I can't find any function that is declared as auto. Could you please paste some example of a function that has a return value which is declared as auto?
- F-0X 6y agoThe major examples are parts of the stdlib which offer higher-level pipelines (some answers here indicate the need for such things to be very flexible in their return values to allow this, but this is not a priori obvious - Java manages similar functionality with just the Stream<T> class after all). In this (and the sibling pages in algorithm) nearly every entry is listed as either "template" or "auto" relhttps://dlang.org/phobos/std_algorithm_iteration.html https://dlang.org/phobos/std_algorithm_iteration.html
- aldacron 6y agoD's classes and interfaces are much like Java's, so it's possible and easy to write functions that express return types like that. It's also quite restrictive for generic programming. D's metaprogramming features are much more powerful. That means a template can return different types that do not conform to a single, easily-expressed interface. The std.algorithm package is built on that concept.
- takeda 6y agoMaybe it was fixed? I would imagine that saying in documentation that return type is auto is equivalent to not mentioning return type at all, so feels like something not intentional.
- masklinn 6y ago> Maybe it was fixed? It wasn't. They probably didn't look into the more "generic" functions e.g. hofs and algorithms. The vast majority of functions in https://dlang.org/phobos/std_algorithm_iteration.html https://dlang.org/phobos/std_algorithm_iteration.html returns "auto"
- stevefan1999 6y agoWell, not everyone likes automatic type deduction -- some people just like to torment him/herself by repeating information that is unneeded. Why?
- Koshkin 6y agoSometimes when reading a long passage in a novel you need a reminder who "he" is.
- throwaway894345 6y agoType inference systems generally have crumby error messages, and are harder to reason about all around. The best type inference systems are those that allow inference within a function definition, but the function signature requires explicit annotation. This keeps the inference local, which is easier for humans to read about. Good tooling can make either system easier to work with, but tooling is much less important in the type annotation case because the cost of adding annotations is trivial (contrary to your "torment" vocabulary) compared to reasoning about (non-local) type inference. In general, this reduces to the principle that concrete is easier to reason about than abstract. The type signature of an unannotated function in a type inference system is maximally abstract, while (especially in practice) the signatures for functions that are manually annotated are more concrete if not fully concrete. There are still problems in non-type-inferred systems with programmers who try to be egregiously abstract, but these are fewer and farther between.
- schveiguy 6y agoSometimes I feel like auto is definitely overused. In a recent fix, I changed something that returned a boolean (no templates involved) from returning auto to returning bool. But sometimes auto is the best tool for the job, especially when writing wrapping types. In that case, yes, you have to read the documentation (and I mean what is written in the ddoc comments). But in many cases, you don't have to, because you recognize the pattern, or it's simply a wrap of the underlying type's function.
- lumberjackstian 6y agoI've felt this as well, been using D for a couple years now, and this is the kind of thing that just makes me have to context switch more than I'd like. With the current implementation of the language it's hard to avoid, and function's return type can be quite complex, so writing it down can be hard. Another reason is the (ironically) dynamic nature of a return type. E.g. auto whatDoesItReturn(int i)() { static if (i == 0) { return int.init; } else { return string.init; } } Template code can do that quite easily and then you don't have a choice but to write auto as the return value. What would be fantastic if the documentation could be given access to the the compiler's return type inference, so that it could document the auto returns with a little more info. Another way useful approach would be to implement protocols like in swift, or traits like in scala/rust/others, signatures in ml, etc. Then you would be able to define the interface of what a function returns.
- RandallBrown 6y agoWhat would be the return type of that? Does D have an Either type?
- lumberjackstian 6y agoDepends on the value of the template parameter. If it's 0 the return type is an int, if it's not 0 the return type is a string. There's a wanting implementation of a sumtype in the standard library (https://dlang.org/phobos/std_variant.html#.Algebraic https://dlang.org/phobos/std_variant.html#.Algebraic), and a much better one as a package: https://code.dlang.org/packages/sumtype https://code.dlang.org/packages/sumtype
- RandallBrown 6y agoInteresting, so the return type isn't known until runtime.
- lumberjackstian 6y agoWhen it comes to templates it's not until instantiation time - when the compiler see the code being used. So this is just an issue during compilation. The docs on static if may shed some more light: https://dlang.org/spec/version.html#staticif https://dlang.org/spec/version.html#staticif
- jimbob45 6y agoI vehemently disagree. Auto/var is a tool that may be used judiciously by your userbase. This new philosophy of blocking your users from using dangerous tools because you know better than them just invites workarounds and kludges. Give the user the tools and warn them of the ways it can go wrong. There's a reason Rust is losing the war to C++. Anyways, var/auto is critical in some cases. C#'s LINQ, for example, would be very difficult to develop with if you had to manually figure out the type you were returning with long queries every time you wanted to restructure your query.
- z3t4 6y agoIm annoyed that you have to spell out auto all over the place. It should be implicit. The compiler should automatically add auto if you have not specified something else.
- underthensun 6y agoI really hate the auto keyword but as I like D so much, I kinda get used to it.