Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
OPERATOR OVERLOADING
IN SCALA
Joey Gibson
First Things First
   Working with Java since 1996
   Playing with Scala for not-quite-a-year

   Originally a blog pos...
What Is Operator Overloading?
   A language facility that allows developers to define
    behavior for symbols like +, -,...
The Basics
   Technically, Scala does not have operator
    overloading
     Operatorsare just methods
     Any method ...
What About Precedence?
   Scala looks at the first character of the operator
    name
       All other special chars
   ...
Operator Naming
   Typically, you would use arithmetic operator
    symbols, but you don’t have to
   Since operators ar...
Complex.scala
package com.joeygibson.oopres

class Complex(val real: Int, val imaginary: Int) {
  def +(operand: Complex):...
ComplexTest.scala
package com.joeygibson.oopres


import org.junit.runner.RunWith
import org.scalatest.FlatSpec
import org...
Interesting Naming Examples
package com.joeygibson.oopres

import org.apache.commons.lang.StringUtils

class Fragment(val ...
Testing Interesting Names
package com.joeygibson.oopres


@RunWith(classOf[JUnitRunner])
class FragmentTest extends FlatSp...
You Can Even Get Silly…
package com.joeygibson.oopres

class Absurdity(val text: String) {
  def //(other: Absurdity) = {
...
Testing the Silliness
package com.joeygibson.oopres


@RunWith(classOf[JUnitRunner])
class AbsurdityTest extends FlatSpec ...
Arguments of Different Types
   Define multiple versions of method, taking different
    types
   Use Implicit conversio...
Multiple Defs of Operator
package com.joeygibson.oopres


class Complex2(val real: Int, val imaginary: Int) {
    def +(op...
Testing Multiple Defs
package com.joeygibson.oopres

@RunWith(classOf[JUnitRunner])
class Complex2Test extends FlatSpec wi...
Implicit Conversions
   The implicit function must be in scope
   It can live in the companion object of either class
  ...
Implicit Conversions
package com.joeygibson.oopres


object Complex3 {
    implicit def intToComplex3(anInt: Int): Complex...
Testing Implicits
package com.joeygibson.oopres

@RunWith(classOf[JUnitRunner])
class Complex3Test extends FlatSpec with S...
Using Both
package com.joeygibson.oopres



object Complex4 {

    implicit def intToComplex4(anInt: Int): Complex4 = {

 ...
You Can’t Use ++ as Prefix
package com.joeygibson.oopres


class MyNumber(private var num: Int) {


    def number: Int = ...
The First One Works, The Second…
package com.joeygibson.oopres


@RunWith(classOf[JUnitRunner])
class MyNumberTest extends...
ἐγώ ἐιμι
   Email: joey@joeygibson.com
   Blog: http://joeygibson.com
     Original   post: http://bit.ly/wNvAl
   Twi...
Upcoming SlideShare
Loading in …5
×

Operator Overloading In Scala

11,298 views

Published on

I gave this presentation on January 14, 2010 to the Atlanta Scala user group. It covers Scala's implementation of operator overloading, as well as touching on implicit conversions.

Published in: Technology
  • Be the first to comment

Operator Overloading In Scala

  1. 1. OPERATOR OVERLOADING IN SCALA Joey Gibson
  2. 2. First Things First  Working with Java since 1996  Playing with Scala for not-quite-a-year  Originally a blog post on joeygibson.com  See the original at http://bit.ly/wNvAl  Based on example from Programming Scala, by Venkat Subramaniam
  3. 3. What Is Operator Overloading?  A language facility that allows developers to define behavior for symbols like +, -, / for their own classes, mimicking built-in operators  C++, Smalltalk, Ruby, lots of others have it  Java does not have it  Except + for String concatenation  BigDecimal, BigInteger, etc. would be nicer to use with operators
  4. 4. The Basics  Technically, Scala does not have operator overloading  Operatorsare just methods  Any method taking 0/1 argument can be called as an operator  foo doSomething “x” is the same as foo.doSomething(“x”)  foo + 23 is the same as foo.+(23)  You can define both binary and unary operators  Only +, -, ~ and ! can be used as unary operators  As with binary operators, it’s just a method and  -foo is the same as foo.unary_-
  5. 5. What About Precedence?  Scala looks at the first character of the operator name  All other special chars  */%  +-  :  =!  <>  &  ^  |  All letters  All assignment operators
  6. 6. Operator Naming  Typically, you would use arithmetic operator symbols, but you don’t have to  Since operators are just methods, you can use non- standard characters  Δ,λ, γ, Ω, etc.  Neat/useful, but use sparingly, unless it makes your code easier to read and/or maintain  If the last character in an operator name is a colon, that method associates to the right
  7. 7. Complex.scala package com.joeygibson.oopres class Complex(val real: Int, val imaginary: Int) { def +(operand: Complex): Complex = { new Complex(real + operand.real, imaginary + operand.imaginary) } def *(operand: Complex): Complex = { new Complex(real * operand.real - imaginary * operand.imaginary, real * operand.imaginary + imaginary * operand.real) } override def toString() = { real + (if (imaginary < 0) "" else "+") + imaginary + "i" } }
  8. 8. ComplexTest.scala package com.joeygibson.oopres import org.junit.runner.RunWith import org.scalatest.FlatSpec import org.scalatest.matchers.ShouldMatchers import org.scalatest.junit.JUnitRunner @RunWith(classOf[JUnitRunner]) class ComplexTest extends FlatSpec with ShouldMatchers { "A Complex" should "sum up to 4-9i" in { val c1 = new Complex(1, 2) val c2 = new Complex(2, -3) val c3 = c1 + c2 val res = c1 + c2 * c3 res.toString should equal ("4-9i") } }
  9. 9. Interesting Naming Examples package com.joeygibson.oopres import org.apache.commons.lang.StringUtils class Fragment(val text: String) { override def toString = text def Δ(other: Fragment): Fragment = { val diff = StringUtils.difference(text, other.text) new Fragment(diff) } def ::(other: Fragment): Fragment = { new Fragment(text + " || " + other.text) } }
  10. 10. Testing Interesting Names package com.joeygibson.oopres @RunWith(classOf[JUnitRunner]) class FragmentTest extends FlatSpec with ShouldMatchers { it should "return proper differences" in { val f0 = new Fragment("Scala is groovy") val f1 = new Fragment("Scala is cool") val diff = f0 Δ f1 diff.toString should equal("cool") } it should "concatenate properly" in { val f0 = new Fragment("First Fragment") val f1 = new Fragment("Second Fragment") val f2 = f0 :: f1 f2.toString should equal ("Second Fragment || First Fragment") } }
  11. 11. You Can Even Get Silly… package com.joeygibson.oopres class Absurdity(val text: String) { def //(other: Absurdity) = { new Absurdity(text + ", " + other.text) } def //(other: Absurdity) = { new Absurdity(other.text + ", " + text) } override def toString = text }
  12. 12. Testing the Silliness package com.joeygibson.oopres @RunWith(classOf[JUnitRunner]) class AbsurdityTest extends FlatSpec with ShouldMatchers { it should "do something absurd" in { val a = new Absurdity("foo") val b = new Absurdity("bar") val c = a // b c.toString should equal ("foo, bar") } it should "do something equally absurd" in { val a = new Absurdity("foo") val b = new Absurdity("bar") val c = a // b c.toString should equal ("bar, foo") } }
  13. 13. Arguments of Different Types  Define multiple versions of method, taking different types  Use Implicit conversions
  14. 14. Multiple Defs of Operator package com.joeygibson.oopres class Complex2(val real: Int, val imaginary: Int) { def +(operand: Complex2): Complex2 = { new Complex2(real + operand.real, imaginary + operand.imaginary) } def +(operand: Int): Complex2 = this + new Complex2(operand, 0) def *(operand: Complex2): Complex2 = { new Complex2(real * operand.real - imaginary * operand.imaginary, real * operand.imaginary + imaginary * operand.real) } def *(operand: Int): Complex2 = this * new Complex2(operand, 1) def unary_- = new Complex2(-real, imaginary) override def toString() = { real + (if (imaginary < 0) "" else "+") + imaginary + "i" } }
  15. 15. Testing Multiple Defs package com.joeygibson.oopres @RunWith(classOf[JUnitRunner]) class Complex2Test extends FlatSpec with ShouldMatchers { it should "convert int to Complex2" in { val c = new Complex2(1, 2) val d = c + 23 d.toString should equal ("24+2i") } // it should "convert int to Complex2, reversed" in { // val c = new Complex2(1, 2) // val d: Complex2 = 23 + c // // d.toString should equal ("24+2i") // } }
  16. 16. Implicit Conversions  The implicit function must be in scope  It can live in the companion object of either class under consideration  Be careful with implicits, especially when using common types
  17. 17. Implicit Conversions package com.joeygibson.oopres object Complex3 { implicit def intToComplex3(anInt: Int): Complex3 = new Complex3(anInt, 0) } class Complex3(val real: Int, val imaginary: Int) { def +(operand: Complex3): Complex3 = { new Complex3(real + operand.real, imaginary + operand.imaginary) } def *(operand: Complex3): Complex3 = { new Complex3(real * operand.real - imaginary * operand.imaginary, real * operand.imaginary + imaginary * operand.real) } def unary_- = new Complex3(-real, imaginary) override def toString() = { real + (if (imaginary < 0) "" else "+") + imaginary + "i" } }
  18. 18. Testing Implicits package com.joeygibson.oopres @RunWith(classOf[JUnitRunner]) class Complex3Test extends FlatSpec with ShouldMatchers { it should "convert int to Complex3" in { val c = new Complex3(1, 2) val d = c + 23 d.toString should equal ("24+2i") } it should "convert int to Complex3, reversed" in { import com.joeygibson.oopres.Complex3.intToComplex3 val c = new Complex3(1, 2) val d: Complex3 = 23 + c d.toString should equal ("24+2i") } }
  19. 19. Using Both package com.joeygibson.oopres object Complex4 { implicit def intToComplex4(anInt: Int): Complex4 = { printf("Implicitly converting to Complex4n") new Complex4(anInt, 0) } } class Complex4(val real: Int, val imaginary: Int) { def +(operand: Complex4): Complex4 = { new Complex4(real + operand.real, imaginary + operand.imaginary) } def +(operand: Int): Complex4 = this + new Complex4(operand, 0) def *(operand: Complex4): Complex4 = { new Complex4(real * operand.real - imaginary * operand.imaginary, real * operand.imaginary + imaginary * operand.real) } def *(operand: Int): Complex4 = this * new Complex4(operand, 0) def unary_- = new Complex4(-real, imaginary) override def toString() = { real + (if (imaginary < 0) "" else "+") + imaginary + "i" } }
  20. 20. You Can’t Use ++ as Prefix package com.joeygibson.oopres class MyNumber(private var num: Int) { def number: Int = num override def toString = num.toString def ++ = { val n = num num += 1 new MyNumber(n) } def unary_++ = { num += 1 this } }
  21. 21. The First One Works, The Second… package com.joeygibson.oopres @RunWith(classOf[JUnitRunner]) class MyNumberTest extends FlatSpec with ShouldMatchers { it should "post increment" in { val x = new MyNumber(23) val z = x++ z.number should equal (23) x.number should equal (24) } // it should "pre increment" in { // val x = new MyNumber(23) // val z = ++x // // z.number should equal (24) // x.number should equal (24) // } }
  22. 22. ἐγώ ἐιμι  Email: joey@joeygibson.com  Blog: http://joeygibson.com  Original post: http://bit.ly/wNvAl  Twitter: @joeygibson  Facebook: http://facebook.com/joeygibson

×