How can I fix this break: loop over two iterators and break when condition is satisfied

As a minimal example I wrote this code:

  1. Make a 2D matrix which contains numbers randomly generated from 0 to 9.
  2. Find the indices of first number divisible by 3.

I have two part question:

  1. What changes should I make to fix the code while keep current structure of for expression. Right now it gives compilation error as:

No given instance of type scala.util.boundary.Label[Int] was found for parameter label of method break in object boundary.\nI found:\n\n evidence$1\n\nBut parameter evidence$1 does not match type scala.util.boundary.Label[Int].

  1. Can I do this without a var?
import scala.util.boundary, boundary.break

val random = new scala.util.Random
val matrix = (0 until 10).map(_ =>
    (0 until 10).map(_ => random.nextInt(10)).toArray
).toArray

def findDivisibleby3: Option[(Int, Int)] =
    var result: Option[(Int, Int)] = None

    result = boundary:
        for
            i <- 0 until 10
            j <- 0 until 10
            if matrix(i)(j) % 3 == 0
        do
            break(Some(i, j))

    result
end findDivisibleby3

object Main extends App:
    findDivisibleby3
end Main

I gave it a shot:

2 Likes

Thanks! this does work. But rules of syntax are something I cannot get around to.

1 Like

The error is actually:

No given instance of type scala.util.boundary.Label[Some[(Int, Int)]]

Look at the type: Some[(Int, Int)] that it wants.
The reason is that your for ... do ... is an expression that does not give an interesting value but does something; so the type of that expression is Unit and the uninteresting value is () which does not match the returntype of your function.
(for loops that gives interesting values should use the for ... yield ... -expressions syntax)
The solution by @spamegg1 works as the returntype matches what is returned.

2 Likes

I agree that syntax should not get in the way.

Using a var is not terrible.

def findDivisibleby3: Option[(Int, Int)] =
  var result: Option[(Int, Int)] = None
  boundary:
    for
      i <- 0 until 10
      j <- 0 until 10
      if matrix(i)(j) % 3 == 0
    do
      result = Some(i -> j)
      break()
  result

Also note

val matrix = Array.fill(9, 9)(random.nextInt(10))

and

@main def test = println(findDivisibleby3)

Worth adding

-opt -opt-inline:'scala.Predef$*'

I see the idiom Some(i → j) does not use specialized tuple, even under -opt. (Edit: that will happen after the arrow becomes inline.)

2 Likes