Type class for scala.language.dynamics

The scala.language.dynamics feature can be “accessed” through the Dynamic trait.
It would be very nice to also have the alternative of a type class which allows you to do this, as it would allow existing types to have dynamic invocations. For example you could create swizzling for tuples which would let you do something like

(1, 2, 3).zyx ==> (3, 2, 1)

The type class would contain extension methods such as selectDynamic, applyDynamic, and so on.

It would look something like:

trait Dyn[T]:
  // allows you to define the following methods
  extension (t: T)
    def selectDynamic(...): ...
    def applyDynamic(...)(...): ...

You might be able to with something like:


extension [T <: Tuple & Dynamic](t: T)
  <dynamic methods here>


given [T <: Tuple]: Conversion[T, T & Dynamic] =
  (t: T) => t.asInstanceOf // Dynamic is a marker trait, so this is fine

The compiler checks at compiletime that Dynamic is a supertype, but it doesn’t have to come from an extends clause !

1 Like

I stand corrected, I was able to make it work for the related (and more powerful) Selectable:

import scala.languageFeature.dynamics
import scala.language.implicitConversions

extension [T <: Tuple & Selectable](t: T)
  def selectDynamic(methodName: String) = methodName match
    case "first" => (t: Tuple)(0)



given [T <: Tuple]: Conversion[T, T & Selectable {def first: Int}] =
  (t: T) => t.asInstanceOf[T & Selectable {def first: Int}] // Selectable is a marker trait, so this is fine


(1, 2, 3).first // 1: Int

But not with Dynamic:

import scala.languageFeature.dynamics
import scala.language.implicitConversions

extension [T <: Tuple & Dynamic](t: T)
  def selectDynamic(methodName: String) = methodName match
    case "first" => (t: Tuple)(0)



given [T <: Tuple]: Conversion[T, T & Dynamic] =
  (t: T) => t.asInstanceOf[T & Dynamic]


val t: (Int, Int, Int) & Dynamic = (1, 2, 3)

t.first
// java.lang.ExceptionInInitializerError
// Caused by:  java.lang.ClassCastException: class scala.Tuple3 cannot be cast to class scala.Dynamic

So it seems either a smarter conversion is required, or you do really need Dynamic as an extends

As for making it into a typeclass, here is my (unsuccessful) attempt:

import scala.languageFeature.dynamics
import scala.language.implicitConversions


trait Dyn[T, Shape]:
  given [A <: T]: Conversion[A, A & Selectable & Shape] = _.asInstanceOf


type Firstable[T <: Tuple] = Dyn[T, {def first: Int}]

given [T <: Tuple]: Firstable[T] with
  extension [T <: Tuple & Selectable](t: T)
    def selectDynamic(methodName: String) = methodName match
      case "first" => (t: T)(0)


def foo[T <: Tuple : Firstable](x: T) = x.first // value first is not a member of T
// The above means the implicit conversion is not being applied, as my first example works

val t: (Int, Int, Int) = (1, 2, 3)

foo(t)
3 Likes

Hey this is very awesome! I will try this later.