September 27
On Friday, September 27, 2024 2:13:45 PM MDT thinkunix via Digitalmars-d-learn wrote:
> monkyyy via Digitalmars-d-learn wrote:
> > On Friday, 27 September 2024 at 04:23:32 UTC, thinkunix wrote:
> >> What about using 'auto' as the return type?
> >> I tried it and it seemed to work OK.
> >>
> >> Wondering if there are any good reasons to use auto,
> >> or bad reasons why not to use auto here?
> >
> > You have started a style debate that will last a week, great work
>
> That was not my intent.  It was an honest question.  I'm here to learn and not looking to start debates or for attitude.
>
> I've seen a lot of "use auto everywhere" especially in C++ and was wondering where the D community stands on it's use.  Is it generally favored or not?
>
> Personally, I think auto makes understanding code harder for humans. But in this example, it seemed like auto was a good fit.

Well, I don't think that auto is a particularly controversial topic among D programmers, but there's no question that in at least some cases, it becomes a question of preference and style.

auto is used heavily in D, and for some kinds of code, it has to be. In particular, range-based code routinely returns "Voldemort" types (types which you can't name) from a function. You care that it's a range (so that needs to be clear from the documentation), but you're not supposed to know or care what the actual type is. Before we had that, the signatures for a lot of range-based functions (e.g. most of std.algorithm) were actually pretty terrible to read and understand, because the explicit types were so long and messy (since it's very common for ranges to wrap one another, and they're usually templated). In a lot of those situations, you really only care about the API of the type and not what the exact type is. So, auto simplifies the code considerably and makes it easier to understand.

auto is also pretty critical in generic code in general, because it allows you to not worry about the exact type you're dealing with. You just need to worry about which kinds of operations work with that particular type. So, variables get declared as auto all the time in typical D code. A lot of D programmers will only use the type explicitly with variables if they want to force a particular type or if they think that it makes that code easier to understand.

auto can also make code more maintainable in that when refactoring code, the type will update automatically, so if it changes, you don't have to change it all over the place. On the flip side though, it does make it harder to know what types you're dealing with, which can sometimes make it harder to read and maintain code. So, when auto isn't actually needed, there's always going to be some debate about whether it's better to use auto or not, and that's subjective enough that you're really going to have to decide on your own what works for you.

Also, for better or worse, because the function has to be compiled to determine the actual return type (so it won't work with function prototypes like in .di file), function attributes are inferred for auto return functions just like they are for templated functions, so some D programmers will make functions auto just to get the attribute inference.

I would guess that as a general rule, most folks prefer explicit types in function signatures where auto isn't needed simply because it's self-documenting at that point. So, I would think that most D programmers would use an explicit type with the function being discussed in this thread, but auto will certainly work just fine. Without any explicit casts within the function, because doing math on char or ubyte results in int, the result is going to be int (as opposed to uint like in the original post). So, if that works for what the function is intended for, and the documentation is clear about what's being returned, then it's not a problem.

However, in this particular case, it's arguably better to return ubyte than int or uint. That's because the result will always fit within a ubyte, and if you don't return a ubyte, the caller is going to have to cast to ubyte to do something like assign the value to a ubyte. So, simply returning auto as-is arguably isn't desirable. That being said, you can still use auto if you want to. Because the math results in int, casts to ubyte will be required regardless of whether the return type in the signature is ubyte or auto, but you could choose to use auto and have the result be ubyte thanks to the casts.

Ultimately though, I would argue that in this case, auto just makes the code harder to understand. The documentation can easily say that the return type is ubyte in spite of it saying auto, but it's just as easy to type ubyte, and then the return type is immediately obvious instead of requiring additional documentation just to say what's being returned. So, while auto is used quite heavily in D code, I wouldn't expect many folks to choose to use auto for this particular function.

- Jonathan M Davis



September 27
H. S. Teoh via Digitalmars-d-learn wrote:
> In idiomatic D, you'd use `auto` when either (1) you don't care what the
> type is, you just want whatever value you get to be shoved into a
> variable, or (2) you *shouldn't* care what the type is, because your
> code shouldn't be depending on it, e.g., when you're using Voldemort
> types std.algorithm-style.

Thank you!  That was a very helpful response.
September 27
Jonathan M Davis via Digitalmars-d-learn wrote:
> Well, I don't think that auto is a particularly controversial topic among D
> programmers...

Thank you Jonathan for that very detailed response.

This thread can end now unless others really feel the need to comment.
I got two outstanding responses and now have a much better understanding
of why and when to use auto.
September 28

On Friday, 27 September 2024 at 20:28:21 UTC, H. S. Teoh wrote:

>

...
The reason for (2) is that in UFCS chains, the only thing you really only care about is what kind of range it is that you're dealing with, and maybe the element type. What exactly the container type is, is unimportant, and in fact, stating it explicitly is detrimental to maintenance because the library that gave you that type may change the concrete type in the future while retaining the same range and element type. So by naming an explicit type for the range, you introduce a potential needless breakage in your code when you next upgrade the library. Instead, use auto to let the compiler figure out what the concrete type is, as long as it conforms to the expected range semantics and has a compatible element type, your code will continue to work as before.
...

Once my range didn't work because I used auto instead of bool in the standard InputRange functions (I think it had something to do with length() too...). As I said, I'm not sure, it could also be size_t length(). So there are subtle cases where we should use auto, I wish I could show you but I can't think of any.

SDB@79

1 2
Next ›   Last »