Skip to content

Opaque Types

A pub opaque type is a sum type whose constructors, fields, and variant patterns are private to its defining module. Outside that module the type is visible and can be used in annotations, as function parameters, and as return types, but callers cannot inspect or construct its internal representation directly.

// in module user_ids.vtx
pub opaque type UserId { UserId(value: String) }
// Smart constructor. The only public way to create a UserId.
pub fn make(s: String): UserId { UserId(value: s) }
// Public accessor. Exposes the value without leaking the constructor.
pub fn unwrap(uid: UserId): String {
match uid {
UserId(value: v) => v,
}
}

What is restricted outside the defining module

Section titled “What is restricted outside the defining module”
OperationError
UserId(value: "x"). Variant constructor callE127
uid.value. Field accessE128
match uid { UserId(value: v) => v }. Variant patternE129
Record update syntax on the opaque typeE130

What is allowed outside the defining module

Section titled “What is allowed outside the defining module”
  • Using the type in annotations: fn foo(uid: UserId): UserId
  • Passing values through: fn passThrough(uid: UserId): UserId { uid }
  • Wildcard match: match uid { _ => 0 }
  • Calling the module’s public smart constructors and accessors
// in module consumer.vtx
import user_ids.{UserId, make, unwrap}
fn run(): String {
let uid = make("abc") // OK. Uses the smart constructor
unwrap(uid) // OK. Uses the public accessor
}
fn bad(): UserId { UserId(value: "x") } // E127
fn bad2(uid: UserId): String { uid.value } // E128

Because variant internals are hidden, match on an opaque type from outside its defining module requires a wildcard arm (_ => ...). Any variant pattern arm will be rejected with E129, and a match with no wildcard and no valid arms is non-exhaustive (E105).

// OK. Wildcard covers the opaque type
match uid {
_ => "some value",
}

opaque is only valid in combination with pub:

pub opaque type Name { ... } // OK
opaque type Name { ... } // parse error. Opaque requires pub
pub opaque fn foo() {} // parse error. Opaque only applies to types