Type mismatch, expected: ActionBuilder, actual: Unit.

During my simulation I use function with session attributes. It lookes like:

exec(session => {
  if (session.contains(sn1) && session.contains(sn2) && session.contains(sn3)) {
    ..some logic
  }
  session
})

The thing is that I need to insert it inside a for loop. But when I do so, I get the following error:
Type mismatch, expected: ActionBuilder, actual: Unit.

If I do the following trick I am not getting any output:
def someFunction = {
exec(session => {
for loop with my function
session
})

Using function without the loop gives me the output I need. What can I do to solve this type mismatch issue?

I suspect you have a return in your loop…

My loop doesn’t have any returns:

for (a <- 0 until array.length - 2;
     b <- a + 1 until array.length - 1;
     c <- b + 1 until array.length) {
  verify(array(a), array(b), array(c))

And verify function is ok. Basically, what confuses me the most is that the loop with verify function gives the error, when This is ok:
def verifyArray(…) = {
verify(…)
verify(…)
verify(…)

verify(…)
}

Could you share a full example, please (that should compile except for your issue)?


def verifySN(sn1:String, sn2: String, sn3: String) = {
 exec(session => {
 if (session.contains(sn1) && session.contains(sn2) && session.contains(sn3)) {
 modifyFile(sn1.last.toString)
 verify(
 config,
 Integer.parseInt(sn1.last.toString),
 session(sn1).as[String].toLong,
 session(sn2).as[String].toLong,
 session(sn3).as[String].toLong,
 System.out)
 }
 session
 })
}

def verify(sn1: String, sn2: String, sn3: String) = {
 exec(verifySN(sn1.concat("db1"), sn2.concat("db1"), sn3.concat("db1")))
}

def verifyArray(array: Array[String]) = {
 if (array.length == 3) {
 exec(verify(array(0), array(1), array(2)))
 } else {
 for (a <- 0 until array.length - 2;
 b <- a + 1 until array.length - 1;
 c <- b + 1 until array.length) {
   exec(verify(array(a), array(b), array(c)))
 }}
}

The exec in the for loop (verifyArray) function doesn’t compile. However this one does:
`


def verifyArray(array: Array[String]) = {
  if (array.length == 3) {
    exec(verify(array(0), array(1), array(2)))
  } else {
    exec(verify(array(0), array(1), array(2)))
    .exec(verify(array(0), array(1), array(3)))
    .exec(verify(array(0), array(1), array(4)))
    .exec(verify(array(0), array(2), array(3)))
    .exec(verify(array(0), array(2), array(4)))
    .exec(verify(array(0), array(3), array(4)))
    .exec(verify(array(1), array(2), array(3)))
    .exec(verify(array(1), array(2), array(4)))
    .exec(verify(array(1), array(3), array(4)))
    .exec(verify(array(2), array(3), array(4)))
  }
}

`

As is, the sample you provided doesn’t compile because:

  • modifyFile isn’t defined => created one
  • there’s a recursive loop between verifySN and verify but none of them have explicit return types => set ChainBuilder
  • verify call in verifySN pass 6 parameters yet verify takes only 3

I confused you with my function names. Function modifyFile is a created one, it only modifies some file’s content using scala.sys.process.Process. Function verify is imported from other class and has a return type of boolean. All together it looks like this:


def modifyFile(dbNumber: String) = {
 Process(Seq("bash", "-c",
 s"sed -i 's|ID = [1-3]|ID = $dbNumber|' conf.cfg && "
 + s"sed -i 's|db[1-3]|db$dbNumber|' conf.cfg")) !
}

def verifySN(sn1:String, sn2: String, sn3: String): ChainBuilder = {
 exec(session => {
 if (session.contains(sn1) && session.contains(sn2) && session.contains(sn3)) {
 modifyFile(sn1.last.toString)
 VerifierTool.verify(
 secureLogConfig,
 Integer.parseInt(sn1.last.toString),
 session(sn1).as[String].toLong,
 session(sn2).as[String].toLong,
 session(sn3).as[String].toLong,
 System.out)
 }
 session
 })
}

def verifyAll(sn1: String, sn2: String, sn3: String): ChainBuilder = {
 exec(verifySN(sn1.concat("db1"), sn2.concat("db1"), sn3.concat("db1")))
 .pause(5)
 .exec(verifySN(sn1.concat("db2"), sn2.concat("db2"), sn3.concat("db2")))
 .pause(5)
 .exec(verifySN(sn1.concat("db3"), sn2.concat("db3"), sn3.concat("db3")))
}

def verifyArray(array: Array[String]) = {
 if (array.length == 3) {
 exec(verifyAll(array(0), array(1), array(2)))
 } else {
 for (a <- 0 until array.length - 2;
 b <- a + 1 until array.length - 1;
 c <- b + 1 until array.length) {
 exec(verifyAll(array(a), array(b), array(c)))
 }
 }
}

I added the following lines to your sample and it compiles just fine:

object VerifierTool {
def verify(a: Any, b: Any, c: Any, d: Any, e: Any, f: Any): Unit = ???
}

val secureLogConfig: Any = ???

Are you sure you don’t just have false negative from the crappy IntelliJ Scala compiler?

When I try to use these functions in the simulation, then I get the error:


val restartTestScenario = scenario("Eternity Test Restart")
 .exec(verifyArray(Array("sn1", "sn2", "sn3")))

Type mismatch. Expected: ActionBuilder. Actual: Any.

Finally something that makes sense.

verifyArray returns Any because the first branch return a ChainBuilder while the second one returns nothing (Unit), so the compiler infers the closest common type: Any.

def verifyArray(array: Array[String]): Seq[ChainBuilder] = {
if (array.length == 3) {
Seq(exec(verifyAll(array(0), array(1), array(2))))
} else {
for (
a ← 0 until array.length - 2;
b ← a + 1 until array.length - 1;
c ← b + 1 until array.length
) yield exec(verifyAll(array(a), array(b), array(c)))
}
}

Thanks you so much. It works perfectly good now. The most amazing part is that I didn’t know about “yield”, and how to use it. So many things to learn. Btw, is it possible to use “map” instead of “yield”.

Thanks you so much. It works perfectly good now. The most amazing part is
that I didn't know about "yield", and how to use it. So many things to
learn. Btw, is it possible to use "map" instead of "yield".

Baby steps :wink:
First learn Scala basics.