D input: how-to (RFC)

Tyro[a.c.edwards] nospam at home.com
Mon May 11 04:34:28 PDT 2009


On 5/11/2009 2:35 PM, grauzone wrote:
> Tyro[a.c.edwards] wrote:
>> I am looking for a D version of scanf() but I'm sure there is no such
>> thing so I tried contrived one. I am sure I missed a slew of obvious
>
> There's readf() in std.stream. I think you have to use std.cstream : din
> to use it with stdin.

Thanks, but I'm trying to learn here... Hoping I can get a better
understanding of how things work or are supposed to work. I'll probably 
change it back from read() to get().

>
>> int read(/+File inFile = stdin,+/ A...)(out A a) /+Uncommenting results
>> in: Error: arithmetic/string type expected for value-parameter, not
>> File+/
>
> That would make inFile a template parameter, which obviously doesn't
> make sense with objects, and I guess File is an object. This should work:
>
> int read(A...)(File inFile, out A a)

OK... that works, but how would I set stdin as the default input "file"?

I tried: int read(A...)(out A a, File inFile = stdin) but the compiler 
hangs trying to compile it whenever I call read() using 50% of the CPU 
resource in the process.

>> { start:
>> auto data = stripr(readln());
>> auto input = split(data);
>>
>> string assign()
>> {
>> return
>> ` try {
>> if(a.length != input.length)
>> return -1;
>> a[i] = to!(typeof(t))(input[i]);
>> } catch (ConvError e) {
>> writeln("Invalid input!");
>> goto start;
>> }`;
>> }
>
> If the user types in too much or too less input, read() returns with an
> error (-1), and the caller has to deal with it.
> If the user typed in something unparseable, the function prompts an
> error and lets the user retry.
> This is inconsistent.

Got it... would it be better for the caller handles such problems or the 
compiler?

> Also, instead of using CTFE to return a const string, why not simply
>
> const assign = ` .... ` ;

tried that but kept tying "string assign = " and "auto assign = "; both 
of which kept failing until I placed it in a function. Thanks I have 
changed it to enum.

> You're using D 2.0, you probably have to replace "const" by "enum". I
> don't know.
>
> You use goto to retry. I'd replace it by a loop. If someone wants to
> argue with me if goto is or is not evil, go ahead.
>
>> foreach(i, t; a)
>> {
>> static if(is(typeof(t) == void))
>> {}
>> else static if(is(typeof(t) == bool))
>> {}
>
> bools can't be read? If the implementation is incomplete, there should
> be at least an "assert(false);", maybe even a "static assert(false);".

Got it. What value would you read for a bool though? to me it can be 
0||1, true||false, yes||no, etc... Would I simply use 0 && 1 and forget 
about the rest?

>> else static if(is(typeof(t) == byte))
>> mixin(assign);
>> else static if(is(typeof(t) == ubyte))
>> mixin(assign);
>> else static if(is(typeof(t) == short))
>> mixin(assign);
>> else static if(is(typeof(t) == ushort))
>> mixin(assign);
>> else static if(is(typeof(t) == int))
>> mixin(assign);
>> else static if(is(typeof(t) == uint))
>> mixin(assign);
>> else static if(is(typeof(t) == long))
>> mixin(assign);
>> else static if(is(typeof(t) == ulong))
>> mixin(assign);
>> /+static if(is(typeof(t) == cent))
>> mixin(assign);
>> static if(is(typeof(t) == ucent))
>> mixin(assign);+/
>> else static if(is(typeof(t) == float))
>> mixin(assign);
>> else static if(is(typeof(t) == double))
>> mixin(assign);
>> else static if(is(typeof(t) == real))
>> mixin(assign);
>
> Oh god, what the fuck! String mixins are the new #define! OK, at least

ROTFDWL - that was truly unexpected. Thanks.

> this reduces the code duplication, but the code duplication shouldn't be
> there in the first place.
>
> You could just throw all the types into a tuple, and then foreach() on
> it, checking for the type in each iteration.

Awesome... I didn't even think about that. Got it!

> Or just make a single giant if() statement to check for all types to!()
> supports (like if(is(typeof(t) == int) && is(typeof(t) == uint)...). In
> any case, you could reduce the number of is() parts by using isNumeric()
> from std.traits.
>
> Or find a way to check for to!() supported data types automatically (but
> I don't know to!() well enough if this is possible).
>
>> else static if(is(typeof(t) == ifloat))
>> a[i] = ifloat.max;
>> else static if(is(typeof(t) == idouble))
>> a[i] = idouble.max;
>> else static if(is(typeof(t) == ireal))
>> a[i] = ireal.max;
>> else static if(is(typeof(t) == cfloat))
>> a[i] = cfloat.max;
>> else static if(is(typeof(t) == cdouble))
>> a[i] = cdouble.max;
>> else static if(is(typeof(t) == creal))
>> a[i] = creal.max;
>
> What?

That's a residue of my first try... I will take care of those. I really 
should have replaced those with "assert(false);" because I didn't 
understand how to implement them. Will read some more and try again in.

>
>> else static if(is(typeof(t) == char))
>> a[i] = input[i][0];
>
> input could be an empty string, and random things could happen.

got it...

>> else static if(is(typeof(t) == wchar))
>> mixin(assign);
>> else static if(is(typeof(t) == dchar))
>> a[i] = input[i][0];
>> else static if(is(typeof(t) == string))
>> if(a.length > 1)
>> a[i] = input[i];
>> else
>> a[i] = data;
>
> I see, if the caller of the function only requests a char[], the
> splitting by white space is disregarded, and the whole string is
> returned. Isn't that a but inconsistent? At least, it could always
> return the remainder of the string, if this char[] parameter is the last
> of the function.

I was actually hoping to find a way to put the unused portion back unto 
the buffer but that seems a much better approach.

> Also, the array index i isn't checked for input, and random things could
> happen. (You'd get an exception in debug mode, but not in release mode.)

??? not sure what you mean here. i is the index of the variable as it 
appears in the tuple "A". Why would I need to check it for input? i is 
valid as long as we have not reached the end of the tuple.

> Also, http://en.wikipedia.org/wiki/Dangling_else

Some more reading to do... got it!

>> else static if(is(typeof(t) == dstring))
>> {}
>> else static if(is(typeof(t) == char[]))
>> a[i] = stripr(data).dup;
>
> Shouldn't split() already remove all white space?

split removes the white space but only from the copy of the string 
returned. The original remains untouched.

>> }
>> return 0;
>> }

Thank you very much for responding.

Andrew


More information about the Digitalmars-d-learn mailing list