Solution (source code)

= Solution

Use a <lower type bound> to widen the element type only in the new value:

``
class ISet[+T](contents: List[T]) {
  private val data: List[T] = contents

  def add[U >: T](x: U): ISet[U] =
    new ISet[U](x :: data)

  def delete(): (T, ISet[T]) = data match {
    case x :: xs => (x, new ISet[T](xs))
    case Nil => throw new NoSuchElementException("ISet.delete")
  }
}
``

The list is immutable and neither method changes this instance. A new wider value cannot be accepted directly as the old narrow `T`; instead `add[U >: T]` returns a fresh `ISet[U]`. The original `ISet[T]` retains its element guarantee, and deletion returns both its old head and a fresh bag for the tail. This <covariant persistent multiset> safely shares unchanged list tails and preserves duplicate multiplicities. The historical name `ISet` does not require silently changing the question's bag semantics into duplicate-removing set semantics.<Scala 2.13 variance annotations specification>[Variance Annotations: lower-bound widening of Sequence.append]{ref}