Reputation: 15917
I find that after chaining Option using orElse, the element type changed, which made me impossible to use it as expected.
For example:an xml with the type of NodeSeq
.
scala> xml1.headOption map { head => None } orElse xml2.lastOption map {last => Some(last)}
res11: Option[Some[ScalaObject with Equals]] = Some(Some(None))
before the orElse
, head
is of type Node
, which is correct, but last
should also be of type Node
, but the compiler thinks it is of type ScalaObject with Equals
, and i cannot pass last
to functions take a Node
as a parameter.
I can cast it using last.asInstanceOf[Node]
, is there a way to avoid this cast and still make last
of type Node
?
Upvotes: 1
Views: 320
Reputation: 33019
Try this instead (notice the added parenthesis):
(xml.headOption map { head => None }) orElse (xml.lastOption map {last => Some(last)})
The problem is that the map
is being applied after orElse
rather than before orElse
. In other words, the expression is parsed like this:
((xml.headOption map { head => None }) orElse xml.lastOption) map {last => Some(last)}
Since the expression on the left-hand-side of orElse
has type Option[Option[Node]]
but the right-hand-side expression has type Option[Node]
the lowest common supertype is Option[ScalaObject with Equals]
.
Scala's flexible syntax can make coding very nice at times, but other times it results in crazy things like this. For complex expressions like this it's a good idea to add parenthesis to make your meaning more explicit.
Upvotes: 3
Reputation: 2829
In general, I think you need to re-examine what exactly you're doing, since it doesn't make much sense. xml.headOption map { head => None }
is always going to resolve to Some(None)
(in your case), which is rarely what you want. My best guess is that you want something like:
xml.headOption.orElse(xml.lastOption)
Though it's worth noting that if headOption is None, so will lastOption be.
Edit: As Dao Wen points out, it's quite possible to infer the correct upper bound of Option[Node]
in this example, and the issue obscuring it was that of the wrong orElse
being called. However, I still think that the real issue here is that what you're doing doesn't make much sense, and should probably be reconsidered.
Upvotes: 1
Reputation: 29528
map {head => None}
is probably not what you intend. It that a typo?
After that, you have an Option[None.type]
, a not too interesting type which has only two possible values, None
and Some(None)
.
As your xml is not empty, it happens to be Some(None).
xml.LastOption
has type Option[Node]
So when you do the orElse
bettwen them it looks for the most precise common supertype (least upper bound), of None.type
and Node
. And there is none of interest, it happens to be ScalaObject with Equals
, it could just as well be AnyRef
.
Your final map {last => Some(last)}
is rather strange too. What do you intend there?
Upvotes: 0