Reputation: 1586
In Scala, what's the most generalizable way to require a type can be treated as a String?
I know view bound requires that an object can be "viewed as" another type, but this doesn't work.
def func[T <% String](s: T): String = s.toString
val x: Long = 0
x.toString // String = 0
func(x) // error: No implicit view available from Long => String.
Type Any has a toString method... so I could just do a type bound... but is every object in Scala automatically a subtype of Any? It seems like maybe, but is this dumb for some reason I'm not anticipating?
def func[T <: Any](s: T): String = s.toString
class A { override def toString "xxx" }
func(new A) // String = xxx
class B(val b: Int)
func(new B(0)) // String = B@12345678
object C { override def toString = "ccc" }
func(C) // String = ccc
So it seems to work, even though my objects don't explicitly extend any subclass of Any. Will this generalize to any object in Scala, even if it doesn't necessarily end up with a pretty string that looks like what I want?
EDIT
per comment below, viewing as a string and creating a new string are different. in this case, I don't care, but to make the view bound version work... I'd guess something like this would be appropriate?
implicit def strConv[T](s: T) = s.toString
def func[T <% String](s: T) = s
func(new A) // A = xxx
Upvotes: 0
Views: 987
Reputation: 5585
Regarding your edit and what those view bounds are for.
A view bound exists to allow you to have a function that will accept any type so long as an implicit conversion exists to the type you wish you had. I'm going to make your sample function just a touch fancier in the interests of showing what that really means.
First, some implicit conversions (I'm going to stick with Long
and Double
to drive the point home)
implicit def long2String(l: Long) = l.toString
implicit def double2String(d: Double) = d.toString
Now, a function that really wants to operate on Strings
, but will accept anything that's convertible to String
def func[T <% String](s: T) = s.substring(0,2)
Now, if I call that function with a Double
, I'll get this
scala> func(9.123)
res8: String = 9.
And with a Long
scala> func(999999L)
res7: String = 99
But with an Int
scala> func(99)
<console>:15: error: No implicit view available from Int => String.
func(99)
Your specific example
def func[T <% String](s: T) = s
doesn't quite work, though, since it actually returns T
not String
. You can do this, though.
def func[T <% String](s: T): String = s
Upvotes: 3
Reputation: 32309
Yeah it will always work: Any
is the highest thing in the hierarchy. Check out the diagram. Looks like it generalizes Scala's value types (AnyVal
) and reference types (AnyRef
). As a consequence, T <: Any
will be true for any T
.
With that in mind, you can drop T <: Any
completely (and replace it with just T
). Heck, the REPL even simplifies it for you:
scala> def func[T <: Any](s: T): String = s.toString
func: [T](s: T)String
In case it isn't clear - you might as well just use .toString
straight up - this function will serve no purpose.
Upvotes: 2