Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
The Expressive C++17 Coding Challenge in D (wilzba.ch)
41 points by systems on Feb 14, 2018 | hide | past | favorite | 12 comments


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. :]


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


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);
      }
    }


> 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.


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.


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 ())


This blog post was an amazing advertisement for D.


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.


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


...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.


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.


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.




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: