0

Background

I'm using a java web UI library (Vaadin, but that's irrelevant - I'm not using the Scaladin add-on) which has a TextField that has a method setValue(String) to set the current text value.

As it's a java library, it has no notion of Option but can represent a null value as e.g. an empty string (it's configurable). So I've written an implicit wrapper class as follows:

implicit class ExtendedTextField(self: TextField) {
    def :=(value: String) = self.setValue(value)
    def :=(maybeValue: Option[String]) = self.setValue(maybeValue.orNull)
}

This allows me to set the value using the := operator directly on a TextField instance and allows me to deal with the Option to null conversion in a single place.

Problem

When I have e.g. a form with a bunch of text fields showing the values for some object of type X, then if I have an Option[X] I'm doing this:

fieldA := (for (x <- maybeX) yield x.valueA)
fieldB := (for (x <- maybeX) yield x.valueB)
fieldC := (for (x <- maybeX) yield x.valueC)
...

In other words, I want to call the := with Some(string) in case I have maybeX is Some but with None if maybeX is none. In addition, suppose x.valueD is actually an Option[String], I would call

fieldD := (for (x <- maybeX) yield x.valueD).flatten

(I could simply always call flatten, but it wouldn't have an effect if there are no nested options)

Is there a nicer way to write this, getting rid of all the duplicate for comprehensions and flattening the result? Maybe using a macro?

I'd prefer not to use reflection (I'm sure it will be possible to put all the fields in a sequence, zip it with a sequence containing the property names, then map this using a function that returns None or does the relflection lookup, and also flattens the result).

herman
  • 11,740
  • 5
  • 47
  • 58

1 Answers1

2

That is about as compact as it gets since it is a set of different map transforms you want to perform if it has got a value. You might get it a bit shorter with map instead of a for comprehension:

fieldA := x.map(_.valueA)
fieldB := x.map(_.valueB)
fieldC := x.map(_.valueC)

and for you case of an option inside of x flatMap which gets you the same result as map + flatten:

fieldD := x.flatMap(_.valueD)

You might be able to create a macro that does this but you will then trade of this repetition against how hard your code will be to understand, and the gain will probably be very little.

johanandren
  • 11,249
  • 1
  • 25
  • 30
  • Well, I was thinking about defining := operators for Tuple2, Tuple3 etc. but I guess if I can import x._ there's not much point in trying to make it any shorter than `fieldA := map(_.valueA)`. Thanks for the suggestion to use map / flatMap! – herman Sep 14 '14 at 21:19