I want to get rid of a run-time cast to a generic ( asInstanceOf[A] ) without implicit conversions.
This happens when I have a fairly clean data model consisting of case classes with a common attribute and want to implement a general algorithm on it. As an example, the resulting algorithm should take a class of type A , which is a subclass of trait T and should return a copy of a specific class A with some updated field.
This is easy to achieve when I can simply add the abstract copy method to the base attribute and implement it in all subclasses. However, this potentially contaminates the model with methods required only by certain algorithms, and sometimes this is not possible, because the model may be beyond my control.
Here is a simplified example that demonstrates a problem and a solution that uses runtime execution.
Please do not dwell on the details.
Suppose there is a property and some case classes that I cannot change:
trait Share { def absolute: Int } case class CommonShare( issuedOn: String, absolute: Int, percentOfCompany: Float) extends Share case class PreferredShare( issuedOn: String, absolute: Int, percentOfCompany: Float) extends Share
And here is a simple way to recalculate the current percentOfCompany when the total number of shares has changed and the field in the case class has been updated
def recalculateShare[A <: Share](share: A, currentTotalShares: Int): A = { def copyOfShareWith(newPercentage: Float) = { share match { case common: CommonShare => common.copy(percentOfCompany = newPercentage) case preferred: PreferredShare => preferred.copy(percentOfCompany = newPercentage) } } copyOfShareWith(share.absolute / currentTotalShares.toFloat).asInstanceOf[A] }
Some examples of calls in REPL:
scala> recalculateShare(CommonShare("2014-01-01", 100, 0.5f), 400) res0: CommonShare = CommonShare(2014-01-01,100,0.25) scala> recalculateShare(PreferredShare("2014-01-01", 50, 0.5f), 400) res1: PreferredShare = PreferredShare(2014-01-01,50,0.125)
So this works, and as I understand it, calling .asInstanceOf[A] will never fail, but it is necessary to compile the code. Is there a way to avoid use at runtime without using implicit conversions?