Tutorial :Scala API design; a service which returns a Set<I> where I is some interface (abstract/trait)



Question:

I have asked quite a few questions about the Scala collection types and how they might actually be used. Consider how I might write some service API/implementation in Java:

public interface JavaProductAPI {       public Set<IProduct> getProducts(String isin);  }  

And now the impl:

public class JavaProductAPIImpl implements JavaProductAPI {      private Map<String, Set<ProductImpl>> productsByIsin;        public Set<IProduct> getProducts() {          Set<ProductImpl> s = productsByIsin.get(isin);          return s == null                      ? Collections.<IProduct>emptySet()                     : Collections.<IProduct>unmodifiableSet(s);      }    }  

Lets say that there's a really good reason why I need to have access within the service implementation to the set of products as being of ProductImpls, not IProducts.

It seems that in Scala, there's no real way to achieve this whilst at the same time exlicitly returning an scala.collection.immutable.Set from the API access method. Unless I don't mind returning a copy of the set.

I'm going to assume that returning an actual copy of the data is bad practice (feel free to argue this point!):

val productsByIsin: Map[String, scala.collection.Set[ProductImpl]] = ...  def getProducts(isin: String): scala.collection.immutable.Set[IProduct] = {    productsByIsin.get(isin) match {       case Some(s) => scala.collection.immutable.Set(s toSeq :_*)       case None => scala.collection.immutable.Set.empty    }   }  

So that therefore my only real design choice is to have the API return a scala.collection.Set and use a read-only view:

val productsByIsin: Map[String, scala.collection.mutable.Set[ProductImpl]] = ...  def getProducts(isin: String): scala.collection.Set[IProduct] = {    productsByIsin.get(isin) match {       case Some(s) => s readOnly       case None => scala.collection.Set.empty    }   }  


Solution:1

Your last block of code more closely mimics the Java code you're emulating: returning a read-only view of a mutable Set.

That said, in this situation, if your backing implementation is an immutable.Set[ProductImpl] and you want to return an immutable.Set[IProduct], it's safe to cast.

import scala.collection._    trait IProduct  class ProductImpl extends IProduct    val productsByIsin: immutable.Map[String, immutable.Set[ProductImpl]] =    immutable.Map.empty  def getProducts(isin: String): immutable.Set[IProduct] =    productsByIsin.getOrElse(isin, immutable.Set.empty).asInstanceOf[immutable.Set[IProduct]]  

Note:If u also have question or solution just comment us below or mail us on toontricks1994@gmail.com
Previous
Next Post »