Skip to content
This repository was archived by the owner on Dec 22, 2021. It is now read-only.

Conversation

@julienrf
Copy link
Contributor

Fixes #139.

The approach is to provide not just implicit BuildFrom instances but implicit FromSpecificIterable instances (which have a newBuilder() method that takes no initial collection).

However this solution raises a ambiguous implicits error when used with sorted Map collections (e.g. TreeMap). But I believe this is a limitation of the current way we prioritize implicits. See my comments in the diff for more details.

@julienrf julienrf requested review from Ichoran and szeiger July 24, 2017 11:26
def newBuilder(from: CC[A]): Builder[E, CC[E]] = from.sortedIterableFactory.newBuilder[E]()
def fromSpecificIterable(from: CC[A])(it: Iterable[E]): CC[E] = from.sortedIterableFactory.fromSpecificIterable(it)
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These definitions are not anymore necessary: they have been superseded by the implicit definitions in factories.

// TODO wrap with assert when HashMap’s equality is correctly implemented
Parse.parseCollection[(Int, Int), immutable.HashMap[Int, Int]](immutable.HashMap).parse("1-2|3-4").contains(immutable.HashMap((1, 2), (3, 4)))
assert(Parse.parseCollection[Int, immutable.List[Int]].parse("1|2|3").contains(1 :: 2 :: 3 :: immutable.Nil))
assert(Parse.parseCollection[(Int, Int), immutable.HashMap[Int, Int]].parse("1-2|3-4").contains(immutable.HashMap((1, 2), (3, 4))))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The factory is now provided implicitly, which was the initial goal of this PR.

def apply[A](xs: A*): CC[A] = fromIterable(View.Elems(xs: _*))
def fill[A](n: Int)(elem: => A): CC[A] = fromIterable(View.Fill(n)(elem))
def newBuilder[A](): Builder[A, CC[A]]
implicit def canBuildIterable[A]: FromSpecificIterable[A, CC[A]] = IterableFactory.toSpecific(this)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BTW, I’d like to rename FromSpecificIterable[A, C] to CanBuild[A, C]. If users write code that takes parameters of that type, I think CanBuild conveys a clearer meaning (“ability to build a collection C from elements of type A”) than FromSpecificIterable. WDYT?


val xs4 = immutable.TreeMap((1, "1"), (2, "2"))
val xs5 = flatCollect(xs4) { case (2, v) => immutable.List((v, v)) }
val xs5 = flatCollect(xs4) { case (2, v) => immutable.List((v, v)) }(immutable.TreeMap)
Copy link
Contributor Author

@julienrf julienrf Jul 24, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, this is the issue. Here the TreeMap factory hasn’t been inferred because of an ambiguity with SortedSet.

Here is what happens, if I understand correctly. We are looking for an implicit BuildFrom[TreeMap[Int, String], (String, String), C]. The two candidates we find are:

  • SortedSet.canBuildSortedIterable, of type [A] => BuildFrom[Any, A, SortedSet[A]]
  • TreeMap.canBuildSortedMap, of type [K, V] => BuildFrom[Any, (K, V), TreeMap[K, V]]

Why are these candidates ambiguous? Because none is more specific than the other: TreeMap[?, ?] and SortedSet[?] are not subtypes of each other.

Why are they both available in the implicit scope? The one from the companion object TreeMap is available because we are looking for an implicit BuildFrom[TreeMap[Int, String], ?, ?]. For the other one, I guess this is because somewhere in the hierarchy of SortedMap we have a SortedSet that shows up (SortedMap[K, V] extends SortedOps[K, SortedSet, SortedMap[K, V]]). Consequently, the companion object of SortedSet contributes to the implicit scope.

How to fix the problem? Unfortunately, I don’t think we can make the type of one of the two implicits more specific than the other (e.g. we can not make SortedMap[K, V] extend SortedSet[K] because they extend Iterable[(K, V)] and Iterable[K], respectively). One solution could be to change the priority of implicits in the language: when exploring companion objects, the further we go in the hierarchy (ie when we explore companions of ancestors of TreeMap), the lower the priority of their implicit definitions should be. Does that make sense (/cc @adriaanm!)? With this change, I don’t think we would break existing code. However, code that doesn’t compile now (because of an ambiguity) may compile after this change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@szeiger szeiger mentioned this pull request Jul 24, 2017
@julienrf
Copy link
Contributor Author

I just pushed a workaround for the ambiguity: I no longer mention SortedSet in the definition of SortedMap, so that SortedSet’s companion does not contribute to the implicit scope when we manipulate sorted Map collections.

@julienrf
Copy link
Contributor Author

The PR is ready to merge.

@julienrf julienrf merged commit d2cb21b into master Jul 27, 2017
@julienrf julienrf deleted the implicit-builders-again branch July 27, 2017 09:14
@szeiger szeiger mentioned this pull request Aug 17, 2017
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant