whatsinthename
whatsinthename

Reputation: 2157

Method returns unit instead of string in scala

I am trying to get the string out of the Set type in Scala. However, no matter what I try it is returning Unit as a return type instead of a string.

if (!validationMessages.isEmpty) {
      dataTuple = (parsedJson.toString(), for (s <- validationMessages.toString()){
        s.toString()
      })
      println(dataTuple)
    }
    else {
      dataTuple = (parsedJson.toString(), "some string...")
    }  

Basically, I am trying to return a tuple like (String, String). What am I missing?

Upvotes: 0

Views: 454

Answers (2)

Tim
Tim

Reputation: 27356

The value of a block is the value of the last expression in the block. In this case the value of the if part is

println(dataTuple)

and the value of the else part is

dataTuple = (parsedJson.toString(), "some string...")

Both of these expressions return Unit so the result is Unit.

The quick fix is to make dataTuple the last statement in each branch:

if (!validationMessages.isEmpty) {
      dataTuple = (parsedJson.toString(), for (s <- validationMessages.toString()){
        s.toString()
      })
      println(dataTuple)
      dataTuple
    } else {
      dataTuple = (parsedJson.toString(), "some string...")

      dataTuple
    } 

But also consider something like this as a simpler solution:

val msg = 
    if (validationMessages.nonEmpty) {
       validationMessages.mkString(", ")
    } else {
       "some string"
    }
(parsedJson.toString, msg)

The mkString is an attempt to replace this code:

for (s <- validationMessages.toString()) {
  s.toString()
}

This code appears to be trying to create a string by combining all the validation messages, but it actually returns Unit because the for does not have a yield. mkString calls toString on each element of the Set and then creates a string by putting ", " between each element. This seems to be roughly what is wanted and should be easy to modify to the actual requirement.

Upvotes: 5

mbbush
mbbush

Reputation: 182

Why is the code behaving like this?

That code has return type Unit, because that is the return type of both branches of the if statement.

The if branch ends with println(dataTuple), which returns Unit. The else branch ends with dataTuple = ..., which is variable assignment, which returns Unit. If you wanted it to return the tuple stored in dataTuple, you'd just have to add dataTuple to the end.

What do you probably want to do instead?

(parsedJson.toString, validationMessages.mkString("[", ", ", "]"))

That will return a tuple containing first parsedJson as a string, and second, each element of validationMessages, in arbitrary order (because Set is unordered), starting with [, with a , between consecutive elements, and ] at the end.

So if parsedJson was {"key1": "value1"} and validationMessages was Set("unexpected key: key1", "missing key: key0") this would return ("{"key1":"value1"}",["unexpected key: key1", "missing key: key0"].

If you don't want to put something special at the beginning/end of your .mkString, you can call it with only the middle argument (the delimiter).

If validationMessages is empty, then validationMessages.mkString("delimiter") returns an empty string, and validationMessages.mkString("start", "delimiter", "end") returns "startend".

One of the beautiful things about scala is how you can do complex things in a single line (as long as you know the language well enough).

Upvotes: 4

Related Questions