E223: Cannot Be Included in Capture Set — 캡처 셋에 없는 능력을 참조했어요

E223: Cannot Be Included in Capture Set — 캡처 셋에 없는 능력을 참조했어요

캡처 체킹(capture checking) 중에, 어떤 클래스나 표현식의 캡처 셋에 포함되지 않은 능력(capability) 참조를 그 안에서 사용하면 이 에러가 발생해요.

캡처 체킹은 코드 조각이 사용할 수 있는 능력(가변 참조, I/O 핸들 같은 것들)을 추적합니다. 어떤 클래스가 제한된 캡처 셋을 가질 때 — scala.caps.Pure를 명시적으로 상속하거나, java.lang.Exception 같은 순수 타입을 상속해서 암시적으로 그런 경우 — 그 셋 밖의 능력에 대한 참조는 거부됩니다.

참고: 이 에러는 실험적인 캡처 체킹 기능을 켜야 발생해요.

출처: Scala 3 Reference

본문

Example

trait Handle:
  val id: String

trait PureParent extends caps.Pure
class Processor(val ctx: Handle^) extends PureParent // error

class ImplicitlyPure(ctx: Handle^) extends java.lang.Exception // error

def test(handle: Handle^) =
  new PureParent:
    val ctx = handle // error
    val id = ctx.id

PureParent는 순수 타입이므로 능력(여기서는 Handle^)에 대한 참조를 가질 수 없어요.

Error

-- [E223] CaptureChecking Error: example.scala:5:20 ----------------------------
5 |class Processor(val ctx: Handle^) extends PureParent // error
  |                    ^
  |Reference `Processor.this.ctx` is not included in the allowed capture set {} of the self type of class Processor.
-- [E223] CaptureChecking Error: example.scala:7:21 ----------------------------
7 |class ImplicitlyPure(ctx: Handle^) extends java.lang.Exception // error
  |                     ^
  |Reference `ImplicitlyPure.this.ctx` is not included in the allowed capture set {} of the self type of class ImplicitlyPure.
-- [E223] CaptureChecking Error: example.scala:11:8 ----------------------------
11 |    val ctx = handle // error
   |    ^^^^^^^^^^^^^^^^
   |Reference `handle` of value ctx is not included in the allowed capture set {} of the self type of anonymous class Object with PureParent {...}.

Solution

순수 타입을 상속하는 클래스는 능력에 대한 참조를 전혀 담을 수 없어요. 코드를 다음과 같이 재구성하면 됩니다 — 두 가지 선택지가 있어요.

trait Handle:
  val id: String

trait NonPureParrent
trait PureParent extends NonPureParrent, caps.Pure
class Processor(val ctx: Handle^) extends NonPureParrent

class ImplicitlyPure(ctx: Handle) extends java.lang.Exception

def test(handle: Handle^) =
  new PureParent:
    val id = handle.id