Skip to content

[performance] Show trait #2433

@illusory0x0

Description

@illusory0x0

motivation

Now that the show trait uses the &Logger trait object, using dynamic dispatch results in much worse performance than using StringBuilder directly.

///|
test "hello" {
  if @lib.hello() != "Hello, world!" {
    fail("@lib.hello() != \"Hello, world!\"")
  }
}

///|
test (b : @bench.T) {
  b.bench(name="StringBuilder", fn() {
    let sb : StringBuilder = StringBuilder::new()
    for _ in 0..<1000 {
      sb.write_char('a')
    }
  })
  b.bench(name="&Logger", fn() {
    let lg : &Logger = StringBuilder::new()
    for _ in 0..<1000 {
      lg.write_char('a')
    }
  })
}
bench username/hello/lib/hello_test.mbt::1
name          time (mean ± σ)         range (min … max) 
StringBuilder   14.62 µs ±   0.17 µs    14.38 µs …  14.85 µs  in 10 ×   6928 runs
&Logger         18.64 µs ±   0.19 µs    18.41 µs …  18.93 µs  in 10 ×   5365 runs
Total tests: 1, passed: 1, failed: 0. [native]
bench username/hello/lib/hello_test.mbt::1
name          time (mean ± σ)         range (min … max) 
StringBuilder   17.91 µs ±   0.22 µs    17.57 µs …  18.28 µs  in 10 ×   5436 runs
&Logger         24.10 µs ±   0.83 µs    23.51 µs …  26.35 µs  in 10 ×   4139 runs
Total tests: 1, passed: 1, failed: 0. [wasm]

current API

pub(open) trait Show {
  output(Self, &Logger) -> Unit
  to_string(Self) -> String = _
}

expected API

Using a concrete type is better and simpler than using a trait object.

pub(open) trait Show {
  output(Self, StringBuilder) -> Unit
  to_string(Self) -> String = _
}

alternative choice

Extending the capabilities of traits to support generic traits solves this problem.

moonbitlang/moonbit-evolution#5

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions