Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how can I call a method in auxiliary constructor?

Tags:

scala

class foo(val x:Int){
  def convertToInt(z:string) = {do somthing to convert a string to an integer}
  def this(y:string) = this(convertToInt(y))
}

calling convertToInt in auxiliary constructor (this(y:string)) causes this error:

error: not found: value convertToInt

I know I can use a singleton object and pack all static functions like convertToInt into it, but is it a good solution?

object foo{
    def convertToInt(z:string) = {do somthing to convert a string to an integer}
}   
class foo(val x:Int){
    def this(y:string) = this(foo.convertToInt(y))
}
like image 232
Mohammad Reza Esmaeilzadeh Avatar asked Feb 16 '11 08:02

Mohammad Reza Esmaeilzadeh


2 Answers

I think in this case the best solution would be to use factory methods instead of public constructor.

So you can define your constructor private and provide factory apply methods in companion object:

class Foo private (val x:Int) 

object Foo {
    def apply(i: Int) = new Foo(i)
    def apply(s: String) = new Foo(convertToInt(s))

    def convertToInt(s: String) = s.toInt
}   

println(Foo(512).x)
println(Foo("256").x)

You can find more information about constructor vs factory method here:

Constructors vs Factory Methods

It's the same for Scala.

Update

As an example of alternative solution I made very generic solution. Foo class can now work with any class that ever existed or can be created in future, assuming, that this type can be converted (you can define how it should be converted) to/from Int:

trait Convertable[From, To] {
    def convert(from: From): To
}

object Convertable {
    implicit val intString = new Convertable[Int, String] {
        def convert(from: Int) = from toString // your logic here
    }
    
    implicit val stringInt = new Convertable[String, Int] {
        def convert(from: String) = from toInt // your logic here
    }

    implicit def self[T] = new Convertable[T, T] {
        def convert(from: T) = from
    }
}

case class Foo[T](original: T)(implicit toInt: Convertable[T, Int], fromInt: Convertable[Int, T]) {
    val x: Int = toInt convert original
    def toOriginal = fromInt convert x
}


println(Foo(512) x)
println(Foo("256") x)

(I could define toOriginal by just returning = original, but it would be too boring :)

As you can see, this solution is generic and more complicated. But as far as I saw, many application need some kind of conversion between different primitive values and/or classes. So in many cases it's sutable (and may be event considered very good) solution for many cases and may be for your also. But it's often impossible to tell what's "the best" solution for all possible cases.

like image 99
tenshi Avatar answered Oct 21 '22 18:10

tenshi


by using angle's offer about factory method instead of Auxiliary Constructor:

class Foo(val s:String) {
      val s = ""
      def bar2:String = s+s
      def bar3:List[Char] = s.toList
}

object Foo extends{
      def bar1(y:List[Char]):String =y.mkString
      def apply(s:String)= new Foo(s)
      def apply(y:List[Char])= new Foo(bar1(y))
}

client code:

val foo1 = Foo(List('a','b'))
println(foo1.s)
println(foo1.bar2)
println(foo1.bar3)
like image 44
Mohammad Reza Esmaeilzadeh Avatar answered Oct 21 '22 20:10

Mohammad Reza Esmaeilzadeh