kmh
kmh

Reputation: 1586

scala type requires toString

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

Answers (2)

Ian McLaird
Ian McLaird

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

Alec
Alec

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

EDIT

In case it isn't clear - you might as well just use .toString straight up - this function will serve no purpose.

Upvotes: 2

Related Questions