3

I want to do something like this:

def parse[A: Numeric](str: String): A = {
   if A =:= Int, str.toInt
   if A =:= Float, str.toFloat
   if A =:= BigInt, BigInt(str)
   ...
   ...
}

Unfortunately, it seems that there is no fromString defined in the Numeric trait. What is the most idiomatic way to achieve this in Scala?

1 Answer 1

1

What you're asking for is in general impossible by the extendable nature of typeclasses; there is no way you could match against all possible implementations of Numeric because any user-defined type could implement it. Likewise because of that, it's not guaranteed that every Numeric[A] is parseable from a string.

There's two ways out of this. One is a partial solution where you make sure you only use strings representing integer literals, then use Int's fromString to parse it and Numeric's fromInt to convert it.

The other way is to pass in the actual string parsing function when the function is called. This can kind of feel like cheating as your parse method no longer does any real work, but can be made to be quite useful with implicits.

The most straightforward way is to just add a (maybe implicit) String -> A parameter (or maybe String -> Option[A] for fewer runtime errors). Another way of achieving this is to go the the typeclass route again and implement something like a Readable typeclass. Then you can have your function be the following:

def parse[A: Numeric: Readable](x: String): A = ...

Now you just need to make sure you have Readable[A] implementations for all the A you care about.

Sign up to request clarification or add additional context in comments.

6 Comments

That's exactly what I do here (see the Scannable type class): github.com/pathikrit/better-files/blob/master/core/src/main/… But I wish Scala's Numeric trait had a fromString in it...
Actually now that I think about it, I think there's a better way. Let me write up the edit....
Never mind; everything I can think just devolves back into the same thing. The only other thing I could think of was perhaps using spire and using its Integral typeclass and then matching on whether it's a Fractional or just an Integral and then using the respective fromDouble or fromInt methods (together with toDouble and toInt) to parse it. Your Scannable seems fine, but I wouldn't call myself a Scala expert and would defer to others.
I opened a Scala minor issue for this: issues.scala-lang.org/browse/SI-9706. This would even simplify Scala's internal .toByte, .toInt code too...
I'll be interested to see where that goes. FWIW, I'm of the opinion that actually a general Readable typeclass in the standard library is the way to go and that adding parsing to the responsibility of the typeclass conflates what should be separate concerns. I'll reserve judgment though and see what the core Scala team thinks.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.