Thread overview | ||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
April 30, 2018 auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
I'll freely admit I haven't put a ton of thought into this post (never a good start), however I'm genuinely curious what people's feeling are with regards to the auto keyword. Speaking for myself, I dislike the auto keyword. Some of this is because I have a preference for static languages and I find auto adds ambiguity with little benefit. Additionally, I find it annoying that the phobos documentation relies heavily on auto obscuring return types and making it a bit more difficult to follow what is happening which gives me a bad taste for it. Having said, the thing that really started my thinking about this was this post I made: https://forum.dlang.org/thread/fytefnejxqdgotjkprpo@forum.dlang.org Where in order to declare a public variable for the RedBlackTree lowerBound/upperBound methods I had to fall back on using the ReturnType template to declare a variable. Jonathan was nice enough to point me in the right direction and maybe there's a way to do this without having to fall back on ReturnType. However this made be wonder if reliance on auto could discourage API writers from having sane return types. So I'm curious, what's the consensus on auto? |
April 30, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | On Monday, 30 April 2018 at 21:11:07 UTC, Gerald wrote:
> Speaking for myself, I dislike the auto keyword. Some of this is because I have a preference for static languages and I find auto adds ambiguity with little benefit. Additionally, I find it annoying that the phobos documentation relies heavily on auto obscuring return types and making it a bit more difficult to follow what is happening which gives me a bad taste for it.
I'm of the same opinion. I think auto (or var in other languages) obscures the types and requires an IDE to reveal what the real type is (hopefully the IDE can figure it out). But it seems we are in minority. Even Java is adopting auto (called var there) and everyone is cheering for that :)
|
April 30, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | On Monday, 30 April 2018 at 21:11:07 UTC, Gerald wrote:
> I'll freely admit I haven't put a ton of thought into this post (never a good start), however I'm genuinely curious what people's feeling are with regards to the auto keyword.
>
> Speaking for myself, I dislike the auto keyword. Some of this is because I have a preference for static languages and I find auto adds ambiguity with little benefit. Additionally, I find it annoying that the phobos documentation relies heavily on auto obscuring return types and making it a bit more difficult to follow what is happening which gives me a bad taste for it.
>
It takes some getting used to. Type inference is useful because often you don't care/know, or want to type out the full name of the type for every variable. It does, however, assume that the developer can also do type inference (when/if you need to know the type). When it's not clear what the type is by looking at the right-hand side perhaps the codebase has bigger problems.
functions that return auto are a bit odd IMHO, that is a feature unique to D. But I don't have a problem with type inference in general, all language have it including C#, C++, TypeScript, Rust...etc not that that is a good argument, but just that its something you have to get used to, because people will use the feature whether you like it or not.
|
April 30, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | On Mon, Apr 30, 2018 at 09:11:07PM +0000, Gerald via Digitalmars-d wrote: [...] > So I'm curious, what's the consensus on auto? Don't know what others think, but personally, it's one of the best things about D: all the safety of static typing, yet with the convenience of automatic type inference, so that I don't have to keep repeating myself. When I'm using chained range-based algorithms, I really do *not* want to have to name every intermediate type explicitly. That would be so cumbersome that the idiom would be essentially useless. Also, design by introspection. Dependence on explicit types is so last century. Design by introspection FTW! Decoupling your code from explicit types makes it more encapsulated, and gives you incentive to write more defensively, resulting in better, more change-resilient code. When an upstream library changes a return type, you can just recompile and go, rather than waste time patching the 150 different places where the explicit type was named. Let the machine do the work for you! As for ReturnType: I actually find it completely worthless. It adds needless template bloat, where typeof() (specifically, typeof(return)) would do just fine. And as for the documentation issue: either (1) the docs are b0rken and need to be rewritten because they didn't describe the returned type sufficiently well, in which case either the docs need to be fixed, or the library is poorly written and you should find another one; or (2) it is an indication that your code has extraneous dependencies on explicit return types and therefore is flaky and will break with the slightest upstream changes, in which case the code should be restructured and the needless assumptions / dependencies removed. T -- 2+2=4. 2*2=4. 2^2=4. Therefore, +, *, and ^ are the same operation. |
April 30, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Giles Bathgate | On Mon, Apr 30, 2018 at 09:31:48PM +0000, Giles Bathgate via Digitalmars-d wrote: [...] > functions that return auto are a bit odd IMHO, that is a feature unique to D. But I don't have a problem with type inference in general, all language have it including C#, C++, TypeScript, Rust...etc not that that is a good argument, but just that its something you have to get used to, because people will use the feature whether you like it or not. [...] To me, a function that returns auto is basically saying "you should not need to know, nor should you depend on, the dirty details of the actual return type". There's a time and place for that, and I don't recommend liberally sprinkling auto return types everywhere just for laziness' sake. But when it's used, it should be used for improving encapsulation, by reducing the leakage of implementation details of the return type, and limiting the calling code to using only agreed-upon properties (i.e., via documentation, contract, etc.) or introspection using static if (meaning that your code is explicitly checking for a certain property before using it, which is a good defensive design, and presumably will be able to handle the case where said property no longer holds). Basically, it's stepping away from the bad old practice of the caller code digging into the innards of your data types that were never meant for public use, and consequently you being locked into a particular implementation because changing said innards will break existing code, even if existing code isn't using the type "properly"; and stepping into a better world of more encapsulated and flexible code. It's stepping away from that old world of code depending on "undocumented features" and "hidden calls", to a better world of code that will Just Work(tm) even if the underlying library changes a return type, and code that can adapt itself to the return type by using introspection to discover what is/isn't available without hardcoding anything or making unfounded assumptions about what the return type has/doesn't have. T -- Music critic: "That's an imitation fugue!" |
May 01, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Monday, 30 April 2018 at 21:56:23 UTC, H. S. Teoh wrote: > On Mon, Apr 30, 2018 at 09:31:48PM +0000, Giles Bathgate via Digitalmars-d wrote: [...] [...] > > > T On Monday, 30 April 2018 at 21:56:23 UTC, H. S. Teoh wrote: [...] Appart from the good points Teoh has made, imagine you would have to statically type in for loops: foreach (i; items) writefln("%s", i); And, yeah, chainig would indeed be a PIA: auto items = myRange.filter!(a => a.length); Most of the time you don't really care about the exact type, only at the end of the block (e.g. it should be `string[]`). And the compiler always tells you about the types, e.g. something like "cannot implicitly convert `words` of type MapResult to string[]". And then, _at the end_, you can use something like items.array; to get `string[]`. I think the problem is not `auto`, the problem is thinking in old ways. If you think old-style Java where you declare loads of statically typed class variables at the beginning, then you're in trouble. But in order to use `auto`, you have to use a different approach. Java: String name; String address; int uiid; ... String getName() { return name; } [...] In D, you are more likely to use home made structs / ranges / tuples as return types that all have the same properties, so auto makes more sense (incomplete code): auto byUser(R)(R entries) { struct User { private { R entries; } this(R entries) { this.entries = entries; } @property bool empty() { return range empty? (true|false) } @property void popFront() { // e.g. entries = entries[1..$]; } @property auto front() { return whatever; // e.g. struct UserInfo { string name; size_t uuid; } } } return User(entries); } The struct `User` can perform whatever is necessary, it can be changed, even renamed but the return type will always conform to the range interface: empty, popFront, front, so the caller can be sure s/he can use it as a range. Also, the type of `entries` can change, but the code will still work. No need to redefine all the variables as a different type. Now auto users = entries.byUser(); can be whatever and you can perform other range based algorithms [1] auto herberts = entries.byUser.filter!(a => a.name == 'Herbert')...etc.etc. Imagine having to use handwritten static typing for that! [1] https://tour.dlang.org/tour/en/gems/range-algorithms |
May 01, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | On Monday, 30 April 2018 at 21:11:07 UTC, Gerald wrote: > I'll freely admit I haven't put a ton of thought into this post (never a good start), however I'm genuinely curious what people's feeling are with regards to the auto keyword. > > Speaking for myself, I dislike the auto keyword. Some of this is because I have a preference for static languages and I find auto adds ambiguity with little benefit. Additionally, I find it annoying that the phobos documentation relies heavily on auto obscuring return types and making it a bit more difficult to follow what is happening which gives me a bad taste for it. > clip > > So I'm curious, what's the consensus on auto? As some have pointed out, it certainly has value. For example, in functions returning ranges, etc. where you wouldn't want to have to write out the whole type. However, as an infrequent D user I admit I prefer to see the actual type where it is feasible, as I find 'auto' is a barrier to understanding to someone who isn't familiar with a particular piece of code. I would never use auto in place of a basic type. |
May 01, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | I'm a die-hard static typing fan, hate dynamic languages, heck I dont even like structural typing (ex, as used by D ranges). And that's exactly why I *love* auto. It lets you have static typing without turning programming into a 2000's-era C++/Java-style royal anti-DRY PITA. I also think auto is especially nice for NOT requiring a heavy-weight IDE, because it makes refactorings and type renaming much simpler. In the very rare case that I'm not clear what type a var is, first of all, that's usually a sign something else is wrong with the code, and secondly, that's trivially answered by tossing in a "pragma(msg, typeof(xxxx))". Now, all that said, using auto for a function signature's return type shouldn't usually be done, except in very careful, specific "voldemort type" kinds of situations (and even then, I dont see a real big point). |
May 02, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | I'm a die-hard static typing fan, hate dynamic languages, heck I dont even like structural typing (ex, as used by D ranges). And that's exactly why I *love* auto. It lets you have static typing without turning programming into a 2000's-era C++/Java-style royal anti-DRY PITA. I also think auto is especially nice for NOT requiring a heavy-weight IDE, because it makes refactorings and type renaming much simpler. In the very rare case that I'm not clear what type a var is, first of all, that's usually a sign something else is wrong with the code, and secondly, that's trivially answered by tossing in a "pragma(msg, typeof(xxxx))". Now, all that said, using auto for a function signature's return type shouldn't usually be done, except in very careful, specific "voldemort type" kinds of situations (and even then, I dont see a real big point). |
May 02, 2018 Re: auto: useful, annoying or bad practice? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Gerald | On Monday, 30 April 2018 at 21:11:07 UTC, Gerald wrote:
> So I'm curious, what's the consensus on auto?
For local variables, it's not an unalloyed good, but it is good. When I use Java, everything is explicit, and sometimes that's nice. In D, I think I overuse `auto` for local variables. Sometimes I find myself switching it out for an explicit type, just because I want the compiler to check that the right-hand side is of the type I expect (eg with numeric conversion rules).
For function return types, though? The consensus among Phobos devs is it's a "here be dragons" sign. It's a sign that there could be breaking changes to your code without warning if you use that return type in a nontrivial way. Of course, this isn't made clear anywhere, and they don't actually make these changes all that often.
But even for that purpose, it's broken. Like your example was basically:
RBRange!(RBNode!long*) divide(RedBlackTree!long tree, long pivot, bool first)
{
if (first) return tree.upperBound(pivot);
return tree.lowerBound(pivot);
}
If the range type were public, your code would work. If subsequently the Phobos devs needed to change the range type, they could provide an alias, and your code would still work. If they needed to change upperBound to return a different type than lowerBound, there's nothing they can do about it; your code is broken.
But since the return type for both functions is `auto`, they can tell you you were wrong to write that code and they were right to make it stop working.
|
Copyright © 1999-2021 by the D Language Foundation