question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Dependent context function types are less capable than path dependent functions that use context.

See original GitHub issue

Compiler version

3,2,0-RC3

Minimized code

type MyTuple[P <: Product] = (m: Mirror.ProductOf[P]) ?=> m.MirroredElemTypes

def MyTuple2[P <: Product](using m: Mirror.ProductOf[P])(t: m.MirroredElemTypes): m.MirroredElemTypes = t

case class X(a: Int, b: Float)

val y = MyTuple2[X]((1, 2f))
val yy: MyTuple[X] = (1,2f) //doesn't typecheck, wants evidence$1.MirroredElemTypes instead

Output

Found:    (Int, Float)
Required: evidence$1.MirroredElemTypes

Expectation

I expected that yy should compile, since a mirror for X can be summoned, and the type of MirroredElemTypes is clearly (Int, Float), as shown by MyTuple2.

Issue Analytics

  • State:open
  • Created a year ago
  • Reactions:1
  • Comments:11 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
markehammonscommented, Aug 18, 2022

Last year I was working on a library called slinc for facilitating interop between C and Scala on the JVM. In it, the analog of C Structs was case classes, and structs stored in native memory (as opposed to JVM memory) were represented by Ptr[X] where X is a case class analog of a struct X. When you would dereference a Ptr, it would pull a copy of the struct from native memory into an instance of the case class stored in JVM memory. This copy operation could be quite expensive for a large struct with sub structs nested within, so I decided to make Ptr[X] have fields that were derived from X. Basically, if X has the definition case class X(a: Int, b: Float), Ptr[X] is kind of like Ptr[X] { val a: Ptr[Int]; val b: Ptr[Float];} with the “fields” of the pointer being pointers to subsets of the struct’s data, allowing the user to dereference only 4 bytes of a 256-byte struct via ptr.a.deref instead of writing ptr.deref.a.

The problem lies with making the fields of the pointer derivable by the compiler rather than needing to be explicitly written out by the user. In my library I used a transparent inline and programmatic structural types together to cast the pointer into the appropriate shape for the case class it was pointing to, but that’s not a very ergonomic solution. Being able to write something has the type Ptr[X] and the scala compiler knowing immediately that it has fields a: Ptr[Int]and b: Ptr[Float] without the need of transparent inline casting or other tricks would be very good, but with the current restriction on how mirrors work, that type isn’t actually possible.

1reaction
markehammonscommented, Aug 18, 2022

I am not sure whether to close it or transfer to a feature request (but it’s unlikely to be addressed, IMO). @markehammons @julienrf what do you prefer?

If it could be done as a feature, I would like that a lot. I’m playing around a lot with defining derivative types, and this would enable a type to be calculated based off of a case class definition very easily. See for example:

type Exists[T <: Tuple, S <: Singleton] <: Boolean = T match
  case S *: ?     => true
  case ? *: tail  => Exists[tail, S]
  case EmptyTuple => false

type IndexOf[T <: Tuple, S <: Singleton] <: Int = T match
  case S *: ?    => 0
  case ? *: tail => 1 + IndexOf[tail, S]


class StaticDynamic2[Ks <: Tuple, Vs <: Tuple](using Tuple.Size[Ks] =:= Tuple.Size[Vs])(values: Vs) extends Dynamic:
  inline def selectDynamic[S <: Singleton & String](s: S)(using
      Exists[Ks, S] =:= true
  ): Tuple.Elem[Vs, IndexOf[Ks, S]] =
    inline values match
      case u: NonEmptyTuple =>
        inline u(constValue[IndexOf[Ks, S]]) match
          case r: Tuple.Elem[Vs, IndexOf[Ks, S]] =>
            r

object Optional:
  inline def apply[P <: Product](using m: Mirror.ProductOf[P])(t:Tuple.Map[m.MirroredElemTypes,Option]) = StaticDynamic2[m.MirroredElemLabels, Tuple.Map[m.MirroredElemTypes,Option]](t)

case class X(a: Int, b: Float)
val y = Optional[X]((None, Some(2))

If this pattern worked, the type of y would in theory be Optional[X] where that’s defined as type Optional[P <: Product] = (m: MirrorProductOf[P]) ?=> StaticDynamic2[m.MirroredElemLabels, Tuple.Map[m.MirroredElemTypes, Option]]. Right now it has to be defined by the user as StaticDynamic2[("a", "b"), (Int, Float)] which is more complex as case class complexity grows, and more error prone to write. I don’t know how useful this pattern would ever be, but the ability to define the singleton object Optional like I do, but not be able to define the corresponding type Optional feels rather limiting with regards to the type system and dependent typing.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Context representations, context functions, and the ... - NCBI
I then describe several different functions of context that have been studied ... Thus, conditioning to context may be less dependent on pattern...
Read more >
Addressing context dependence in ecology - ScienceDirect.com
Mechanistic context dependence occurs when a relationship, say between variables X and Y, fundamentally differs under different ecological and spatiotemporal ...
Read more >
Context-Dependent Memory: How It Works And Why It Matters
This article discusses the concept of context-dependent memory. ... It is important in emotional, cognitive, and behavioral functions.
Read more >
Context Functions - Scala 3 - EPFL
Context functions are functions with (only) context parameters. Their types are context function types. Here is an example of a context function type:....
Read more >
Context | Android Developers
ContextWrapper, Proxying implementation of Context that simply delegates all ... for use with openFileOutput(String, int) , if the file already exists then ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found