Can Scala "if ... else" be implemented as a library function?

I am wondering if if … else implemented in Predef special compiler handler, similar to how it is done with classOf[A] : the definition is in Predef , the implementation is populated by the compiler.

Of course, many people will be sure that if always if , and else always else , regardless of context. However, defining else as a method in the if result type will remove it from the list of keywords and allow library developers to define their own else methods. (I know that I can use any keyword as an identifier with back windows, but something like `else` just looks awful in the code.) Such methods can be useful in cases discussed in situations such as this one being discussed on the mailing list where people are forced to use otherwise when defining methods that should actually be called else . (SO is also discussed here here and here .)

So:

  • Will such an approach be possible even in theory or will it violate some fundamental principle in Scala?
  • What will be the disadvantages?
+7
source share
4 answers

Perhaps I do not understand your question, but you can already implement if ... else ... as a library function. Consider this:

 class If[A](condition: =>Boolean)(ifBlock: =>A) { def els(elseBlock: =>A):A = condition match { case true => ifBlock case false => elseBlock } } new If(2==3)( println("equal") ) els ( println("not equal") ) 

Of course, this does not do what if ... else ... does, but with some polishing, I think it will. I once implemented a very simple interpreter for a language that had a pattern matching built in with if ... else ... , implemented the same way as here.

+10
source

The short answer is yes; branching logic on some predicate can be implemented as a library function.

It is worth noting that, as Viktor Klang and others noted, if / else essentially collapses a boolean. Folding is what we often do - sometimes it's clear and explicit, and sometimes not.

 // Either#fold is explicit scala> Left[String, Double]("fail") fold(identity, _ + 1 toString) res0: java.lang.String = fail scala> Right[String, Double](4) fold(identity, _ + 1 toString) res1: java.lang.String = 5.0 

Folding options cannot be done explicitly, but we do this all the time.

 // Option has no fold - wont compile! Some(5) fold(1+, 0) // .. but the following is equivalent and valid scala> Some(5) map(1+) getOrElse(0) res3: Int = 6 

Branching logic in Boolean is also a fold, and you can sublimate Boolean accordingly. Note the use of name-name parameters to achieve a lazy score. Without this function, such an implementation is impossible.

 // pimped Boolean - evaluates t when true, f when false class FoldableBoolean(b: Boolean) { def fold[A](t: => A, f: => A) = if(b) t else f } implicit def b2fb(b: Boolean) = new FoldableBoolean(b) 

Now we can reset booleans:

 scala> true fold("true!", "false") res24: java.lang.String = true! scala> false fold("true!", "false") res25: java.lang.String = false 
+8
source

Not only if-else , but any language function can be redefined into branches of a language known as "Scala virtualized"

https://github.com/TiarkRompf/scala-virtualized

This forms the basis of the Delite project at Stanford PPL, as well as the basis of research funded by EU Scala grant. Therefore, you can reasonably expect it to become part of the core language at some point in the future.

+3
source

Any object-oriented language (or any language with polymorphism at runtime) can implement conventions as a library function, since method submission is already a more general conditional form anyway. Smalltalk, for example, has absolutely no conditions other than sending a method.

There is no need for any compiler magic, except perhaps for syntactic convenience.

In Scala, it would look something 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 pretty weak. I had to cheat a little to get it compiled in a reasonable amount of time. Someone who better understands a system like Scala might want to fix it. Also, now when I look at it, 8 classes, traits, and objects, two of them abstract, seem a bit overworked ;-)]

Of course, the same is true for pattern matching. Any language with pattern matching does not need other kinds of conditional expressions, since pattern matching is in any case more general.

[BTW: This is basically a port for this Ruby code. I wrote a couple of years ago for fun.]

+3
source

All Articles