Last active
November 28, 2023 14:15
-
-
Save choonkeat/74002057e3c74ebc3b4428b0161a80a7 to your computer and use it in GitHub Desktop.
Discriminated union for Go
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gosumtype | |
import ( | |
"time" | |
) | |
// To define this sum type: | |
// | |
// type User | |
// = Anonymous | |
// | Member String Time | |
// | Admin String | |
// | |
// Ideally, we just code something like this and the | |
// rest of the boiler plate can be generated | |
type User interface { | |
Switch(s UserScenarios) | |
} | |
type UserScenarios struct { | |
Anonymous func() | |
Member func(email string, since time.Time) | |
Admin func(email string) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gosumtype | |
import ( | |
"log" | |
"time" | |
) | |
// Example usage | |
func Caller() { | |
user1 := Anonymous() | |
user2 := Member("Alice", time.Now()) | |
user3 := Admin("Bob") | |
log.Println( | |
"User1:", UserString(user1), | |
"User2:", UserString(user2), | |
"User3:", UserString(user3), | |
) | |
} | |
func UserString(u User) string { | |
var result string | |
u.Switch(UserScenarios{ | |
Anonymous: func() { | |
result = "anonymous coward" | |
}, | |
Member: func(email string, since time.Time) { | |
result = email + " (member since " + since.String() + ")" | |
}, | |
Admin: func(email string) { | |
result = email + " (admin)" | |
}, | |
}) | |
return result | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gosumtype | |
import ( | |
"log" | |
"strconv" | |
"testing" | |
"time" | |
) | |
func TestUser(t *testing.T) { | |
testCases := []struct { | |
givenUser User | |
}{ | |
{ | |
givenUser: Anonymous(), | |
}, | |
{ | |
givenUser: Member("[email protected]", time.Now()), | |
}, | |
{ | |
givenUser: Admin("[email protected]"), | |
}, | |
} | |
for i, tc := range testCases { | |
t.Run(strconv.Itoa(i), func(t *testing.T) { | |
// using names are very helpful, but loses the exhaustive check at compile time | |
// since Go happily set the undefined scenarios as function zero value: nil | |
// | |
// but we can use https://golangci-lint.run/usage/linters/#exhaustruct | |
// to check at CI instead of suffering from zero value at runtime | |
tc.givenUser.Switch(UserScenarios{ | |
Anonymous: func() { | |
log.Println("i am anonymous") | |
}, | |
Member: func(email string, since time.Time) { | |
log.Println("member", email, since) | |
}, | |
Admin: func(email string) { | |
log.Println("admin", email) | |
}, | |
}) | |
}) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package gosumtype | |
import "time" | |
// | |
// Boiler plate code below: | |
// | |
// Anonymous | |
type anonymous struct{} | |
func (a anonymous) Switch(s UserScenarios) { s.Anonymous() } | |
func Anonymous() User { | |
return anonymous{} | |
} | |
// Member string time.Time | |
type member struct { | |
email string | |
since time.Time | |
} | |
func (m member) Switch(s UserScenarios) { s.Member(m.email, m.since) } | |
func Member(email string, since time.Time) User { | |
return member{email, since} | |
} | |
// Admin string | |
type admin struct{ email string } | |
func (a admin) Switch(s UserScenarios) { s.Admin(a.email) } | |
func Admin(email string) User { | |
return admin{email} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Done https://github.com/choonkeat/sumtype-go