Thread overview
auto keyword
Jan 30, 2020
Michael
Jan 30, 2020
Jonathan M Davis
Jan 30, 2020
H. S. Teoh
January 30, 2020
auto is surely a nice feature. Nonetheless I'd prefer to use explicit types. So when reading a code and I see the auto keyword I also have to find out what kind of type is meant.

I have a line of code that looks like this:
auto elements = buf.to!string.strip.split(" ").filter!(a => a != "");

That line strips white space from buf, splits it, removes empty elements and returns an array of strings. At least I thought so.

Indeed elements can be treated as a string slice, but if i replace auto by string[] the compiler complains:
Error: cannot implicitly convert expression filter(split(strip(to(buf)), " ")) of type FilterResult!(__lambda1, string[]) to string[]

In order to use an explicit type I wonder what kind of type I might use instead of auto?
January 30, 2020
On Thursday, January 30, 2020 2:37:40 AM MST Michael via Digitalmars-d-learn wrote:
> auto is surely a nice feature. Nonetheless I'd prefer to use explicit types. So when reading a code and I see the auto keyword I also have to find out what kind of type is meant.
>
> I have a line of code that looks like this:
> auto elements = buf.to!string.strip.split(" ").filter!(a => a !=
> "");
>
> That line strips white space from buf, splits it, removes empty elements and returns an array of strings. At least I thought so.
>
> Indeed elements can be treated as a string slice, but if i
> replace auto by string[] the compiler complains:
> Error: cannot implicitly convert expression
> filter(split(strip(to(buf)), " ")) of type
> FilterResult!(__lambda1, string[]) to string[]
>
> In order to use an explicit type I wonder what kind of type I might use instead of auto?

For code like that, you don't. A lot of code in D - especially code that uses ranges - uses what are called Voldemort types. They are declared inside the function and you have no access to them. They follow a known API, so you know what to do with them, but you they have no name that you have access to. Realistically though, even if you had access to the type's name, you wouldn't want to use it explicitly anyway, because usually, it's a templated type which is instantiated with another templated type and is likely several layers deep. Using the explicit names would be hideous. Years ago (before we had Voldemort types), there was a bug in ddoc that made functions that returned auto not show up in the documentation. So, all of std.algorithm returned explicit types, and they were so hideous that it just scared people. It works _far_ better to just understand how to use these types and not use their names explicitly. It also makes the code far more resilient to changes, since as long as the return type retains the same API, it doesn't matter how the return type is changed. A function like filter could have its return type changed to something else, and the code calling it wouldn't care so long as it was the same kind of range.

Since you probably aren't familiar with ranges in D (or you wouldn't be trying to use them by name), I suggest that you read this:

http://ddili.org/ders/d.en/ranges.html

And in addition to the fact that you pretty much have to use auto with range-based code, you're pretty much going to have to get used to dealing with D code using auto heavily, because that's what most D code does. Certainly, sometimes, you can use type names explicitly, but it's common practice to use auto most of the time. It can take a bit of getting used to, but ultimately, it actually results in more maintainable code.

- Jonathan M Davis



January 30, 2020
On Thu, Jan 30, 2020 at 09:37:40AM +0000, Michael via Digitalmars-d-learn wrote: [...]
> auto elements = buf.to!string.strip.split(" ").filter!(a => a != "");
> 
> That line strips white space from buf, splits it, removes empty elements and returns an array of strings. At least I thought so.

If you want an array of strings, just add .array to the end, and you will get string[] back.


> Indeed elements can be treated as a string slice, but if i replace
> auto by string[] the compiler complains:
> Error: cannot implicitly convert expression filter(split(strip(to(buf)), "
> ")) of type FilterResult!(__lambda1, string[]) to string[]

That's because the actual type is a lazily-evaluated range.


> In order to use an explicit type I wonder what kind of type I might use instead of auto?

In this case, you actually can't spell out the type, because it's a Voldemort type (it's only defined inside the function that constructs it, and is not directly nameable outside).  Usually, a Voldemort type is returned when you *shouldn't* be referring to it with an explicit type. For example, in this case, if what you really want is an array of strings then you should add .array at the end to get a string[].

If you wish to store the lazy range, for whatever reason, you can use
the typeof() operator to extract a type from it (without actually
spelling it out -- because you can't):

	auto elements = buf.to!string.strip.split(" ").filter!(a => a != "");
	alias E = typeof(elements);
	E x;
	x = elements;

Usually this is only useful if you wish the store the lazy range inside some kind of aggregate type while retaining its lazy evaluation semantics.  But if you expect it to be eagerly evaluated anyway, there's no need to jump through hoops to get at the type of `elements`; just stick .array to the end of it and get a string[] back.


T

-- 
"The whole problem with the world is that fools and fanatics are always so certain of themselves, but wiser people so full of doubts." -- Bertrand Russell. "How come he didn't put 'I think' at the end of it?" -- Anonymous