C++ virtual interface
class i_animal {
virtual std::string
make_sound() = 0;
};
Architecture
From your interface definition, Canopy generates a matched proxy and stub. The proxy stands in for the real object on the caller's side; the stub dispatches to the real implementation on the other side. Everything between them — serialisation, transport, lifetime, error propagation — is generated, not hand-written.
Your code holds an rpc::shared_ptr<i_foo> and calls its methods like any
local object. The generated proxy serialises the arguments and hands them to whichever
transport is configured. On the far side, the generated stub deserialises them, dispatches
to your real implementation, and the results return along the same path. Your service code
and your calling code never mention the transport or the wire format.
The proxy/stub pair is generated at two levels: a generic object layer
carries the RPC machinery, and a typed interface layer (i_foo_proxy /
i_foo_stub) handles method dispatch and parameter serialisation in whichever
format the connection uses — YAS binary, JSON, or Protocol Buffers.
Every object lives in a zone — an execution context with its own identity and object namespace. A zone is whatever boundary you need it to be: a process, a machine, a plugin or dynamic library, a child subprocess, or a secure enclave. Each zone has a service that acts as its authority — registering objects, issuing identities, managing transport connections, and tracking reference counts.
Adjacent zones are joined by a transport. When two zones are not directly connected, calls route through intermediary zones via passthroughs — automatic multi-hop routing that keeps the whole path alive while traffic flows through it. The result: an object at any depth in any zone can call an object at any depth in any other zone, without the caller knowing how many hops lie between them.
A zone stays alive exactly as long as something references it — objects in it, proxies out of it, or passthroughs through it. When the last reference is released the zone dies and its objects are reclaimed. See Pointers for the distributed-lifetime model.
Any C++ class that inherits from rpc::base<T, i_interface> is remotable.
Methods return an integer error code and pass results back through [out]
parameters — a convention that serialises cleanly across supported transports and keeps the
blocking and coroutine builds source-identical.
class i_animal {
virtual std::string
make_sound() = 0;
};
interface i_animal {
int make_sound(
[out] std::string& s);
};
From that one definition the generator emits the proxy, the stub, and the serialisation code for every format you request — see IDL.