Google Code Jam 2011 Language Usage

Jonathan M Davis jmdavisProg at gmx.com
Sun May 8 15:11:15 PDT 2011


> Andrew Wiley wrote:
> > I was one of the D users, although I wasn't really worried about
> > competing. I just wanted to see how D would compare after doing so many
> > programming contests in Java.
> > The main thing that frustrated me was that getting input in D wasn't
> > anywhere near as straightforward as it is in Java. For the first problem,
> > I'd do something like this in Java:
> > Scanner in = new Scanner(System.in);
> > int numTests = in.nextInt();
> > for(int test = 0; test < numTests; tests++) { //need the test index for
> > output
> > int numSteps = in.nextInt();
> > for(; numSteps < 0; numSteps--)
> > char robot = in.nextChar();
> > int button = in.nextInt();
> > //solve the problem!
> > }
> > //print the output!
> > }
> 
> Well, I don't like D's readf either (I use scanf, 2-3x faster and better
> whitespace handling). That said, you really made my day.
> The problem is not that reading input in D is less straightforward than in
> Java, the problem is, that you are used to Java's way of doing IO. (which
> I pretty much dislike, I guess it is a matter of taste)
> 
> You do not actually have to bother with string handling at all when doing
> IO in C/C++/D.
> 
> Reading array of integers:
> 
> int[100000] array; //somewhere in static storage, faster
> ...
> scanf("%d",&n);
> foreach(ref x;array) scanf("%d",&x);
> 
> Or, some heap activity involved, and actually more keystrokes, but some
> people like this way:
> readf("%s",&n);//read number of items
> 
> int[] array=to!(int[])(split(strip(readln())));
> 
> 
> How I would have written your example in D.
> int numTests; scanf("%d", &numTests);
> foreach(test;0..numTests){
>     int numSteps; scanf("%d", &numSteps);
>     foreach(step;0..numSteps){ //you have a bug in this line of your Java
> code introducing a looooong loop
>         char robot; scanf("%c", &robot);
>         int button; scanf("%d", &button);
>         //solve the problem!
>     }
>     //print the output
> }
> 
> > In D, that looked like this:
> > string line;
> > int num;
> > stdin.readln(line);
> > formattedRead(line, "%s", &num);
> > for(int casen = 0; casen < num; casen++) {
> > 
> > ...
> > 
> > In a few places, I could have used stdin.readf instead of
> > readln/formattedRead, but not many because the number of items within a
> > test is on the same line as the items.
> 
> That is not a problem at all, you can read the first few elements with
> readf and the rest of the line with readln
> 
> > I could have just been missing something, but something that was trivial
> > in Java became brittle in D because I had to exactly match the
> > whitespace for
> 
> I actually think Java's way is brittle. You have to instantiate a class
> just to read IO.
> 
> > things to work. I suppose I could have read a line and used splitter to
> > split on whitespace, but that would make me have to watch more state and
> > would wind up looking like this:
> > string line;
> > stdin.readln(line);
> > auto split = split(line);
> > int num = to!int(split[0]);
> > split = split[1..$];
> 
> I don't get this.
> 
> > ...
> > 
> > Actually... now that I'm looking at that, if I wrote a Scanner-like class
> > based on this, is there any chance it could go into Phobos? Seems like
> > between split and to, we could get something much less brittle working.
> 
> No chance, that is not the way D/Phobos works. You do not have a class for
> everything that would not need one. (just like Phobos does not have a
> writer class for output)
> 
> However I agree that Phobos has to provide some better input handling,
> since using possibly unsafe C functions is the best way to do it by now.
> (I think readf is severely crippled) I may try to implement a meaningful
> "read" function.

stdin is already a struct in D. To do it in a more Java-like manner would 
likely involve having a templated read function which is templated on the type 
that you want to get out of stdin next. Essentially, you'd do something like 
std.conv.parse directly on stdin by having it as part of std.stdio.File.

Now, personally, I just always read in the whole line and then use 
std.conv.parse on it. I'm not sure if that actually costs you anything in 
terms of functionality, though it might be possible to implement a templated 
read function on std.stdio.File more efficiently. And using parse like that, 
you can get much friendlier I/O which is closer to what you'd get with Scanner 
in Java.

- Jonathan M Davis


More information about the Digitalmars-d mailing list