Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to add a method to a built-in type in Scala?

I would like to add a method to a built-in type (e.g. Double), so that I can use an infix operator. Is that possible?

like image 799
namin Avatar asked Nov 18 '08 07:11

namin


People also ask

How do you create a method in Scala?

We can define a method's list of parameters in parentheses after its name. After the parameters list, we can provide a return type for the method with the leading colon sign. We then define a method's body after the equals sign. The compiler allows us to skip the curly braces if there is only one statement of code.

What is the difference between method and function in Scala?

A method belongs to an object (usually the class , trait or object in which you define it), whereas a function is by itself a value, and because in Scala every value is an object, therefore, a function is an object. The second def is an object of type Int => Int (the syntactic sugar for Function1[Int, Int] ).

What does def mean in Scala?

def is the keyword you use to define a method, the method name is double , and the input parameter a has the type Int , which is Scala's integer data type. The body of the function is shown on the right side, and in this example it simply doubles the value of the input parameter a : def double(a: Int) = a * 2 -----


2 Answers

Yes and no. Yes, you can make it seem like you have added a method to double. For example:

class MyRichDouble(d: Double) {
  def <>(other: Double) = d != other
}

implicit def doubleToSyntax(d: Double) = new MyRichDouble(d)

This code adds the previously-unavailable <> operator to any object of type Double. So long as the doubleToSyntax method is in scope so that it could be invoked without qualification, the following will work:

3.1415 <> 2.68     // => true

The "no" part of the answer comes from the fact that you aren't really adding anything to the Double class. Instead, you are creating a conversion from Double to a new type which does define the method you want. This can be a much more powerful technique than the open-classes offered by many dynamic languages. It also happens to be completely type-safe. :-)

Some limitations you should be aware of:

  • This technique does not allow you to remove or redefine existing methods, just add new ones
  • The implicit conversion method (in this case, doubleToSyntax) absolutely must be in-scope for the desired extension method to be available

Idiomatically, implicit conversions are either placed within singleton objects and imported (e.g. import Predef._) or within traits and inherited (e.g. class MyStuff extends PredefTrait).

Slight aside: "infix operators" in Scala are actually methods. There is no magic associated with the <> method which allows it to be infix, the parser simply accepts it that way. You can also use "regular methods" as infix operators if you like. For example, the Stream class defines a take method which takes a single Int parameter and returns a new Stream. This can be used in the following way:

val str: Stream[Int] = ...
val subStream = str take 5

The str take 5 expression is literally identical to str.take(5).

like image 188
Daniel Spiewak Avatar answered Oct 07 '22 08:10

Daniel Spiewak


This feature came in handy to implement a class performing error estimation:

object errorEstimation {
  class Estimate(val x: Double, val e: Double) {
    def + (that: Estimate) =
      new Estimate(this.x + that.x, this.e + that.e)
    def - (that: Estimate) =
      new Estimate(this.x - that.x, this.e + that.e)
    def * (that: Estimate) =
      new Estimate(this.x * that.x,
                   this.x.abs*that.e+that.x.abs*this.e+this.e*that.e)
    def / (that: Estimate) =
      new Estimate(this.x/that.x,
                   (this.x.abs*that.e+that.x.abs*this.e)/(that.x.abs*(that.x.abs-that.e)))
    def +- (e2: Double) =
      new Estimate(x,e+e2)
    override def toString =
      x + " +- " + e
  }
  implicit def double2estimate(x: Double): Estimate = new Estimate(x,0)
  implicit def int2estimate(x: Int): Estimate = new Estimate(x,0)

  def main(args: Array[String]) = {
    println(((x: Estimate) => x+2*x+3*x*x)(1 +- 0.1))
    // 6.0 +- 0.93
    println(((x: Estimate) => (((y: Estimate) => y*y + 2)(x+x)))(1 +- 0.1))
    // 6.0 +- 0.84
    def poly(x: Estimate) = x+2*x+3/(x*x)
    println(poly(3.0 +- 0.1))
    // 9.33333 +- 0.3242352
    println(poly(30271.3 +- 0.0001))
    // 90813.9 +- 0.0003
    println(((x: Estimate) => poly(x*x))(3 +- 1.0))
    // 27.037 +- 20.931
  }
}
like image 35
namin Avatar answered Oct 07 '22 07:10

namin