Skip to content

Instantly share code, notes, and snippets.

@jcorbin
Created July 26, 2020 18:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jcorbin/1112aeef88655a681ba32c129ef06069 to your computer and use it in GitHub Desktop.
Save jcorbin/1112aeef88655a681ba32c129ef06069 to your computer and use it in GitHub Desktop.
package main
import "fmt"
// rooter is a base interface for example
type rooter interface {
root() int
}
// fooRooter is an example extension
type fooRooter interface {
rooter
foo() int
}
// barRootere is also an example extension
type barRooter interface {
rooter
bar() int
}
// rootFoo implements the foo extension, delegating through to an underlying rooter
type rootFoo struct {
rooter
f int
}
// rootBar likewises implements the bare extension minimally
type rootBar struct {
rooter
b int
}
// zaro is an implementation of the base intereface
type zaro struct{ v int }
func (z zaro) root() int { return z.v }
func (rf rootFoo) foo() int { return rf.f }
func (rb rootBar) bar() int { return rb.b }
// An example to demonstrate a current stumbling block when implementing
// extension interfaces: combinatorics are not in our favor when we want to
// implement a suite of orthogonal single-aspect implementations.
//
// A banal workaround is to implement union types like a `type rootFooBar struct`.
// This can be assisted by convenience constructors like `fund withBar(rooter, b int) rooter`
// to choose dynamically upgrade to the combined implementation when necessary.
//
// But that's merely a workaround for a closed setting, and when the number of
// aspects is not too large. Another solution that works in an open setting is
// the (un)wrapping approach taken by the recent errors package work.
//
// What would be the downside of making this example work?
// Of making it so that interface value casting can pass through to an embedded value?
func Example() {
a := zaro{1}
b := zaro{2}
c := zaro{3}
for i, r := range []rooter{
a,
b,
c,
rootFoo{a, 4},
rootBar{b, 5},
rootBar{rootFoo{c, 6}, 7}, // NOTE this 6 value will be lost
} {
var rv, fv, bv int
rv = r.root()
if f, ok := r.(fooRooter); ok {
fv = f.foo()
}
if b, ok := r.(barRooter); ok {
bv = b.bar()
}
fmt.Printf("[%v] r:%v f:%v b:%v\n", i, rv, fv, bv)
}
// Output:
// [0] r:1 f:0 b:0
// [1] r:2 f:0 b:0
// [2] r:3 f:0 b:0
// [3] r:1 f:4 b:0
// [4] r:2 f:0 b:5
// [5] r:3 f:6 b:7
}
@jcorbin
Copy link
Author

jcorbin commented Jul 26, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment