Thread overview
Switch between two structs with csvreader
Nov 05, 2020
Selim Ozel
Nov 05, 2020
Anonymouse
Nov 06, 2020
Selim Ozel
Nov 06, 2020
H. S. Teoh
Nov 07, 2020
Selim Ozel
November 05, 2020
Hi There,

I am trying to switch between two structs as I am using the csvReader on a raw string. The pseudo-code below throws a "cannot implicitly convert" error due to difference between struct_type1 and struct_type2. I must be doing something wrong or have a wrong understanding of how this function works. Could someone give a good suggestion on handling this?

Thanks!

Best,
Selim

auto records = rawtext.csvReader!struct_type1(';');
if(aControlCondition) {
records = rawtext.csvReader!struct_type2(';');
}

// Iterate through each data row.		
foreach (record; records) {
writeln(record);
}
November 05, 2020
On Thursday, 5 November 2020 at 21:18:52 UTC, Selim Ozel wrote:
> auto records = rawtext.csvReader!struct_type1(';');

D is statically typed and `auto` means "deduce this type for me based on this one function's return value". It is not like JavaScript's `var` whose type may change.

If I'm not mistaken the `csvReader` function returns a range struct, and the full type is something long and unwieldy like `CsvReader!(struct_type1, cast(Malformed)1, string, dchar, string[])`. So just think of `records` as being that.

(You can tell what type it is at compilation with `pragma(msg, typeof(records).stringof)`.)

> if(aControlCondition) {
> records = rawtext.csvReader!struct_type2(';');

Here `csvReader!struct_type2(';')` returns a value of type `CsvReader!(struct_type2, ...)`, which is a different type from that of `records` (and they're not implicitly convertible). So the error message is right. If `auto` worked like `var` your code would work, but it doesn't.

You need two different variables and two different `foreach`es. For the same code to work on both types, the easy solution is templates. Perhaps make the `foreach` part after the reads a templated function that accepts any type passed to it?

November 06, 2020
On Thursday, 5 November 2020 at 22:36:36 UTC, Anonymouse wrote:
> If I'm not mistaken the `csvReader` function returns a range struct, and the full type is something long and unwieldy like `CsvReader!(struct_type1, cast(Malformed)1, string, dchar, string[])`. So just think of `records` as being that.

I actually first going this route but couldn't figure out the correct name for that data type. It is quite long.

> You need two different variables and two different `foreach`es. For the same code to work on both types, the easy solution is templates. Perhaps make the `foreach` part after the reads a templated function that accepts any type passed to it?

Embedding the foreach loop inside a template function and deciding on the data type at the higher level function solved my issue. Thanks for the pointer!

Best,
Selim
November 06, 2020
On Fri, Nov 06, 2020 at 07:17:53PM +0000, Selim Ozel via Digitalmars-d-learn wrote:
> On Thursday, 5 November 2020 at 22:36:36 UTC, Anonymouse wrote:
> > If I'm not mistaken the `csvReader` function returns a range struct, and the full type is something long and unwieldy like `CsvReader!(struct_type1, cast(Malformed)1, string, dchar, string[])`.  So just think of `records` as being that.
> 
> I actually first going this route but couldn't figure out the correct name for that data type. It is quite long.
[...]

You can use the typeof() operator to capture the type of a long, unwieldy type in an alias. This is useful if you ever need to store such a return type somewhere, e.g.:

	alias T = typeof(csvReader(...));

	struct MyStorage {
		T result;
	}

	MyStorage s;
	s.result = csvReader(...);

Let the compiler figure out the type for you. :-)


T

-- 
Guns don't kill people. Bullets do.
November 07, 2020
On Friday, 6 November 2020 at 19:35:47 UTC, H. S. Teoh wrote:
> You can use the typeof() operator to capture the type of a long, unwieldy type in an alias. This is useful if you ever need to store such a return type somewhere, e.g.:
>
> 	alias T = typeof(csvReader(...));
>
> 	struct MyStorage {
> 		T result;
> 	}
>
> 	MyStorage s;
> 	s.result = csvReader(...);
>
> Let the compiler figure out the type for you. :-)
>
>
> T

That's great, thanks!

S