www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - auto keyword

reply Michael <michaelhusmann gmail.com> writes:
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?
Jan 30 2020
next sibling parent Jonathan M Davis <newsgroup.d jmdavisprog.com> writes:
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
Jan 30 2020
prev sibling parent "H. S. Teoh" <hsteoh quickfur.ath.cx> writes:
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
Jan 30 2020