Any object-oriented language (or any language with runtime polymorphism) can implement conditionals as a library feature, since method dispatch already is a more general form of conditional anyway. Smalltalk, for example, has absolutely no conditionals whatsoever except for method dispatch.
There is no need for any kind of compiler magic, except maybe for syntactic convenience.
In Scala, it would look maybe a little bit like this:
trait MyBooleanLike {
def iff[T <: AnyRef](thenn: => T): T
def iffElse[T](thenn: => T)(els: => T): T
def &&(other: => MyBoolean): MyBoolean
def ||(other: => MyBoolean): MyBoolean
def nott: MyBoolean
}
trait MyTruthiness extends MyBooleanLike {
def iff[T](thenn: => T) = thenn
def iffElse[T](thenn: => T)(els: => T) = thenn
def &&(other: => MyBoolean) = other
def ||(other: => MyBoolean) = MyTrue
def nott = MyFalse
}
trait MyFalsiness extends MyBooleanLike {
def iff[T](thenn: => T): T = null.asInstanceOf[T]
def iffElse[T](thenn: => T)(els: => T) = els
def &&(other: => MyBoolean) = MyFalse
def ||(other: => MyBoolean) = other
def nott = MyTrue
}
abstract class MyBoolean extends MyBooleanLike
class MyTrueClass extends MyBoolean with MyTruthiness {}
class MyFalseClass extends MyBoolean with MyFalsiness {}
object MyTrue extends MyTrueClass {}
object MyFalse extends MyFalseClass {}
Just add a little implicit conversion:
object MyBoolExtension {
implicit def boolean2MyBoolean(b: => Boolean) =
if (b) { MyTrue } else { MyFalse }
}
import MyBoolExtension._
And now we can use it:
object Main extends App {
(2 < 3) iff { println("2 is less than 3") }
}
[Note: my type-fu is rather weak. I had to cheat a little bit to get this to compile within a reasonable timeframe. Someone with a better understanding of Scala's type system may want to fix it up. Also, now that I look at it, 8 classes, traits and objects, two of them abstract, seems a little over-engineered ;-) ]
Of course, the same is true for pattern matching as well. Any language with pattern matching doesn't need other kinds of conditionals, since pattern matching is more general anyway.
[BTW: This is basically a port of this Ruby code I wrote a couple of years ago for fun.]