Scala Collection Extension

I need a card that throws an attempt to overwrite the value for an existing key. I tried:

trait Unoverwriteable[A, B] extends scala.collection.Map[A, B] { case class KeyAlreadyExistsException(e: String) extends Exception(e) abstract override def + [B1 >: B] (kv: (A, B1)): Unoverwriteable[A, B1] = { if (this contains(kv _1)) throw new KeyAlreadyExistsException( "key already exists in WritableOnce map: %s".format((kv _1) toString) ) super.+(kv) } abstract override def get(key: A): Option[B] = super.get(key) abstract override def iterator: Iterator[(A, B)] = super.iterator abstract override def -(key: A): Unoverwriteable[A, B] = super.-(key) } 

and received:

 <console>:11: error: type mismatch; found : scala.collection.Map[A,B1] required: Unoverwirteable[A,B1] super.+(kv) ^ <console>:16: error: type mismatch; found : scala.collection.Map[A,B] required: Unoverwirteable[A,B] abstract override def -(key: A): Unoverwirteable[A, B] = super.-(key) ^ 

I am new to Scala and cannot figure out how to overcome this. Any help? :)

edit: I am using Scala 2.8.0.Beta1-preerelease (which brings some changes to scala.collection)

+5
generics scala extend scala-collections traits
source share
3 answers

As you redefine methods in Map , you cannot define your attribute as a type of return value.

The simplest solution is to simply omit the types:

 abstract override def + [B1 >: B] (kv: (A, B1)) = { /* ... */ } // ... abstract override def -(key: A) = super.-(key) 

Or you can be explicit and add a super type:

 import scala.collection.Map abstract override def +[B1 >: B] (kv: (A, B1)): Map[A, B1] = { /* ... */ } // ... abstract override def -(key: A) = super.-(key): Map[A, B] 

I think you would need to override + , although your other methods are delegated only to Map .

+4
source share

This fixed your compilation error:

 trait Unoverwriteable[A, B] extends scala.collection.Map[A, B] { case class KeyAlreadyExistsException(e: String) extends Exception(e) abstract override def + [B1 >: B] (kv: (A, B1)): scala.collection.Map[A, B1] = { if (this contains(kv _1)) throw new KeyAlreadyExistsException( "key already exists in WritableOnce map: %s".format((kv _1) toString) ) super.+[B1](kv) } abstract override def get(key: A): Option[B] = super.get(key) abstract override def iterator: Iterator[(A, B)] = super.iterator abstract override def -(key: A): scala.collection.Map[A, B] = super.-(key) } 

However, I think you really want to decorate collection.mutable.Map#+= as follows:

 trait Unoverwriteable[A, B] extends collection.mutable.Map[A, B] { case class KeyAlreadyExistsException(e: String) extends Exception(e) abstract override def +=(kv: (A, B)): this.type = { if (this contains (kv _1)) throw new KeyAlreadyExistsException("key already exists in WritableOnce map: %s".format((kv _1) toString)) super.+=(kv) } } 
+4
source share

You can do this using scala.collection.immutable.Map with a little implicit magic. That is, you define one additional method in the interface and an implicit conversion. Here, as I will do this in version 2.7, I am sure that in 2.8 there are several ways to override, but you should get a general idea.

 trait Unoverwriteable[A, B] extends scala.collection.immutable.Map[A, B] { import Unoverwriteable.unoverwriteableMap case class KeyAlreadyExistsException(e: String) extends Exception(e) def underlying: scala.collection.immutable.Map[A, B] def update [B1 >: B] (key: A, value: B1): Unoverwriteable[A, B1] = { if (this contains(key)) throw new KeyAlreadyExistsException( "key already exists in WritableOnce map: %s".format(key.toString) ) underlying update (key, value) } def get(key: A): Option[B] = underlying get key def elements: Iterator[(A, B)] = underlying.elements def -(key: A): Unoverwriteable[A,B] = underlying - key def empty[C]: Unoverwriteable[A,C] = underlying.empty[C] def size: Int = underlying.size } 

Then you define the implicit in the companion object:

 object Unoverwriteable { implicit def unoverwriteableMap[A, B](map0: scala.collection.immutable.Map[A, B]): Unoverwriteable[A, B] = new Unoverwriteable[A, B] { def underlying = map0 } } 

To use it, add an Unwriteable type annotation to your map. If you uncomment the last 2 lines in the main method, you will get a KeyAlreadyExistsException.

 object UOMain { def main(args: Array[String]): Unit = { val map0 = Map((1 -> 1), (2 -> 2)): Unoverwriteable[Int, Int] println("map0="+ map0) val map1 = map0 - 2 println("map1="+ map1) //val map2 = map1 + (1 -> 1000) //println("map2" + map2) } } 
+3
source share

All Articles