Skip to content

Instantly share code, notes, and snippets.

@EtaCassiopeia
Created May 9, 2025 02:46
Show Gist options
  • Save EtaCassiopeia/283f1a283349958beb8882603ef876ca to your computer and use it in GitHub Desktop.
Save EtaCassiopeia/283f1a283349958beb8882603ef876ca to your computer and use it in GitHub Desktop.
import scala.annotation.implicitNotFound
import scala.language.{dynamics, implicitConversions}
object HMap:
opaque type M[T <: Tuple] = Map[Any, Any]
extension [T <: Tuple](m: M[T])
def add[K <: Singleton, V](k: K, v: V)(using
NoMatch[T, K] =:= true
): M[(K, V) *: T] = m + (k -> v)
def get[K <: Singleton](k: K)(using
NoMatch[T, K] =:= false
): GetMatch[T, K] =
m(k).asInstanceOf[GetMatch[T, K]]
def delete[K <: Singleton](k: K)(using
NoMatch[T, K] =:= false
): M[DropMatch[T, K]] = m - k
trait UpdateHandler[T <: Tuple, K <: Singleton, V] {
type Out <: Tuple
def apply(m: M[T], k: K, v: V): M[Out]
}
implicit def updateExisting[T <: Tuple, K <: Singleton, V](using
ev1: HMap.NoMatch[T, K] =:= false,
ev2: HMap.GetMatch[T, K] =:= V
): UpdateHandler[T, K, V] { type Out = T } = new UpdateHandler[T, K, V] {
type Out = T
def apply(m: M[T], k: K, v: V): M[T] = m + (k -> v)
}
implicit def addNew[T <: Tuple, K <: Singleton, V](using
ev: HMap.NoMatch[T, K] =:= true
): UpdateHandler[T, K, V] { type Out = (K, V) *: T } = new UpdateHandler[T, K, V] {
type Out = (K, V) *: T
def apply(m: M[T], k: K, v: V): M[(K, V) *: T] = m.add(k, v)
}
val empty: M[EmptyTuple] = Map.empty
type NoMatch[Tup <: Tuple, K] = Tup match
case (K *: ? *: EmptyTuple) *: ? => false
case (? *: ? *: EmptyTuple) *: rest => NoMatch[rest, K]
case EmptyTuple => true
type GetMatch[Tup <: Tuple, K] = Tup match
case EmptyTuple => Nothing
case (K *: t *: EmptyTuple) *: ? => t
case (? *: ? *: EmptyTuple) *: rest => GetMatch[rest, K]
type DropMatch[Tup, K] <: Tuple = Tup match
case EmptyTuple => EmptyTuple
case (K *: ? *: EmptyTuple) *: rest => rest
case (k *: t *: EmptyTuple) *: rest =>
(k *: t *: EmptyTuple) *: DropMatch[rest, K]
class PseudoCaseClass[T <: Tuple](hmap: HMap.M[T]) extends Dynamic {
def selectDynamic[K <: Singleton](k: K)(using
@implicitNotFound("Could not prove that Singleton Type ${K} exists within HMap ${T}")
ev: HMap.NoMatch[T, K] =:= false
): HMap.GetMatch[T, K] = hmap.get(k)(using ev)
def updateDynamic[K <: Singleton, V](k: K)(v: V)(using
handler: HMap.UpdateHandler[T, K, V]
): PseudoCaseClass[handler.Out] = new PseudoCaseClass(handler(hmap, k, v))
}
object ContextTest extends App {
import HMap.*
val hmap = HMap.empty
.add("name", "John")
.add("age", 30)
.add("isStudent", false)
val pseudoCaseClass = new PseudoCaseClass(hmap)
println(pseudoCaseClass.name) // John
println(pseudoCaseClass.age) // 30
println(pseudoCaseClass.isStudent) // false
val updated = pseudoCaseClass.age = 31
println(updated.age) // 31
val updated2 = pseudoCaseClass.lastname = "Smith"
println(updated2.lastname) // Smith
val l: Any = updated2.lastname
case class AClass(value: String)
val updated3 = pseudoCaseClass.aClass = AClass(value = "123")
println(updated3.aClass)
val a: AClass = updated3.aClass
print(a.value)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment