Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/phelmkamp/valor
Go option and result types that optionally contain a value
https://github.com/phelmkamp/valor
either enum error golang maybe monad option result singleton tuple unit
Last synced: about 2 months ago
JSON representation
Go option and result types that optionally contain a value
- Host: GitHub
- URL: https://github.com/phelmkamp/valor
- Owner: phelmkamp
- License: mit
- Created: 2022-04-07T03:26:46.000Z (over 2 years ago)
- Default Branch: main
- Last Pushed: 2023-07-27T01:12:00.000Z (over 1 year ago)
- Last Synced: 2024-07-31T20:51:39.504Z (5 months ago)
- Topics: either, enum, error, golang, maybe, monad, option, result, singleton, tuple, unit
- Language: Go
- Homepage:
- Size: 199 KB
- Stars: 16
- Watchers: 2
- Forks: 1
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
- awesome-go - valor - Generic option and result types that optionally contain a value. (Functional / Search and Analytic Databases)
- awesome-go-extra - valor - 04-07T03:26:46Z|2022-05-25T16:22:47Z| (Functional / Advanced Console UIs)
README
# valor
[![Go Reference](https://pkg.go.dev/badge/github.com/phelmkamp/valor.svg)](https://pkg.go.dev/github.com/phelmkamp/valor)
[![Go Report Card](https://goreportcard.com/badge/github.com/phelmkamp/valor)](https://goreportcard.com/report/github.com/phelmkamp/valor)
[![codecov](https://codecov.io/gh/phelmkamp/valor/branch/main/graph/badge.svg?token=GH8IYR78VD)](https://codecov.io/gh/phelmkamp/valor)This module provides option and result types that optionally contain a value; hence the name valor, short for "value or".
This is not an attempt to make Go code look less like Go.
Instead, the goal is to codify the ["comma ok"](https://blog.toshima.ru/2019/07/21/go-comma-ok-idiom.html) and
["errors are values"](https://go.dev/blog/errors-are-values) principles that Go already encourages.## Installation
```bash
go get github.com/phelmkamp/valor
```## Types
### Value
[`optional.Value`](https://pkg.go.dev/github.com/phelmkamp/valor/optional) is modeled after the "comma ok" idiom.
It contains a value (ok) or nothing (not ok).```go
m := map[string]int{"foo": 42}
val := optional.OfIndex(m, "foo")
fmt.Println(val.IsOk()) // truevar foo int
fmt.Println(val.Ok(&foo), foo) // true 42valStr := optional.Map(val, strconv.Itoa)
fmt.Println(valStr) // {42 true}val = optional.OfIndex(m, "bar")
fmt.Println(val.Or(-1)) // -1
fmt.Println(val.OrZero()) // 0
fmt.Println(val.OrElse(func() int { return 1 })) // 1
```### Result
[`result.Result`](https://pkg.go.dev/github.com/phelmkamp/valor/result) contains either a value or an error.
```go
// traditional
if res := result.Of(w.Write([]byte("foo"))); res.IsError() {
fmt.Println(res.Error())
return
}// try to get value, printing wrapped error if not ok
// note: only relevant values are in-scope after handling
var n int
if res := result.Of(w.Write([]byte("foo"))); !res.Value().Ok(&n) {
fmt.Println(res.Errorf("Write() failed: %w").Error())
return
}// same as above with multiple values
var s string
var b bool
if res := two.TupleResultOf(multi(false)); !res.Value().Do(
func(t two.Tuple[string, bool]) { s, b = t.Values() },
).IsOk() {
fmt.Println(res.Errorf("multi() failed: %w").Error())
return
}// errors.Is
if res := result.Of(w.Write([]byte("foo"))); res.ErrorIs(io.ErrShortWrite) {
fmt.Println(res.Error())
return
}// errors.As
if res := result.Of(w.Write([]byte("foo"))); res.IsError() {
var err *fs.PathError
if res.ErrorAs(&err) {
fmt.Println("path=" + err.Path)
}
fmt.Println(res.Error())
return
}// errors.Unwrap
if res := result.Of(mid(true)); res.IsError() {
fmt.Println(res.ErrorUnwrap().Error())
return
}
```### Tuples
[`unit.Type`](https://pkg.go.dev/github.com/phelmkamp/valor/tuple/unit), [`singleton.Set`](https://pkg.go.dev/github.com/phelmkamp/valor/tuple/singleton),
[`two.Tuple`](https://pkg.go.dev/github.com/phelmkamp/valor/tuple/two), [`three.Tuple`](https://pkg.go.dev/github.com/phelmkamp/valor/tuple/three), and
[`four.Tuple`](https://pkg.go.dev/github.com/phelmkamp/valor/tuple/four) contain zero through four values respectively.
Among other things, they enable `Value` and `Result` to contain a variable number of values.{% raw %}
```go
get := func(string, int, bool) {
return "a", 1, true
}
val := two.TupleValueOf(get())
fmt.Println(val) // {{a 1} true}
```
{% endraw %}### Enum
[`enum.Enum`](https://pkg.go.dev/github.com/phelmkamp/valor/enum) is an enumerated type.
It's initialized with a set of allowed values and then each "copy" optionally contains a currently selected value.```go
const (
Clubs = "clubs"
Diamonds = "diamonds"
Hearts = "hearts"
Spades = "spades"
)
var Suit = enum.OfString(Clubs, Diamonds, Hearts, Spades)
func main() {
fmt.Println(Suit.Values()) // [clubs diamonds hearts spades]
fmt.Println(Suit.ValueOf("Foo")) // { false}
fmt.Println(Suit.ValueOf(Hearts)) // {hearts true}
}
```## Similar concepts in other languages
### Rust
`Value` is like Rust's [`Option`](https://doc.rust-lang.org/std/option/enum.Option.html).
`Result` is like Rust's [`Result`](https://doc.rust-lang.org/std/result/enum.Result.html).A `switch` statement provides similar semantics to Rust's `match`:
```go
var foo int
switch val {
case val.OfOk():
foo = val.MustOk()
fmt.Println("Ok", foo)
case optional.OfNotOk[int]():
fmt.Println("Not Ok")
return
}var n int
switch res {
case res.OfOk():
n = res.Value().MustOk()
fmt.Println("Ok", n)
case res.OfError():
fmt.Println("Error", res.Error())
return
}
```### Java
`Value` is like Java's [`Optional`](https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/Optional.html).
### More
* [https://en.wikipedia.org/wiki/Result_type](https://en.wikipedia.org/wiki/Result_type)
* [https://en.wikipedia.org/wiki/Option_type](https://en.wikipedia.org/wiki/Option_type)## Releases
This module is currently at v0 but every effort will be made to avoid breaking changes.
Instead, functionality will be deprecated as needed with plans to remove in v1.## Linter
[valorcheck](https://github.com/phelmkamp/valor/tree/main/valorcheck#readme) is a linter to check that access to an optional value is guarded against the case where the value is not present.