3

I'm trying to create an anonymous implementation of a context function in Scala 3. In detail, the code is the following:

def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = new ContextFunction1[Raise[E], A] { override def apply(using r: Raise[E]): A = block(using r) } 

However, if I try to compile it, the compiler gives me the following error:

[error] 213 |} [error] | ^ [error] | Found: Object with ((in.rcard.raise4s.Raise[E]) ?=> A) {...} [error] | Required: A 

There is no error if I switch to a classic Function1.

3
  • 1
    Does ContextFunction1 even exists? I can't find it in the docs. I wonder if this feature is implemented on top of a lot of sugar syntax. Commented Apr 25, 2024 at 20:26
  • 2
    Would that be okay to write it "inline" / SAM style? stackoverflow.com/questions/76822795/… Commented Apr 25, 2024 at 20:26
  • @GaëlJ can you give me an example? Commented Apr 25, 2024 at 20:40

1 Answer 1

3

ContextFunction1 is not a part of Scala API https://docs.scala-lang.org/api/all.html, so shouldn't be used in source code manually, although it's documented at https://docs.scala-lang.org/scala3/reference/contextual/context-functions-spec.html

Even ordinary functions are normally instantiated via lambda syntax rather than new keyword. new Function1 is compiled to invokespecial while ... => ... is compiled to invokedynamic bytecode.

Define implicit functions via ?=> (both on type and value level):

def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = (r: Raise[E]) ?=> block(using r) def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = r ?=> block(using r) def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = _ ?=> block def mem[E, A](block: Raise[E] ?=> A): Raise[E] ?=> A = block 

In the compiler, symbols for ContextFunctionN are created here:

https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/core/Definitions.scala#L90-L148

 /** The trait FunctionN and ContextFunctionN for some N * @param name The name of the trait to be created * * FunctionN traits follow this template: * * trait FunctionN[-T0,...-T{N-1}, +R] extends Object { * def apply($x0: T0, ..., $x{N_1}: T{N-1}): R * } * * That is, they follow the template given for Function2..Function22 in the * standard library, but without `tupled` and `curried` methods and without * a `toString`. * * ContextFunctionN traits follow this template: * * trait ContextFunctionN[-T0,...,-T{N-1}, +R] extends Object { * def apply(using $x0: T0, ..., $x{N_1}: T{N-1}): R * } * ImpureXYZFunctionN follow this template: * * type ImpureXYZFunctionN[-T0,...,-T{N-1}, +R] = {cap} XYZFunctionN[T0,...,T{N-1}, R] */ private def newFunctionNType(name: TypeName): Symbol = { ... 

Being not able to instantiate ContextFunction1 seems to be expected behavior

// `ContextFunctionN` does not have constructors !ctor.exists || zeroParams(ctor.info) 

https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/core/Types.scala#L6011

/** ... check that ... no user-written class extends ContextFunctionN. */ def checkParents(cls: Symbol, parentTrees: List[Tree])(using Context): Unit = cls.info match { ... 

https://github.com/scala/scala3/blob/main/compiler/src/dotty/tools/dotc/typer/RefChecks.scala#L120

For FunctionN sources are generated for Scala 2 standard library (used in Scala 3 too). For ContextFunctionN sources are not even generated.

At runtime ContextFunctionN do not exist (Class.forName("scala.ContextFunction1") throws ClassNotFoundException). ContextFunctionN are erased to FunctionN.

The error message could be better. Such messages were shown often in early days of Dotty e.g. for polymorphic functions: Type lambda with higher kind

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.