0
votes

Bear in mind that I started with Scala a week ago.

Classes: Currency - Abstract, Bitcoin, Dollar, Euro

Traits: Converter, Printer

My Abstract Class has 2 variables: Name and Value (both vars)

Method in Converter Trait

def convert(to:Currency):Double = ???

This is the part where I am stuck. I need to override this method in each of my subclasses (Currencies) so that they convert from one Currency to the other two. I can do it with new methods but it needs to be done with one. What should I pass as a Parameter so that the Method recognizes which one to convert it to. Euro, Dollar & Bitcoin take only one Int as a parameter.

What I also do not understand is this "to: " part of the parameter.

Since this is also my first question on Stack Overflow, and I am not quite sure how all this works, I would like to point out that i am looking forward to pointers and/or suggestions, since the simple solution wouldn't help me at all in the long run. If some of you think I left out some critical information, feel free to tell me, I will gladly edit my question.

2

2 Answers

2
votes

to: Currency means that you are declaring a parameter called to whose type is Currency. Unfortunately, you don't want a Currency object because that contains a specific amount - you just want to be passed the class of the currency that is supposed to be returned.

Well, you could do it like this:

def convert(to: Class[Currency]): Double = ???

But the more type-safe way would be to do it like this:

def convert[C <: Currency](to: Class[C]): C = ???

but I am not sure how you would implement that one. You might need to use Manifest instead of Class for that one.

1
votes

Welcome to StackOverflow.

First, as an advice for future questions try to provide all the (relevant) code that you can - for example, in this case the definition of your concurrency classes would be useful.

Second, I believe this is an assignment and probably you don't need to go too far.
As Robin already said, this to parameter is used to determine the target type - but, since it would be a class it would have a value, which is not desired.
I suppose the idea is to pass an empty class and do something like this using pattern matching.

class Bitcoin(override val amount: Int = 0) extends Concurrency(amount) {
  override def convert(to: Concurrency): Concurrency = to match {
    case _: Bitcoin => this // no need to transform
    case _: Euro    => new Euro((this.amount / 2).toInt)
    case _: Dollar  => new Dollar((this.amount / 3).toInt)
  }
}

new Bitcoin(30).convert(to = new Dollar()) // res0: Concurrency: Dollar(10)

Third, this is a more typesafe solution that I hope you find interesting and "fun"(ctional) - bad joke intended.

sealed abstract class Concurrency(val amount: Int) {
  def name: String

  /** Tansforms this concurrency value to a new target type. */
  final def to[C <: Concurrency](implicit builder: Concurrency.Builder[C]): C =
    builder.build(this)
}

object Concurrency {
  /** Builder of target concurrencies. */
  trait Builder[C <: Concurrency] {
    def build(origin: Concurrency): C
  }
}

final case class Bitcoin(override val amount: Int) extends Concurrency(amount) {
  override final val name: String = "Bitcoin"
}

object Bitcoin {
  import Concurrency.Builder

  implicit val BitcoinBuilder: Builder[Bitcoin] = new Builder[Bitcoin] {
    override def build(origin: Concurrency): Bitcoin = origin match {
      case b: Bitcoin     => b // no need to transform
      case Euro(amount)   => Bitcoin(amount * 2)
      case Dollar(amount) => Bitcoin(amount * 3)
    }
  }
}

final case class Euro(override val amount: Int) extends Concurrency(amount) {
  override final val name: String = "Euro"
}

object Euro {
  import Concurrency.Builder

  implicit val EuroBuilder: Builder[Euro] = new Builder[Euro] {
    override def build(origin: Concurrency): Euro = origin match {
      case e: Euro         => e // no need to transform
      case Bitcoin(amount) => Euro((amount / 2).toInt)
      case Dollar(amount)  => Euro((amount / 1.5).toInt)
    }
  }
}

final case class Dollar(override val amount: Int) extends Concurrency(amount) {
  override final val name: String = "Dollar"
}

object Dollar {
  import Concurrency.Builder

  implicit val DollarBuilder: Builder[Dollar] = new Builder[Dollar] {
    override def build(origin: Concurrency): Dollar = origin match {
      case d: Dollar       => d // no need to transform
      case Euro(amount)    => Dollar((amount * 1.5).toInt)
      case Bitcoin(amount) => Dollar((amount / 3).toInt)
    }
  }
}

Dollar(10).to[Bitcoin] // res0: Bitcoin = Bitcoin(30)

Don't doubt to ask for clarification.