-
Notifications
You must be signed in to change notification settings - Fork 42
Lazy Sets
REST API code generation for Go
describes several strategies a developer can adopt for implementing Sysl-defined services in Go. Stretching that theme, a speculative but very compelling idea is for SetOf…
to be lazy.
func (*TransactionServiceServerImpl) GetTransactions(
ctx context.Context,
crn string,
Backend1GetTxs func(ctx context.Context, crn string) SetOfTx,
Backend2FetchTrans func(ctx context.Context, custid string) SetOfTx,
) SetOfTransaction {
cctx, cancel := context.WithCancel(ctx)
a := Backend1GetTxs(cctx, crn).Map(TxToTransaction)
b := Backend2FechTrans(cctx, "crn:"+crn).Map(TxToTransaction)
// Exclude b TxIDs already in a.
return a.Union(b.ButNot(a.Project("TxID"))).OrCancel(cancel)
}
We've abandoned conventional error-handling because it is impossible to tell upfront whether a call will fail.
This model requires that operators Union
, ButNot
, etc. understand laziness and the possibility of failure at every point. Each operator returns a SetOf…
, which has methods allowing access to elements of the set. The most basic access mode would be to stream the set via a channel:
(SetOfTx).Stream() <-chan func() (Tx, error)
A core premise of this approach is that if we never actually need the data, it is meaningless to ponder whether the request succeeded or not. In fact, the implementation should not even make the call until it is clear that the result will be needed. For instance, B
is not needed in A.Minus(B)
when A
is empty. In the rare case when you need to ensure that the call happens, you can call Any()
just to trigger the behaviour.