widget contravariant - JSFiddle

by Hyunsok Oh

JavaScript

function logg(m, linebreakbefore=false) {
  let e = document.createElement("p")
  let t = document.createTextNode(m)
  e.appendChild(t)
  if(linebreakbefore) {
    document.body.appendChild(document.createElement("br"))
  }
  document.body.appendChild(e)
}

class Widget {
  constructor(id) { this.id = id }
  render() {
    logg(`recursively rendering ${this.id}`)
  }
}

class Button extends Widget {
  click() {
    logg(`clicking ${this.id}`)
  }
}

class Traverser {
  constructor(v) { this.v = v }
  traverse() { logg(`traversing ${this.v}`) }
}

class ButtonTraverser extends Traverser {
  traverse() { logg(`traversing & clicking ${this.v}`); this.v.click() }  
}

class WidgetTraverser extends Traverser {
  traverse() { logg(`traversing & rendering ${this.v}`); this.v.click() }    
}

let w = new Widget(0)
let b = new Button(1)

w.render()
b.render()
b.click()

function traverseIt(traverser, widget) {
  traverser.traverse(widget)
}

let t1 = new Traverser()

traverseIt()