dfinity / dfinity/vetkeys

Motoko: move `ByteBuf` and `Result` into `Types` so mixins can be siblings

Open
#449 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
21
Forks
7
Avg merge
10h 30m
Merged PRs (30d)
5

Description

What we are asking for

Move ByteBuf and Result into mo:ic-vetkeys/Types, which already
exists. Nothing new, no rename.

Why it is a prerequisite, not a preference

Two Motoko mixins cannot both declare the same type. Today ByteBuf and
Result are declared inside the mixin
(ControlPlaneCanister.mo:88-91),
so any two mixins that both need them cannot be siblings:

// A.mo and B.mo, each with:  public type ByteBuf = { inner : Blob };
composite.mo:5.11-5.12: type error [M0051], duplicate definition for type ByteBuf in block

Same error whether the declaration is public or not. This is why the
library composes as a chain today
ControlPlaneCanister declares both
and Canister declares neither, inheriting them through include. A chain
only yields prefixes: you can keep "everything up to enumeration" and own the
values; you cannot keep everything except vetKD.

So this blocks #443's ask 1 (define the composite in terms of includable
parts) outright. It is small, settled, and can land first.

Why Types rather than a new module

Types already holds AccessRights — a type that appears seven times in the
Candid — beside its internal operations vtable. Adding two more interface
types is not a change of character, and types.mo is where the Motoko
architecture guidance puts a central schema anyway.

A group then imports exactly one type module:

import EncryptedMaps "mo:ic-vetkeys/encrypted_maps/EncryptedMaps";
import Types "mo:ic-vetkeys/Types";      // ByteBuf, Result, AccessRights

The migration cost, which is not zero

Adopters currently write ByteBuf unqualified because the mixin declares it —
ic_vetkeys_encrypted_maps_custom_canister does. They would have to
qualify it, and specifically not alias it locally. A local alias looks
free and is not:

public type Result<Ok, Err> = Shared.Result<Ok, Err>;   // compiles, service stays correct

It renames the generated binding's types — Result_2Result_1,
Result_11Result__1_3 — while the service itself is unchanged: we
resolved every alias transitively and compared all 29 methods, with 0
differing signatures
. So the churn is invisible to a conformance check and
very visible in a diff of the committed declarations.

This is the trap the release note has to name, because "qualify, don't alias"
is not advice anyone derives on their own.

Worth a release note, and worth updating both custom-canister examples in the
same change.

We hit the collision only because we created a second Types locally; had
the library's own module held all three, there would have been nothing to
alias.

Split out of #443, where this was ask 5. #443's ask 1 depends on it.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at ControlPlaneCanister.mo lines 88-91 and the existing mo:ic-vetkeys/Types module to trace the ByteBuf and Result declarations and their consumers. Update the two custom-canister examples to qualify these types, add the release note warning to qualify rather than alias them, and verify the mixin composition and generated declarations remain correct.

Written by the indexing model from the issue text.

Assessment

Domain
backend-api-design
Issue type
Refactor
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
72/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.