Besides @Stefan_Salewski's comments, it also bears mentioning that A) you need 
to be careful to compile the Nim with `-d:danger` before making Nim performance 
conclusions, B) `--gc:arc` may also help but may or may not be in your 
particular version of Nim and C) the algorithm in your Nim case is not quite 
the same - in the Go you just do an unconditional append and then a second loop 
while in the Nim you do a triple lookup when present and double lookup when 
missing . Avoiding string creation with the slicing and doing a more direct 
translation of the Go would look like: 
    
    
    func smallestRepr(arg: string): string =
      let doubled = arg & arg
      result = arg
      var slice = result # I *think* I have this right but have not tested..
      for i in 1 .. arg.high:
        copyMem slice[0].addr, doubled[i].addr, arg.len
        if slice < result:
          result = slice
    
    proc main() =
      var seen = initTable[string, seq[string]]()
      for word in paramStr(1).lines:
        let key = word.smallestRepr
        seen.mgetOrPut(key, @[]).add word
      for key, words in seen:
        if words.len == 4: echo words
    main()
    
    
    Run

At least in the past when I've benchmarked things, Go's tables were much slower 
than Nim's.

In the past I have noticed that, at least with the gcc backend, you can get a 
big boost (near 2X) from profile-guided optimization (`gcc -fprofile-generate 
...; Run sample prog; gcc -fprofile-use ...`) where the `...` s would be all 
the C files Nim wants to compile and the sample prog will probably be named 
`a.out`. (Usually everything in `~/.cache/nim/r/` on Unix, but visible via `nim 
c --verbosity:2` everywhere.)

Reply via email to