Metod Argumanlarindan Tip Cikarimi

61 views
Skip to first unread message

Volkan Yazıcı

unread,
May 15, 2015, 3:39:12 AM5/15/15
to scala-...@googlegroups.com
Herkese Selamlar,

scala-user e-posta listesine sordugum bir soruda, hala cevapsiz halde beklemedeyim. Belki burada bir bilen cikar dusuncesi ile sorumu sizinle de paylasmak istedim. Sikinti basit, asagidaki kod neden calismaz:

sealed trait StringReader[T] {

  def fromString(input: String): T

}

object StringReader {

  def fromString[T](input: String)(implicit reader: StringReader[T]): T =
    reader.fromString(input)

  implicit object IntStringReader extends StringReader[Int] {

    def fromString(input: String): Int = input.toInt

  }

  implicit object DoubleStringReader extends StringReader[Double] {

    def fromString(input: String): Double = input.toDouble

  }

}

case class Token(intField: Int, doubleField: Double)

import StringReader.fromString

val token = Token(intField = fromString("1"), doubleField = fromString("1.0"))

//Error:(30, 46) ambiguous implicit values:
//  both object IntStringReader in object StringReader of type A$A42.this.StringReader.IntStringReader.type
//and object DoubleStringReader in object StringReader of type A$A42.this.StringReader.DoubleStringReader.type
//match expected type A$A42.this.StringReader[T]
//lazy val token = Token(intField = fromString("1"), doubleField = fromString("1.0"))
//^

Burada illa asagidaki gibi explicit type vermemiz gerekiyor:

val token = Token(intField = fromString[Int]("1"), doubleField = fromString[Double]("1.0"))

Bunun bir kolayi yok mudur? Koskoca Scala, intField = fromString("1"ifadesindeki named argument'in Int oldugunu gorup, fromString metodunu Int ile cagirmayi neden akil edemez?


Iyi calismalar.

Emrehan Tüzün

unread,
May 15, 2015, 7:31:43 AM5/15/15
to scala-...@googlegroups.com
Selamlar,

Burada trait'deki T'nin covariant olmasi gerekiyor cunku StringReader[Int] ve StringReader[Double] da StringReader[T]'in subtype'i olmali.


http://www.scala-js-fiddle.com/gist/65c94c4da8ac363bd5d0

========================================================

sealed trait StringReader[+T] {

    def fromString(input: String): T
}


object StringReader {
  def fromString[T](input: String)(implicit reader: StringReader[T]): T = reader.fromString(input)
   
  implicit object IntStringReader extends StringReader[Int] {
    def fromString(input: String): Int = input.toInt
  }

  implicit object DoubleStringReader extends StringReader[Double] {
    def fromString(input: String): Double = input.toDouble
  }
}

========================================================

import StringReader.fromString

object ScalaJSExample extends js.JSApp{

  case class Token(intField: Int, doubleField: Double)
   
  def main(): Unit = {

    val token = Token(intField = fromString("1"), doubleField = fromString("1.0"))
  }
}

========================================================

Saygilarimla,
Emrehan


--
Bu iletiyi Google Grupları'ndaki "Scala Türkiye" grubuna abone olduğunuz için aldınız.
Bu grubun aboneliğinden çıkmak ve bu gruptan artık e-posta almamak için scala-turkiy...@googlegroups.com adresine e-posta gönderin.
Daha fazla seçenek için https://groups.google.com/d/optout adresini ziyaret edin.

alper özaslan

unread,
May 15, 2015, 7:33:10 AM5/15/15
to scala-...@googlegroups.com

Daha kolay bir yolu yok gibi gözüküyor zamanında bizde benzer bir problemle karşılaşmıştık ama biz reflection kullanarak çözmüştük.Sizin istediğiniz çözümün benzeri burada var tek tek her tip için cast yapmalısınız  ve ayrıca beklenen type bildirmelisiniz. 

http://stackoverflow.com/questions/14791861/casting-string-to-int-using-scala-extractors

Volkan Yazıcı

unread,
May 15, 2015, 7:44:12 AM5/15/15
to scala-...@googlegroups.com
Canimsin Emrehan!
Bu kod niye calisiyor su an hicbir fikrim yok ama calisiyor.
Sonunda covariance/contravariance kullanan bir kodum oldu!
Bana gozuktu yine variance doc'larinin yollari...

Volkan Yazıcı

unread,
May 15, 2015, 8:15:17 AM5/15/15
to scala-...@googlegroups.com
Emrehan, bu sefer de cift yonlu donusum yapamiyorum:

sealed trait StringConverter[+T] {

  def fromString(input: String): T

  def toString(input: T): String

}

object StringConverter {

  def fromString[T](input: String)(implicit converter: StringConverter[T]): T = converter.fromString(input)
  
  def toString[T](input: T)(implicit converter: StringConverter[T]): String = converter.toString(input)

  implicit object IntStringConverter extends StringConverter[Int] {

    def fromString(input: String): Int = input.toInt

    def toString(input: Int): String = input.toString

  }

  implicit object DoubleStringConverter extends StringConverter[Double] {

    def fromString(input: String): Double = input.toDouble

    def toString(input: Double): String = input.toString

  }

}

object ScalaJSExample extends js.JSApp {

  case class Token(intField: Int, doubleField: Double)

  def main(): Unit = {

    val token = Token(
      intField = StringConverter.fromString("1"),
      doubleField = StringConverter.fromString("1.0"))
    println(s"token: $token")

    val string = StringConverter.toString(1)
    println(s"string: ${string}")

  }

}
//Main.scala:9: error: covariant type T occurs in contravariant position in type T of value input
//  def toString(input: T): String
//               ^

Fikri olan? (CS101 ogrencileri gibi random +/- vb. karakter ile brute force bir debugging de sonuc vermedi.)
toString ve fromString'i iki ayri trait icinde tanimlamak da bir cozum olabilir.
Ama ayni trait'te bu isi cozersem cok sik olacak.


2015-05-15 13:31 GMT+02:00 Emrehan Tüzün <emreha...@gmail.com>:

Mehmet Ali GÖZAYDIN

unread,
May 15, 2015, 8:18:19 AM5/15/15
to scala-...@googlegroups.com
Emrehan cozum guzelmis :)

Abi 2. bir generic kullansan?



15 Mayıs 2015 15:15 tarihinde Volkan Yazıcı <volkan...@gmail.com> yazdı:

Volkan Yazıcı

unread,
May 15, 2015, 8:20:51 AM5/15/15
to scala-...@googlegroups.com
Bu olay neden boyle arap sacina dondu anlamis degilim. Verilen bir tip icin String donusumleri tanimlamak istiyorum, basima olunmaz dertler aciliyor.

Fehmi Can Saglam

unread,
May 15, 2015, 8:58:02 AM5/15/15
to scala-...@googlegroups.com, Volkan Yazıcı
Liskov’s substitution principle geregi toString metodunun asagidaki gibi contravariant olmasi gerekiyor:

def toString[S >: T](input: S): String = input.toString

Bu sekilde calisiyor mu?

--
Fehmi Can Saglam
> > sealed trait *StringReader[+T]* {
> --
> Bu e-postayı Google Grupları'ndaki "Scala Türkiye" adlı gruba abone olduğunuz için
> aldınız.
> Bu grubun aboneliğinden çıkmak ve bu gruptan artık e-posta almamak için scala-turkiy...@googlegroups.com
> adresine e-posta gönderin.
> Daha fazla seçenek için, https://groups.google.com/d/optout adresiniz ziyaret
> edin.
>

Emrehan Tüzün

unread,
May 15, 2015, 9:24:37 AM5/15/15
to scala-...@googlegroups.com
Selamlar,

Fehmi Abi hakli. Ek olarak implementasyonda da "def toString[T >: Double](input: T): String = input.toString" seklinde degisiklik yapmak zorunda kaldim. "Best practice" boyle midir bilmiyorum, sadece ilk ornek icin covariant'i onermistim.

http://www.scala-js-fiddle.com/gist/bc986ca7306d7ecdbf60

Saygilarimla,
Emrehan

Volkan Yazıcı

unread,
May 15, 2015, 11:14:59 AM5/15/15
to Fehmi Can Saglam, scala-...@googlegroups.com
Fehmi, Emrehan, fakat bu sefer de Int'e (ya da Double'a) ulasamiyorum.
Soyle ki: def toString[S >: Int](input: S): String = (input * 2).toString compile olmuyor.

Fehmi Can Saglam

unread,
May 15, 2015, 12:49:45 PM5/15/15
to Volkan Yazıcı, scala-...@googlegroups.com
Bence buradaki sorun belli bir cozume odaklaniyor olmamiz. Scala tecrubem sunu soyluyor: Eger bir yontem ile giderken abuk sabuk sorunlarla karsilasiyorsan dur ve geri don. Cozmeye calistigin problemin contextini tam olarak bilemiyorum. Ama soyle bir sey ciziktirdim. Belki fikir verebilir: 

http://www.scala-js-fiddle.com/gist/96e2b69c2b939d9fa7b3?

--
Fehmi Can Saglam


On 15 May 2015 at 18:14:59, Volkan Yazıcı (volkan...@gmail.com) wrote:
> Fehmi, Emrehan, fakat bu sefer de Int'e (ya da Double'a) ulasamiyorum.
> Soyle ki: *def toString[S >: Int](input: S): String = (input * 2).toString*

Volkan Yazıcı

unread,
May 18, 2015, 8:59:09 AM5/18/15
to Fehmi Can Saglam, scala-...@googlegroups.com
Evvela ugrasi icin cok tesekkurler Fehmi. Fakat bu cozum problemi tekrar basa donduruyor: http://www.scala-js-fiddle.com/gist/64a5b2280b1d9238ae74 Soyle ki, bu sefer implicit'leri apply() metodunun icinde elle inject ediyoruz, ki zaten ben bunu yapmak istemiyordum. Ben Int istiyorum, bu String'ten convert edilip de mi gelecek, bana dogrudan Int mi verilecek, bilmiyorum ve bilmek de istemiyorum; bu kullaniciya kalmis bir bahis.

Erdem Agaoglu

unread,
May 21, 2015, 8:52:08 AM5/21/15
to scala-...@googlegroups.com, fehmica...@gmail.com
Selam Volkan,

Bu sirada isine yarar bir sey cikti mi bilemiyorum ama soyle bir seyler uydurdum.


On Friday, May 15, 2015 at 6:14:59 PM UTC+3, Volkan Yazıcı wrote:
Fehmi, Emrehan, fakat bu sefer de Int'e (ya da Double'a) ulasamiyorum.
Soyle ki: def toString[S >: Int](input: S): String = (input * 2).toString compile olmuyor.

Buradan anladigim kadariyla, bir tip icin tek yerde String donusumleri tanimlamaya calisiyorsun. Fakat trait'teki tek parametreyi hem covariant hem contravariant olarak kullanman gerekiyor. Oyle bir sey yapamadigin icin bu fonksiyonda ikinci bir parametre tanimliyorsun. Burasi contravariant oldugu icin implementasyondaki tipten uzaklasmis oluyor.

Onun yerine ikinci (contravariant) parametreyi dogrudan trait'e tanimlayabilirsin.

sealed trait StringConverter[+T, -S] {
  def fromStr(input: String): T
  def toStr(input: S): String
}

bu durumda implementasyonlarda tipleri iki defa veriyorsun tabi, birisi return tipleri icin, digeri arguman tipleri icin:

object StringConverter {
  
  implicit object IntStringConverter extends StringConverter[Int, Int] {
    def fromStr(input: String): Int = input.toInt
    override def toStr(input: Int): String = (input * 2).toString
  }

  implicit object DoubleStringConverter extends StringConverter[Double, Double] {
    def fromStr(input: String): Double = input.toDouble
    def toStr(input: Double): String = (input / 2).toString
  }
}

utility fonksiyonlarda da ayni sekilde:

  def fromStr[T, S](value: String)(implicit c: StringConverter[T, S]): T = c.fromStr(value)
  def toStr[T, S](value: S)(implicit c: StringConverter[T, S]): String = c.toStr(value)


Son halde soyle kullanabildim:

object Volkan {
  
  case class Token(intField: Int, doubleField: Double)

  def main(args: Array[String]) {
    val token = Token(StringConverter.fromStr("1"), StringConverter.fromStr("1.0"))
    println(s"token: $token")

    println(s"int: ${StringConverter.toStr(1)}")
    println(s"dbl: ${StringConverter.toStr(1.0)}")

  }

}

Cikti:

[info] Running Volkan 
token: Token(1,1.0)
int: 2
dbl: 0.5

Bu T ve S arasinda bir iliski gosterebiliyo muyuz onu bilemedim.
Reply all
Reply to author
Forward
0 new messages