fork(1) download
class Knob(door: Door) {
	private var latched: Boolean = true
	def is_latched_off = !latched
	def turn = latched = false
	def unturn = if (door.is_close) latched = true
}

class Door {
	var knob: Knob = new Knob(this)
	private var closed: Boolean = true
	def is_close = closed
	def is_open = !is_close
	def can_be_open = is_open || knob.is_latched_off
	def be_open = if (can_be_open) closed = false
	def be_close = { closed = true; knob.unturn }
	def push = be_open
	def pull = be_close
}

class DoorCloserPull(door: DoorWithCloser) extends Thread {
	var done: Boolean = false
	override def run = {
		Thread.sleep(door.delay)
		if (!done) door.pull
	}
}

class DoorWithCloser extends Door {
	var delay = 300
	var delayed_pull = new DoorCloserPull(this)
	override def push = {
		super[Door].push
		if (!delayed_pull.done) delayed_pull.done = true
		delayed_pull = new DoorCloserPull(this)
		delayed_pull.start
	}
}

trait AbstractDoorStopper {
	var stoppered: Boolean
	def pull: Unit
	def push: Unit
}

trait DoorStopper extends AbstractDoorStopper {
	def be_stoppered_on = stoppered = true
	def be_stoppered_off = stoppered = false
	abstract override def pull = if (!stoppered) super.pull
	abstract override def push = { be_stoppered_off; super.push }
}

class DoorWithStopper extends Door with DoorStopper {
	var stoppered = false
	override def pull = super.pull
	override def push = super.push
}

class DoorWithCloserStopper extends DoorWithCloser with DoorStopper {
	var stoppered = false
	override def be_stoppered_off = push
	override def pull = super.pull
	override def push = {
		super[DoorStopper].be_stoppered_off
		super[DoorWithCloser].push
	}
}

object Main extends App {
	var door = new Door
	println("door is a Door...")
	door.knob.turn
	println("door.knob.turn; door.can_be_open => " + door.can_be_open)
	door.knob.unturn
	println("door.knob.unturn; door.can_be_open => " + door.can_be_open)
	door.push
	println("door.push; door.is_open => " + door.is_open)
	door.knob.turn; door.push
	println("door.knob.turn; door.push; door.is_open => " + door.is_open)
	door.pull
	println("door.pull; door.is_close => " + door.is_close)
	println("door.can_be_open => " + door.can_be_open + "\n")
	
	var door2 = new DoorWithCloser
	println("door2 is a DoorWithCloser...")
	door2.knob.turn; door2.push
	println("door2.knob.turn; door2.push; door2.is_open => " + door2.is_open)
	print("0.1 second after")
	Thread.sleep(100)
	println(", door2.is_open => " + door2.is_open)
	print("0.4 seconds after")
	Thread.sleep(300)
	println(", door2.is_open => " + door2.is_open + "\n")

	var door3 = new DoorWithStopper
	println("door3 is a DoorWithStopper...")
	door3.knob.turn; door3.push
	println("door3.knob.turn; door3.push; door3.is_open => " + door3.is_open)
	door3.be_stoppered_on; door3.pull
	println("door3.be_stoppered_on; door3.pull; door3.is_close => " + door3.is_close)
	door3.be_stoppered_off; door3.pull
	println("door3.be_stoppered_off; door3.pull; door3.is_close => " + door3.is_close)
	door3.knob.turn; door3.push
	println("door3.knob.turn; door3.push; door3.is_open => " + door3.is_open)
	door3.be_stoppered_on; door3.pull
	println("door3.be_stoppered_on; door3.pull; door3.is_close => " + door3.is_close)
	door3.push; door3.pull
	println("door3.push; door3.pull; door3.is_close => " + door3.is_close + "\n")

	var door4 = new DoorWithCloserStopper
	println("door4 is a DoorWithCloserStopper...")
	door4.knob.turn; door4.push
	println("door4.knob.turn; door4.push; door4.is_open => " + door4.is_open)
	door4.be_stoppered_on
	print("door4.be_stoppered_on; 0.4 seconds after")
	Thread.sleep(400)
	println(", door4.is_open => " + door4.is_open)
	door4.be_stoppered_off
	print("door4.be_stoppered_off; 0.4 seconds after")
	Thread.sleep(400)
	println(", door4.is_open => " + door4.is_open)
	door4.knob.turn; door4.push
	println("door4.knob.turn; door4.push; door4.is_open => " + door4.is_open)
	door4.be_stoppered_on
	print("door4.be_stoppered_on; 0.4 seconds after")
	Thread.sleep(400)
	println(", door4.is_open => " + door4.is_open)
	door4.push
	print("door4.push; 0.4 seconds after")
	Thread.sleep(400)
	println(", door4.is_open => " + door4.is_open + "\n")	
}
Success #stdin #stdout 0.35s 4448256KB
stdin
Standard input is empty
stdout
door is a Door...
door.knob.turn; door.can_be_open => true
door.knob.unturn; door.can_be_open => false
door.push; door.is_open => false
door.knob.turn; door.push; door.is_open => true
door.pull; door.is_close => true
door.can_be_open => false

door2 is a DoorWithCloser...
door2.knob.turn; door2.push; door2.is_open => true
0.1 second after, door2.is_open => true
0.4 seconds after, door2.is_open => false

door3 is a DoorWithStopper...
door3.knob.turn; door3.push; door3.is_open => true
door3.be_stoppered_on; door3.pull; door3.is_close => false
door3.be_stoppered_off; door3.pull; door3.is_close => true
door3.knob.turn; door3.push; door3.is_open => true
door3.be_stoppered_on; door3.pull; door3.is_close => false
door3.push; door3.pull; door3.is_close => true

door4 is a DoorWithCloserStopper...
door4.knob.turn; door4.push; door4.is_open => true
door4.be_stoppered_on; 0.4 seconds after, door4.is_open => true
door4.be_stoppered_off; 0.4 seconds after, door4.is_open => false
door4.knob.turn; door4.push; door4.is_open => true
door4.be_stoppered_on; 0.4 seconds after, door4.is_open => true
door4.push; 0.4 seconds after, door4.is_open => false