Scala Implicit Type Conversion of Classes with Type Parameters

151 views Asked by At

I'm trying to add functionality to the scala.collection.Iterable trait, more specifically, a printerate function that iterates through the elements and prints them out (to the console if there are no parameters, otherwise to the outputstream param). I'm using a predefined extension method that I created for object, printSelf(). However, this is causing an compiler error, 'Value printSelf is not a member of type parameter Object.' I'd also like to have this an a separate file so that it's easy for me to use between several projects and applications.

Here's my current code for my conversion file:

import java.io.OutputStream
import scala.collection.Iterable

package conversion{
  class Convert {
    implicit def object2SuperObject(o:Object) = new ConvertObject(o)
    implicit def iterable2SuperIterable[Object](i:Iterable[Object]) = new ConvertIterable[Object](i)
  } 
  class ConvertObject(o:Object){
    def printSelf(){
      println(o.toString())
    }
    def printSelf(os:OutputStream){
      os.write(o.toString().getBytes())
    }
  }
  class ConvertIterable[Object](i:Iterable[Object]){
    def printerate(){
      i.foreach {x => x.printSelf() }
    }
    def printerate(os:OutputStream){
      i.foreach { x => x.printSelf(os) }
    }
  }
}

I'm also getting a similar error in the code that's trying to test this out, 'value printerate is not a member of scala.collection.immutable.Range':

import conversion.Convert
package test {
  object program extends App {
    new testObj(10) test
  }
  class testObj(i: Integer) {
    def test(){
      val range = 0.until(i)
      0.until(i).printerate()
    }
  }
}

What's wrong with the way that I'm approaching this type conversion?

1

There are 1 answers

0
Gal On BEST ANSWER

Several things in fact:

  1. Convert should be an object, not a class.
  2. You use Object instead of Any
  3. You use Object as a generic type identifier, instead of the much less confusing T.
  4. You do not import the implicit definitions (it's not enough to import the object itself).

This should work:

package conversion {
  object Convert {
    implicit def object2SuperObject(o: Any) = new ConvertObject(o)
    implicit def iterable2SuperIterable[T](i:Iterable[T]) = new ConvertIterable[T](i)
  } 
  class ConvertObject(o: Any){
    def printSelf(){
      println(o.toString())
    }
    def printSelf(os:OutputStream){
      os.write(o.toString().getBytes())
    }
  }
  class ConvertIterable[T](i:Iterable[T]){
    import Convert.object2SuperObject
    def printerate(){
      i.foreach {x => x.printSelf() }
    }
    def printerate(os:OutputStream){
      i.foreach { x => x.printSelf(os) }
    }
  }
}

import conversion.Convert._

Second file:

package test {
  object program extends App {
    new testObj(10) test
  }
  class testObj(i: Integer) {
    def test(){
      val range = 0.until(i)
      0.until(i).printerate()
    }
  }
}