This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Idiom idiocy

3 replies
Robin Barooah
Joined: 2008-12-21,
User offline. Last seen 3 years 27 weeks ago.
Hi,
So a few days ago I defined this:
    object Lang {                def nullable[T] (value:T) :Option[T] = if (value == null) None else Some(value)                 implicit def optionToConvertable[T](option:Option[T]) = new ConvertableOption(option)                class ConvertableOption[T](val option:Option[T]) {            def convert[S] (convert: (T) => S) :Option[S] = option match {                 case None => None                case Some(value) => Some(convert(value))            }                        def convertOption[S] (convert: (T) => Option[S]) :Option[S] = option match {                 case None => None                case Some(value) => convert(value)            }        }            }
My original intention was just to simplify dealing with java libraries - i.e. make it easy to turn things that return null into Options, and to convert a java class into something more scalaesque in a quick and easy step e.g.:
        def fromCache (key:String) :Option[String] =             nullable(cache.get(cacheKey(key))) convert {                _.getValue.asInstanceOf[String]            }
However since writing it I find myself using it a lot to create chains of operations on the contents of an option:
         def value (key:String) :Option[S3Value] = s3Object (key) convert (o => new S3Value(o))                            def apply (key:String) :Option[String] = value (key) convert (v => v.toString)
I don't hail from a strongly FP background.  Is there an obvious way that people normally do this that I'm missing?
--
-Robin

Robin Barooah
http://www.sublime.org
Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: Idiom idiocy
It looks to me like convert and convertOption are just map and flatMap, available in the standard library.

You can chain lots of calls to map and flatMap together with for-comprehensions.

  for {
    obj <- s3Object(key)
    value <- new S3Value(obj)
  } yield value.toString  // returns Option[String]

--j

On Mon, Feb 16, 2009 at 5:58 PM, Robin <robin@sublime.org> wrote:
Hi,
So a few days ago I defined this:
    object Lang {                 def nullable[T] (value:T) :Option[T] = if (value == null) None else Some(value)                 implicit def optionToConvertable[T](option:Option[T]) = new ConvertableOption(option)                class ConvertableOption[T](val option:Option[T]) {            def convert[S] (convert: (T) => S) :Option[S] = option match {                 case None => None                case Some(value) => Some(convert(value))            }                        def convertOption[S] (convert: (T) => Option[S]) :Option[S] = option match {                 case None => None                case Some(value) => convert(value)            }        }            }
My original intention was just to simplify dealing with java libraries - i.e. make it easy to turn things that return null into Options, and to convert a java class into something more scalaesque in a quick and easy step e.g.:
        def fromCache (key:String) :Option[String] =             nullable(cache.get(cacheKey(key))) convert {                _.getValue.asInstanceOf[String]            }
However since writing it I find myself using it a lot to create chains of operations on the contents of an option:
         def value (key:String) :Option[S3Value] = s3Object (key) convert (o => new S3Value(o))                            def apply (key:String) :Option[String] = value (key) convert (v => v.toString)
I don't hail from a strongly FP background.  Is there an obvious way that people normally do this that I'm missing?
--
-Robin

Robin Barooah
http://www.sublime.org

Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: Idiom idiocy
Oops, that should be

   val value = new S3Value(obj)

In which case you're not really chaining lots of maps and flatMaps, but you get the idea.

--j

On Mon, Feb 16, 2009 at 6:09 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
It looks to me like convert and convertOption are just map and flatMap, available in the standard library.

You can chain lots of calls to map and flatMap together with for-comprehensions.

  for {
    obj <- s3Object(key)
    value <- new S3Value(obj)
  } yield value.toString  // returns Option[String]

--j

On Mon, Feb 16, 2009 at 5:58 PM, Robin <robin@sublime.org> wrote:
Hi,
So a few days ago I defined this:
    object Lang {                 def nullable[T] (value:T) :Option[T] = if (value == null) None else Some(value)                 implicit def optionToConvertable[T](option:Option[T]) = new ConvertableOption(option)                class ConvertableOption[T](val option:Option[T]) {            def convert[S] (convert: (T) => S) :Option[S] = option match {                 case None => None                case Some(value) => Some(convert(value))            }                        def convertOption[S] (convert: (T) => Option[S]) :Option[S] = option match {                 case None => None                case Some(value) => convert(value)            }        }            }
My original intention was just to simplify dealing with java libraries - i.e. make it easy to turn things that return null into Options, and to convert a java class into something more scalaesque in a quick and easy step e.g.:
        def fromCache (key:String) :Option[String] =             nullable(cache.get(cacheKey(key))) convert {                _.getValue.asInstanceOf[String]            }
However since writing it I find myself using it a lot to create chains of operations on the contents of an option:
         def value (key:String) :Option[S3Value] = s3Object (key) convert (o => new S3Value(o))                            def apply (key:String) :Option[String] = value (key) convert (v => v.toString)
I don't hail from a strongly FP background.  Is there an obvious way that people normally do this that I'm missing?
--
-Robin

Robin Barooah
http://www.sublime.org


Jorge Ortiz
Joined: 2008-12-16,
User offline. Last seen 29 weeks 4 days ago.
Re: Idiom idiocy
Ok, that was the worst explanation ever. Let me try again. Let's say I'm working with Scala Maps, which have a method with signature: get(key: K): Option[V]

  val result = for {
    value1 <- map1.get(key1)
    value2 <- map2.get(key2)
    value3 <- map3.get(key3)
  } yield operation(value1, value2, value3)

If operation has method signature: operation(key1: Key1, key2: Key2, key3: Key3): Result

Then val 'result' will be of type Option[Result].

If any of the calls to 'get' returns None, then 'result' will be None as well. If all of the calls to 'get' succeed, then 'result' will be Some(x), where x is whatever got returned by 'operation'.

The code above basically gets translated to something like:

  val result = map1.get(key1).flatMap(value1 =>
    map2.get(key2).flatMap(value2 =>
      map3.get(key3).map(value3 =>
        operation(value1, value2, value3))))

Now, If I want the computation to continue regardless of whether map2 contains key2 or not, then I have to provide a default value for value2:

  val result = for {
    value1 <- map1.get(key1)
    val value2 = map2.getOrElse(key2, default)
    value3 <- map3.get(key3)
  } yield operation(value1, value2, value3)

This uses the getOrElse method defined on Maps, but Option also has its own getOrElse method.

--j

On Mon, Feb 16, 2009 at 6:10 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
Oops, that should be

   val value = new S3Value(obj)

In which case you're not really chaining lots of maps and flatMaps, but you get the idea.

--j

On Mon, Feb 16, 2009 at 6:09 PM, Jorge Ortiz <jorge.ortiz@gmail.com> wrote:
It looks to me like convert and convertOption are just map and flatMap, available in the standard library.

You can chain lots of calls to map and flatMap together with for-comprehensions.

  for {
    obj <- s3Object(key)
    value <- new S3Value(obj)
  } yield value.toString  // returns Option[String]

--j

On Mon, Feb 16, 2009 at 5:58 PM, Robin <robin@sublime.org> wrote:
Hi,
So a few days ago I defined this:
    object Lang {                 def nullable[T] (value:T) :Option[T] = if (value == null) None else Some(value)                 implicit def optionToConvertable[T](option:Option[T]) = new ConvertableOption(option)                class ConvertableOption[T](val option:Option[T]) {            def convert[S] (convert: (T) => S) :Option[S] = option match {                 case None => None                case Some(value) => Some(convert(value))            }                        def convertOption[S] (convert: (T) => Option[S]) :Option[S] = option match {                 case None => None                case Some(value) => convert(value)            }        }            }
My original intention was just to simplify dealing with java libraries - i.e. make it easy to turn things that return null into Options, and to convert a java class into something more scalaesque in a quick and easy step e.g.:
        def fromCache (key:String) :Option[String] =             nullable(cache.get(cacheKey(key))) convert {                _.getValue.asInstanceOf[String]            }
However since writing it I find myself using it a lot to create chains of operations on the contents of an option:
         def value (key:String) :Option[S3Value] = s3Object (key) convert (o => new S3Value(o))                            def apply (key:String) :Option[String] = value (key) convert (v => v.toString)
I don't hail from a strongly FP background.  Is there an obvious way that people normally do this that I'm missing?
--
-Robin

Robin Barooah
http://www.sublime.org



Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland