
The Expressive C++17 Coding Challenge in D - systems
https://seb.wilzba.ch/b/2018/02/the-expressive-c17-coding-challenge-in-d/
======
dpc_pw
D deserves much more popularity. It's much better language than Go, with many
similiar strenghts. If only it had Google's backing... Eh...

I still prefer Rust for many reasons (no exceptions, no GC, memory safety),
but in my heart D is the second favourite - the more lightweight, expressive
and pragmatic. I especially wish Rust had macro system and compilation times
of D because they are the best in the class. :]

~~~
systems
what i know is that d doesnt have a macro system but i has features that gives
the same benefits, but using language constructs

[https://dlang.org/articles/pretod.html](https://dlang.org/articles/pretod.html)

------
ncmncm
Without looking at any other solutions, I whipped up a one-off 37-line C++11
program that is easily twice as fast as the best D or Rust one, with no
special tricks. (Change out the uses of "auto" and it qualifies as C++98.)

I am appalled that a 125-line program to do such a simple job could win. If
that was the best they could do, I would have kept the challenge open until
something better came in.

I haven't tried the other programs on one-field files, or where the field
selected is the first, or the last. Did you?

    
    
        #include <iostream>
        #include <fstream>
        #include <streambuf>
        #include <algorithm>
        #include <string>
    
        int main(int, char** argv) {
          std::ifstream in(argv[1]);
          std::string head;
          if (!(in >> head)) return std::cout << "input file missing\n", 1;
          head = "," + head + ",";
          auto sub = std::string(argv[3]);
          auto target = "," + std::string(argv[2]) + ",";
          auto pos = head.find(target);
          if (pos == std::string::npos)
            return std::cout << "column name doesn’t exists in the input file\n", 1;
          auto skip_pre = pos ? std::count(&head[0], &head[pos], ',') : 0;
          auto skip_post = std::count(
            &head[pos + target.size()], &head[head.size()], ',');
          std::ofstream out(argv[4]);
          auto ib = in.rdbuf(), ob = out.rdbuf();
          ob->sputn(&head[1], head.size()-2); ob->sputc('\n');
          bool skipping = pos == 0;
          for (int c = 0, count = skip_pre; (c = ib->snextc()) != EOF; ) {
            if (c == ',' || c == '\n') {
              if (skipping) {
                count = skip_post + skip_pre;
                skipping = count == 0;
                ob->sputn(&sub[0], sub.size());
              } else if (--count == 0) {
                skipping = true;
              }
              ob->sputc(c);
            } else if (!skipping)
              ob->sputc(c);
          }
        }

~~~
geezerjay
> I am appalled that a 125-line program to do such a simple job could win.

The goal of that challenge was to pack the most C++17 features in a program,
and it was just a challenge organized by a couple of blogs.

The winner was also a self-confessed amateur. That's a telltale sign of how
many people have participated, and the level of engagement that the challenge
had.

------
kazinator
TXR Lisp, using standard _awk_ macro:

    
    
      (awk (:inputs *stdin*)                                                          
           (:set fs "," ofs ",")                                                      
           (:let pos (name [*args* 0]) (rplc [*args* 1]))                             
           ((= nr 1) (set pos (pos name f)))                                          
           ((> nr 1) (set [f pos] rplc))                                              
           (t (prn)))
    

Missing args -> pass through:

    
    
      $ txr solve.tl < data
      name,surname,city,country
      Adam,Jones,Manchester,UK
      Joe,Doe,Cracow,Poland
      Michael,Smith,Paris,France
      Alex,McNeil,Gdynia,Poland
    

With args:

    
    
      $ txr solve.tl city London < data
      name,surname,city,country
      Adam,Jones,London,UK
      Joe,Doe,London,Poland
      Michael,Smith,London,France
      Alex,McNeil,London,Poland
    

We need (:inputs _stdin_ ) so that _awk_ takes its input from standard input
rather than processing the _city London_ arguments as input sources.

------
test9753
In Ocaml [LOC: 24] [Level: Beginner]

    
    
      open Core
    
      let () =
        if Array.length Sys.argv <> 5 then
          Printf.eprintf "Invalid args\nUsage: %s <input.csv> <column-name> <replacement-string> <output.csv>" Sys.argv.(0)
        else
          let input_file, column_name, replacement, output_file = Sys.argv.(1), Sys.argv.(2),Sys.argv.(3),Sys.argv.(4) in 
          In_channel.with_file input_file ~f:(fun in_ch ->
          match In_channel.input_line in_ch with 
          | None -> Printf.eprintf "Cannot read first line"
          | Some first_line ->
            let columns = String.split first_line ~on:',' in 
            match List.findi columns ~f:(fun _ col -> col = column_name) with 
            | None -> Printf.eprintf "Cannot find column: %s" column_name
            | Some (index, _) ->
              let _ = Out_channel.with_file output_file ~f:(fun out_ch ->
                Out_channel.output_string out_ch (first_line ^ "\n");
                In_channel.fold_lines in_ch ~init:() ~f:(fun _ line ->
                  let in_columns = String.split line ~on:',' in 
                  let out_columns = List.mapi ~f:(fun i col -> if i = index then replacement else col) in_columns in 
                  let out_line = (String.concat ~sep:"," out_columns) ^ "\n" in
                  Out_channel.output_string out_ch out_line
                )
              ) in ())

------
typon
This blog post was an amazing advertisement for D.

~~~
geezerjay
I don't agree. The comparisons are rather disingenuous as the representative
examples hand-picked for the other languages are rather crude and too much
verbose. For instance, the 120-loc C++ program needlessly introduces functions
that run a single loc (by adding 4 or 5 loc to the bill) and add a dozen or so
lines by breaking long lines.

~~~
greenify
The C++ program won the challenge of being the "most expressive C++17" program
for this task ...

~~~
geezerjay
...and by "most expressive C++17 [program]" it actually meant this:

> So the purpose of this challenge is to write a piece of code that contains
> as many features of C++17 as possible, and that is as clear as possible.

...which, clearly, states that the goal was not minimize lines of code.

I bet D fanboys can find more apples-to-oranges comparisons where D comes out
as the most citric alternative when compared with apples and bananas.

And by the way, the contest was organized by a couple of blogs, and the winner
was a self-confessed amateur. Hardly a tour de force in C++ programming.

------
shakna
I always love how succinct D is, whilst still remaining fairly readable.

I'd also like to point out that SafeD covers a fair bit of the language.
Enough that I feel comfortable making it a requirement in production code.

------
arunc
This is a very well written article. The author shows an idiomatic D code and
explains the details line by line. Clearly emphasizes the expressiveness of D.

