How dynamically handle self-type annotation in scala

66 Views Asked by At

I am trying to use the cake pattern here for my project. Which is working fine.

Here is a pseudo code for that.

trait Source {
  def dataset: String
}

trait FileSource extends Source{
  def path: String
  override def dataset: String = // Something here
}

trait DBSource extends Source{
  def ip: String
  override def dataset: String = // Something here
}

trait Processor {
  self: Source =>
  val name: String
  def output: String = transform(self.dataset)
  def transform: (String => String)
}

trait FilterWhilteSpace extends Processor {
  self: Source =>
  override val name: String = "filter_whitespaces"
  override def transform: (String => String) = _.replaceAll("\w", "")
}

trait MaskPassword extends Processor {
  self: Source =>
  override val name: String = "mask_password"
  override def transform: (String => String) = // Something here
}

class FilterWhilteSpaceForFile extends FilterWhilteSpace with FileSource {
  override def path: String = "abcd"
}

class FilterWhilteSpaceForDB extends FilterWhilteSpace with DBSource {
  override def ip: String = "localhost"
}

class MaskPasswordForDB extends FilterWhilteSpace with DBSource {
  override def ip: String = "localhost"
}

So the problem is here, Data from local DBSource is getting read twice (Once in FilterWhilteSpaceForDB and second in MaskPasswordForDB). Can we create an instance of LocalDBSource which can be used in both or resolve my Source self-type annotation dependency?

class LocalDBSource extends DBSource {
  override def ip: String = "localhost"
}
1

There are 1 best solutions below

2
Tim On

The problem is that your design has Processor inherit from Source which means that each instance of Processor has it's own Source instance. You need to separate the Source hierarchy from the Processor hierarchy:

trait Source {
  def dataset: String
}

case class FileSource(path: String) extends Source {
  def dataset: String = ???
}

case class DBSource(ip: String) extends Source {
  def dataset: String = ???
}

trait Processor {
  def source: Source  
  val name: String  
  def output: String = transform(source.dataset)  
  def transform: String => String
}

case class FilterWhilteSpace(source: Source) extends Processor {
  val name: String = "filter_whitespaces"
  def transform: String => String = _.replaceAll("\\w", "")
}

case class MaskPassword(source: Source) extends Processor {
  val name: String = "mask_password"
  def transform: String => String = ???
}

val db = DBSource("localhost")
val a = FilterWhilteSpace(db)
val b = MaskPassword(db)

Also note that implementing an abstract method is not overriding, so you don't need the override keyword. Only use override when you are replacing an existing concrete implementation.