Let me expand on what I mean:
type Dip20 = record {
transfer: func(Principal, Nat) -> (TxReceipt);
...
};
type SNSLedger = record {
transfer: func(TransferArgs) -> (TransferResponse);
...
};
service : {
interfaceDIP20: () -> (DIP20);
interfaceSNSLedger: () -> (SNSLedger);
...
}
It does add one level indirection (only when initially setup to talk to such a canister, not for every call), but there are many benefits, the least of which is that this is already supported on IC and requires no extra change at system level.