2

Im a beginner at a scala and am looking for the best/idiomatic way to do what I intend to do here.

This is what I want to do

def someMethod(obj:MyObj):List[String] = {
     List[String]() +: 
      {if (somecondition is satisfied) .. " element"} +: 
      { if (another condition) .. " something else " }


}

That is the method checks some properties of the input parameter object and adds elements to the List (that is to be returned) . If none of the conditions are satisfied , it should return an empty List.

  1. Of course the code doesn't compile . But somehow, it seems intuitive to me that List[T] + Unit should return List[T] . Why am I wrong ?

And 2. Please tell me the right way to do this Scala . If I were iterating over a list of conditions, I could have used comprehensions.

4 Answers 4

4

Rather than filtering Unit, I would rather use unary or empty lists:

def someMethod(obj:MyObj): List[String] = {
    Nil ++
    ( if (somecondition is satisfied) List(" element") else Nil ) ++
    ( if (another condition) .. List(" something else ") else Nil ) ++
}

EDIT: Concerning your comment below, if you find the above code too verbose and hard to maintain, you can still create a helper function:

def optElem[T]( condition: Boolean)( value: => T ): Option[T] = if ( condition ) Option( value ) else None
def someMethod(obj:MyObj): List[String] = {
  Nil ++
  optElem (somecondition is satisfied)( " element") ++
  optElem (another condition)(" something else " )
}
Sign up to request clarification or add additional context in comments.

2 Comments

Yep, much more smarten and efficient
btw, this is exactly what I did before posting the question ( I had used empty lists). I found that much more verbose .. Essentially ,I was looking for a way which a new developer who happens to maintain the code in the future would find the least difficult
3

if-else is an expression in Scala. What you have written becomes:

List[String]() +: 
      {if (somecondition is satisfied) {" element"; () } else () }+: 
      { if (another condition) { " something else "; () } else () }

As you can see, the common branch type is Unit.

The type of the whole expression would be List[Any] since that's the common supertype of String and Unit.

Some ways to achieve what you want:

// #1. Ugly.
def someMethod(obj:MyObj):List[String] = {
  val xs = List[String]() 
  val xs1 = if (somecondition is satisfied) xs :+ " element" else xs
  val xs2 = if (another condition) xs1 :+ " something else" else xs1
  xs2
}

// #2. Better, but uses mutable builder.
def someMethod(obj:MyObj):List[String] = {
  val b = List.newBuilder[String]
  if (somecondition is satisfied) b += " element"
  if (another condition) b += " something else"
  b.result
} 

// #3. Best way IMO, but computationally expensive.
def someMethod(obj:MyObj):List[String] = {
  List[String]() ++
  Option("element").filter(some condition) ++ // for more correct semantics
                                              // use LazyOption from Scalaz.
  Option("something else").filter(another condition)
} 

2 Comments

If the filter condition is not a function of the element, then someBool option "element" is a nice pimp to use from Scalaz.
#3, I think this is what the ++: method is designed for: Option("element").filter(some condition) ++: Option("something else").filter(another condition) ++: Nil. This should be more efficient because it prepends things.
2

You may write it like this:

def someMethod(obj:MyObj):List[String] = {
     List(
      if (somecondition is satisfied) " element", 
      if (another condition) " something else "
     ) collect{ case x: String => x }
}

Suppose all conditions are failed: you'll end up with List(Unit,Unit) first which will be filtered by type. Unit doesn't satisfy type condition inside collect, so result will be empty List of Strings

The good thing is that unlike filter method collect chooses as tight type as it can (so you'll get Sequence of Strings -- this will be infered from function inside collect).

Another possibility is to replace .collect { ... } with flatten, but you'll lose type information.

2 Comments

Can you please explain how this code works? In particular I have no idea what .. does in Scala...
@ziggystar no magic here, in scala .. is nothing, I've just copied some code from op snippet, and I guess he wan't to say that this is just. I've added details on how things work and removed .. to eliminate confusion.
1

Another take on this is to construct a list of options then flatten the list.

def f(obj: MyObj): List[String] = {
  List(if (cond1(obj)) Some("element")        else None,
       if (cond2(obj)) Some("something else") else None).flatten
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.