I am familiar with the concept that Scala's for
comprehensions are just syntactic sugar for monadic operations (map
, withFilter
, foreach
, and flatMap
) and the desugaring is described in this popular answer.
By that logic, I was surprised to find that, when using pattern matching as part of the assignment portion of a for
comprehension, no MatchError
is thrown when the pattern doesn't match an element. Instead, the non-matched element is filtered out:
case class Account(id: String, role: String)
val accounts = Set(Account("a", "ADMIN"), Account("b", "USER"), Account("c", "ADMIN"), Account("d", "USER"), Account("e", "USER"))
val adminIds = for (Account(id, "ADMIN") <- accounts) yield id
// Set("a", "c") (no MatchError on Account("b", "USER")!
I would have expected that comprehension to translate to something like this:
val adminIds = accounts.map { case Account(id, "ADMIN") => id }
// or maybe
val adminIds = accounts.map { account =>
val Account(id, "ADMIN") = account
id
}
But of course those would throw a MatchError
. Instead it seems more similar to this:
val adminIds = accounts.collect { case Account(id, "ADMIN") => id }
However, I've never seen any mention of a for
comprehension desugaring into a collect
call.
So how is this done under the hood?