Canonical/Idiomatic in memory files

Walter Bright newshound2 at digitalmars.com
Wed May 29 00:32:50 PDT 2013


On 5/29/2013 12:02 AM, Russel Winder wrote:
> On Tue, 2013-05-28 at 22:33 -0700, Walter Bright wrote:
> […]
>> Coincidentally, I wrote a wc program a year ago:
>
> I note the one on the D web site could do with being made more
> idiomatic. cf. http://dlang.org/wc.html

Yup.


>> -------------------------
>> import std.stdio, std.file, std.string, std.array, std.algorithm, std.typecons;
>> import lazysplit;
>
> As far as I know currently (which may mean I am very wrong), D imports
> import all symbols defined in the module into the current name space.

This is incorrect. They are implemented as sort of "second class citizens" in 
the current name space. This means that any declaration in the current name 
space overrides any in the import name space. If the name is not found in the 
current name space, and is found in more than one import, an ambiguity error is 
generated.


> This is like "star imports" in Python and Java which are now seen as not
> the right thing to do. Python's default is to import the namespace not
> the symbols in it and many believe this is the right thing to do.

D imports also allow "cherry-picking" of individual names out of it.

>> alias Tuple!(int, "lines", int, "words", int, "chars") Lwc;
>
> I used an int[3] for this, but I like the labelled tuple. Is this really
> just a three item dictionary though. Might a dictionary be a better
> structure for this?

It's equivalent to:
    struct Tuple { int lines; int words; int chars; }
which is much more efficient than a dictionary.


>> void main(string[] args) {
>>       writeln("   lines   words   bytes file");
>>
>>       auto total = args[1 .. args.length].wctotal();
>>
>>       if (args.length > 2)
>>           writefln("--------------------------------------\n%8s%8s%8s total",
>>               total[0..3]);
>> }
>
> To emulate /usr/bin/wc, I dispensed with the - sequence. Less code ;-)
>
> Is there an idiom of when to use 1..args.length and when to use 1..$ ?

Not really.


>> auto wctotal(R)(R args) {
>>       Lwc total;
>>       foreach (arg; args) {
>>           auto t = arg.File().byLine(KeepTerminator.yes).wc();
>>
>>           writefln("%8s%8s%8s %s", t[0..3], arg);
>>
>>           foreach(i, v; t)
>>               total[i] += v;
>>       }
>>       return total;
>> }
>
> Why a template? R is always string?

It could be a string, wstring or a dstring.

> The above does not cope with a
> parameter being "-" to indicate use the stdin.

That's true. For stdin, you'd replace "arg.File()" with "stdin".

>> auto wc(R)(R r) {
>>       Lwc t;
>>       foreach (line; r) {
>>           t.lines += 1;
>>           t.words += line.lazySplit().count();
>>           t.chars += line.length;
>>       }
>>       return t;
>> }
>
> The body of this function looks almost, but not quite, exactly like
> mine :-)
>
>> Just replace "arg.File().byLine(KeepTerminator.yes)" with a string filled with
>> your mocked data.
>
> No that is not acceptable, the code under test must remain unchanged in
> order to be tested.

You just need to get the component programming religion! and get away from using 
FILE*. There isn't anything fundamentally different from using a fake FILE* and 
using a template with a different InputRange. If that's still unacceptable, you 
can create an InputRange that is a class with virtual functions empty(), 
front(), and popFront(), then use derived classes for the File or string.



More information about the Digitalmars-d mailing list