Closed noresttherein closed 1 year ago
@scala/collections
I started taking a look, as I know nothing about it.
@noresttherein they don't rate-limit bug reporting.
I am 99% sure you know about it
I can't speak for the royal you, but
I know nothing about it.
(Just noticed I typoed that on my first attempt.)
The lie is that Map[K, V]
is an Iterable[(K, V)]
; that "launders" (in the sense of money laundering or whitewashing) the variance.
Even though Map
is invariant in K
, maybe it is Iterable[(K2, V)]
. (I have not experimented but maybe the collections collective have thought about it.)
Map.from
ought to warn.
"Practically", I'll try the exclusion pointed out in OP. Maybe there are additional strategies for guarding against a subverted key type; for example, the ordering can be taken to reify the key type.
Reproduction steps
I am 99% sure you know about it, but because
Set
makes an attempt to guard against it, andMap
doesn't, I thought I'd mention it. I could not find any mention of it in the database though, and it's been a couple of days since I reported the last bug, so...Scala version: 2.13.x, 3.x
Problem
Obvious:
In
Set
you have:But
Map
misses that:Furthermore, even
Set
is unsound, because it guards itself only against implementations from the standard library; designing it as invariant and then treating it as covariant in the central method to the collection architecture seems a somewhat risky decision. For example, I have (or rather, had, because it is not portable to Scala 3) aNatSet
- naturally sortedSet
. Thanks to a small trick, it is able to use the same API asSet
, and I did not wish to make it aSortedSet
because in the original use case I relied on the fact that ordering was natural (i.e., increasing). It will fail the same wayMap
does in the above example.I am aware that performance is important, but the same effect can be achieved with positive filtering, rather than negative, i.e. returning only
HashSet
andHashMap
with widened types. Furthermore, it would be possible - though quite ugly - to wrap the argument tofrom
in a proxy which catchesClassCastException
and replaces the underlying set with aHashSet
/HashMap
if needed. Technically,underlying
field doesn't even have to be@volatile
(assuming all fields in all objects inside aHashSet
are final in the byte code): we can leave that synchronization for after an exception is actually caught.As a side note, warranting perhaps a separate bug report,
(without an expclicit call to
sortedMapFactory
) does not compile for me.