开发者

Is Option wrapping a value a good pattern?

开发者 https://www.devze.com 2023-02-08 03:47 出处:网络
I recently wrote the following bit of Scala: val f: File = ... // pretend this file came from somewhere

I recently wrote the following bit of Scala:

val f: File = ... // pretend this file came from somewhere
val foo = toFoo(io.Source.fromFile(f).mkString)

I really didn't like the way this flowed. To understand what's happening, you ha开发者_运维问答ve to start with f in the middle, read left to fromFile, read right to mkString, read left again to toFoo. Ugh.

Especially after getting used to functional transformations of sequences, this is difficult to read. My next attempt looks like this:

val foo = Some(f)
  .map(io.Source.fromFile)
  .map(_.mkString)
  .map(toFoo)
  .get

I like the flow of this much better. You can see what happens Is this a good use of the Option class? Or am I abusing it? Is there a better pattern that I can use to achieve the same flow?


This is perfectly okay. However, there is a method |> in Scalaz that does one better, and you can create it yourself if you don't want all of Scalaz:

class Piper[A](a: A) { def |>[B](f: A => B) = f(a) }
implicit def pipe_everything[A](a: A) = new Piper(a)

f |> io.Source.fromFile |> {_.mkString} |> toFoo

Personally, I tend to write a lot of code that requires parentheses and I like methods better than operators in most cases, so in my code I normally call |> "use", but it's the same deal:

f.use(io.Source.fromFile).use(_.mkString).use(toFoo)

In Scala 2.11 or later, you can get the same behavior and improved performance with (slightly) less syntax:

implicit class Piper[A](private val a: A) extends AnyVal {
  def |>[B](f: A => B) = f(a)
}


I have no problems with the other answers given here, but did you consider changing the name of toFoo into something that 'flows' better? I mean, toFoo really smells like something that should be on the right of an expression, but if you rename it into something else, it might fit on the left as well.

// toFoo, as defined by you
val foo = toFoo(io.Source.fromFile(f).mkString)
// Same function, different name
val foo = createFooFrom(io.Source.fromFile(f).mkString)


You add toFoo to String through the pimp my library pattern. Then it becomes:

val foo = Source fromFile f mkString () toFoo
0

精彩评论

暂无评论...
验证码 换一张
取 消