Scala implicit dynamic casting

I would like to create a scala Views helper for Android

Using this combination of features and class

class ScalaView(view: View) { def onClick(action: View => Any) = view.setOnClickListener(new OnClickListener { def onClick(view: View) { action(view) } }) } trait ScalaViewTrait { implicit def view2ScalaView(view: View) = new ScalaView(view) } 

I can write onClick () like this:

 class MainActivity extends Activity with ScalaViewTrait { //.... val textView = new TextView(this) textView.onClick(v => v.asInstanceOf[TextView] setText ("asdas")) } 

It bothers me that I want to avoid casting v to TextView

v There will always be a TextView if applied to a TextView LinearLayout , if applied to a LinearLayout , etc.

Is there a way that v gets dynamic casting for any kind?

Just started with scala and I need your help.

UPDATE

Solved, see my answer below

+4
source share
3 answers

I have succeeded. Here is how

 trait ScalaViewTrait { implicit def view2ScalaView[T <: View](view: T) = new ScalaView[T](view) } class ScalaView[T <: View](view: T) { def onClick(action: T => Any) = view.setOnClickListener(new OnClickListener { def onClick(view: View) { action(view.asInstanceOf[T]) } }) } 

And now I can write onClick like this

 textView.onClick(v => v.setText("asdsa")) 

v actually a TextView when onClick applies to a TextView

PS. Maybe I will write a bunch of helpers and publish them on GitHub. <3 Scala

+2
source

The problem is that, given the Android API, it is simply impossible to ensure complete type safety and the convenience of defining an action that only works in the corresponding View subclass.

Your approach sacrifices type safety and Drexin victims (some). Like you, I would be willing to give up type safety in this situation, as it is reasonable to expect good behavior in the Android library, but I would encapsulate the troubles a little differently.

First, I would define a wrapper for OnClickListener as follows:

 case class MyOnClickListener[V <: View](action: V => Any) extends OnClickListener { def onClick(view: View) = try action(view.asInstanceOf[V]) catch { case e: ClassCastException => throw new RuntimeException("This should never happen!", e) } } 

And then forget that OnClickListener exists (or at least never uses it anywhere in my code). Now all unsafe things are gathered in one place, and the ScalaView class ScalaView clean, for example:

 class ScalaView[T <: View](view: T) { def onClick(action: T => Any) = view.setOnClickListener(MyOnClickListener(action)) } 

You will probably come across other places where you need such a shell, and this approach allows you to store all ugly throws, etc., carefully kept in one place, and not scattered throughout your code.

+3
source

Instead, you can simply overlay it with just a pattern match:

 // ... textView.onClick { case v: TextView => v.setText("foobar") case v => log.error("Expected TextView got %s.".format(v.getClass)) } 
+1
source

All Articles