2

I have to retrieve Derived class objects stored in a Map given the respective class name as key.

As show below

trait Caluclator
class PreScoreCalculator(data:Seq[Int]) extends Caluclator
class BenchMarkCalculator(data:Seq[Int]) extends Caluclator


val calculatorsLookUp:Map[String, Calculator]  = Map[String, Calculator](
            "PreScore" -> new PreScoreCalculator,
             "BenchMark" -> new BenchMarkCalculator
            )

Given key name i need to get respective object/instance from Map

def getCalculatorByOperationName(operation:String) : Option[ Calculator]  = {
       calculatorsLookUp.get(operation)
    }

I am calling as below

   val calcName = "PreScore"

   val opt = getCalculatorByOperationName(calcName) 

   if(opt.isInstanceOf[PreScoreCalculator] )   /// this is coming as false
      calculationController.calculate(opt)     // this is not being executed.

Expect : Execute calculationController.calculate(opt)

Error : Above if condition is false hence not getting executed.

So how to handle this problem?

How to handle below i.e. default constructor objects ?

class PreScoreCalculator(data:Seq[Int]) extends Caluclator
Shasu
  • 458
  • 5
  • 22

3 Answers3

2

You have a small bug:

opt is of type Option[Calculator]

In Scala a nice way to handle that is pattern matching:

opt match {
    case Some(calculator: PreScoreCalculator) =>
      calculationController.calculate(calculator)
    case _ => // nothing to do
  }

Or do it in a more declarative way:

  opt.filter(_.isInstanceOf[PreScoreCalculator])
      .foreach(calculationController.calculate)

However the use of instanceOf is a bit of an anti pattern.

As a tip:

Use println(opt.getClass) > then you see the class.

pme
  • 14,156
  • 3
  • 52
  • 95
  • thank you for prompt reply , sorry this execute all the time even if the key is not PreScore. And println(opt.getClass) gives "class scala.Some" – Shasu Mar 22 '19 at 14:14
  • you are right sorry - I fixed my answer and tested now both cases;) – pme Mar 22 '19 at 15:02
  • thank you so much , why are using foreach here ? What am I iterating here ? – Shasu Mar 25 '19 at 06:59
  • 1
    `opt` is of type `Option[Calculator]`. If you want do something with it you have to unwrap it, to use it > `foreach` does that - check the API of `Option`. – pme Mar 25 '19 at 07:27
  • Thank you for clarity , if my PreScoreCalculator takes a constructor i.e. PreScoreCalculator(data:Seq[Int]) how can handle it , in the above scenario ? – Shasu Mar 25 '19 at 07:34
  • if `calculate` takes a `Calculator` you handle it like above - otherwise you have to adjust your question and add the `calculate` function for clarity. – pme Mar 25 '19 at 07:39
  • okey let me put it in different way ? how to put this "class PreScoreCalculator(data:Seq[Int]) extends Caluclator " in Map ? – Shasu Mar 25 '19 at 07:49
1

The problem here is on

val opt = getCalculatorByOperationName(calcName)

because it will return Option[Calculator] not Calculator. Now it will look like this..

if(opt.map(_.isInstanceOf[PreScoreCalculator]).getOrElse(false))
  calculationController.calculate(opt.get)

Hope it helps.

Rex
  • 558
  • 2
  • 9
  • thank you , may i know why are you using .map here ? if it is not .isInstanceOf[PreScoreCalculator] returns false if the key is not "PreScore" right ? why do we need .getOrElse(false) ??? – Shasu Mar 22 '19 at 14:15
  • 1
    Okay. First, result of the `opt ` is always `Option[Calculator]` and Scala’s Predef object offers an implicit conversion that lets you write key -> value as an alternate syntax for the pair (key, value). In case the result is None then it will go to `.getOrElse(false) ` so it is safe. – Rex Mar 22 '19 at 23:34
  • Can you please help me what went wrong here https://stackoverflow.com/questions/71080797/unable-to-write-parquet-file-due-error-sparkexception-job-aborted-fileforma – Shasu Feb 11 '22 at 13:27
1

You should not call isInstanceOf & asInstanceOf manually, because that is basically throwing the compiler away.
You should use pattern matching instead:

opt match {
   case Some(c: PreScoreCalculator) => calculationController.calculate(c)
   ... // Other calculators.
   case None => println("Calculator not found.")
}

Note: This is basically the same Ichoran and I already said in gitter, I am just leaving this here for the record.

  • Miguel Mejia Suarez Thank you so much for more clarity , if my PreScoreCalculator takes a constructor i.e. PreScoreCalculator(data:Seq[Int]) how can handle it , in the above scenario ? – Shasu Mar 25 '19 at 06:58
  • @Miguel Mejia Suarez Can you please recommand good book for learning scala application design and best practices ? – Shasu Mar 25 '19 at 07:00
  • @Shyam Can you elaborate that please? Do you need to extract that `Seq` too? PS: Can you modify the code of the Calculators, or those are out of you control? – Luis Miguel Mejía Suárez Mar 25 '19 at 15:41
  • 1
    @Shyam Technically speaking, SO is not a place to ask for books / courses recommendations... but, since it is a comment and not a question itself, I guess is not too bad. Of course everyone will think different, but I really liked **"Programming in Scala"** _(Book)_ & **"Functional Programming in Scala"** _(Coursera Specialization)_ for starting. And after a while _(most people recommend one year of experience)_ start learning about FP **"Scala with Cats"** is great to begin with. – Luis Miguel Mejía Suárez Mar 25 '19 at 15:49