singledispatch (v5)

Revision 5 of this benchmark created on


Description

Python/Clojure style multimethod that dispatches on type of first argument.

Setup

const singledispatch = fallback => {
  let _key = Symbol('singledispatch method')

  // Assign fallback to Object prototype.
  // This makes it the method of last resort.
  Object.prototype[_key] = fallback

  const dispatch = (object, ...rest) => {
    let method = object[_key]
    return method(object, ...rest)
  }

  dispatch.define = (constructor, method) => {
    constructor.prototype[_key] = method
  }

  return dispatch
}

class Vec2D {
	constructor(x, y) {
		this.x = x
		this.y = y
	}

	add(x, y) {
		return new Vec2D(
			this.x + x,
			this.y + y
		)
	}
}

class Vec3D {
	constructor(x, y, z) {
		this.x = x
		this.y = y
		this.z = z
	}

	add(x, y, z) {
		return new Vec3D(
			this.x + x,
			this.y + y,
			this.z + z
		)
	}
}

class Vec4D {
	constructor(x, y, z, a) {
		this.x = x
		this.y = y
		this.z = z
		this.a = a
	}

	add(x, y, z, a) {
		return new Vec4D(
			this.x + x,
			this.y + y,
			this.z + z,
			this.a + a
		)
	}
}

class Vec5D {
	constructor(x, y, z, a, b) {
		this.x = x
		this.y = y
		this.z = z
		this.a = a
		this.b = b
	}

	add(x, y, z, a, b) {
		return new Vec4D(
			this.x + x,
			this.y + y,
			this.z + z,
			this.a + a,
			this.b + b
		)
	}
}

const add = singledispatch()

add.define(
  Number,
  (n, x) => n + x
)

add.define(
  Vec2D,
  (vec2d, x, y) => new Vec2D(
    vec2d.x + x,
    vec2d.y + y
  )
)

add.define(
  Vec3D,
  (vec3d, x, y, z) => new Vec3D(
    vec3d.x + x,
    vec3d.y + y,
    vec3d.z + z
  )
)

add.define(
  Vec4D,
  (vec4d, x, y, z, a) => new Vec4D(
    vec4d.x + x,
    vec4d.y + y,
    vec4d.z + z,
    vec4d.a + a
  )
)

add.define(
  Vec5D,
  (vec5d, x, y, z, a, b) => new Vec5D(
    vec5d.x + x,
    vec5d.y + y,
    vec5d.z + z,
    vec5d.a + a,
    vec5d.b + b
  )
)

const sub = singledispatch()

sub.define(
  Number,
  (n, x) => n - x
)

sub.define(
  Vec2D,
  (vec2d, x, y) => new Vec2D(
    vec2d.x - x,
    vec2d.y - y
  )
)

let origin = new Vec2D(0, 0)
let origin3d = new Vec3D(0, 0, 0)
let origin4d = new Vec4D(0, 0, 0, 0)
let origin5d = new Vec5D(0, 0, 0, 0, 0)

Test runner

Ready to run.

Testing in
TestOps/sec
singledispatch - megamorphic
// More than 4x polymorphism falls back to
// the megamorphic cache (up to 1000x)
// https://www.builder.io/blog/monomorphic-javascript
add(0, 5);
add(origin, 5, -5);
add(origin3d, 5, -5, 5);
add(origin4d, 5, -5, 5, -5);
add(origin5d, 5, -5, 5, -5, 5);
ready
singledispatch - polymorphic
// Up to 4x polymorphism uses
// the polymorphic cache (fast).
// https://www.builder.io/blog/monomorphic-javascript
sub(0, 5);
sub(origin, 5, -5);
ready
method
origin.add(5, -5);
origin3d.add(5, -5, 5);
origin4d.add(5, -5, 5, -5);
origin5d.add(5, -5, 5, -5, 5);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.