Package truthy provides truthy condition testing with Go generics

Truthy

Truthiness

Truthy is a package which uses generics (Go 1.18+) to create useful boolean tests and helper functions.

Examples

// truthy.Value returns the truthiness of any argument.
// If the value's type has a Bool() bool method, the method is called and returned.
// If the type has an IsZero() bool method, the opposite value is returned.
// Slices and maps are truthy if they have a length greater than zero.
// All other types are truthy if they are not their zero value.

truthy.Value(0) // false
truthy.Value(1) // true

truthy.Value("") // false
truthy.Value(" ") // true

truthy.Value([]byte(``)) // false
truthy.Value([]byte(` `)) // true

truthy.Value([]int{}) // false
truthy.Value([]int{1, 2, 3}) // true

var err error
truthy.Value(err) // false
truthy.Value(errors.New("hi")) // true
if truthy.Value(err) {
	panic(err)
}


var p *int
truthy.Value(p) // false

p = new(int)
// truthy does not check value underlying pointer!
truthy.Value(p) // true

// Ever wish Go had ? : ternary operators?
// Now it has a ternary function.
x := truthy.Cond("", 1, 10) // x == 10

// truthy.Cond cannot lazily evaluate its arguments,
// but you can use a closure to fake it.
s := truthy.Cond([]string{""},
	func() string {
		// do some calculation
		return "foo"
	},
	func() string {
		// do some calculation
		return "bar"
	})()
// s == "foo"


// How about an equivalent of the nullish coalescing operator ?? 
// as seen in C#, JavaScript, PHP, etc.:
var s string
truthy.First(s, "default") // "default"
s = "something"
truthy.First(s, "default") // "something"
truthy.First(0, 0*1, 1-1, 0x10-10) // 6

// Easily set defaults
n := getUserInput()
truthy.SetDefault(&n, 42)

// Collection testing and filtering
truthy.Any(0, 1, 2) // true
truthy.All(0, 1, 2) // false

ss := []string{"", "a", "b", ""}
truthy.Filter(&ss) // ss == []string{"a", "b"}

// Logical operators
if truthy.Or("1", 0) {
	fmt.Println("yay") // prints yay
}

if truthy.And(300, "") {
	fmt.Println("boo") // not executed
}

Installation

As of October 2021, Go 1.18 is not released, but you can install Go tip with

$ go install golang.org/dl/gotip@latest
$ gotip download
$ gotip init me/myproject
$ gotip get github.com/carlmjohnson/truthy

FAQs

Oh god

This is the correct reaction.

Isn't this just using reflection? Does it even really require generics?

I tried to write a non-generic version of this package first, but you can’t reflect on an interface type. When you do reflect.Value(x), you lose the fact that x was, e.g. an error, because reflect.Value() only takes interface{} and the conversion loses the interface type. You’d end up saying whether the underlying concrete type was empty or not, which is typically not what you want. To work around that, you could require that everything is passed as a pointer, e.g. reflect.Value(&err), but truthy.Value(&err) sucks as an API. If you look at how truthy.Value() works, it accepts a value of type T, and then passes *T to reflect.Value() and calls value.Elem() to finally get the correct reflection type. So, on a technical level, you couldn’t quite make this API work without generics, although it could be close. However, truthy.Filter(), truthy.SetDefault(), truthy.Any(), and truthy.All() could be implemented with pure reflection, although the implementation would be a lot uglier.

Then there’s truthy.First(). To be honest, truthy.First() is the only part of the package that I consider actually useful, and even that, I mostly expect it to be used for picking a string or default. Anyhow, it requires generics to avoid the cast back from interface type to the concrete type.

Should I use this package?

Probably not. It's a little bit of a joke package, but the truthy.First() and truthy.SetDefault() functionality seem useful, especially for strings. Time will tell what best practices around the use of generics in Go turn out to be.

Owner
Carl Johnson
Carl M. Johnson is a philosopher and programmer, currently employed as the Technology Director for @spotlightpa.
Carl Johnson
Similar Resources

Functional tools in Go 1.18 using newly introduced generics

functools functools is a simple Go library that brings you your favourite functi

Dec 5, 2022

Experimenting with golang generics to implement functional favorites like filter, map, && reduce.

funcy Experimenting with golang generics to implement functional favorites like filter, map, && reduce. 2021-12 To run the tests, you need to install

Dec 29, 2021

A collection of functional operators for golang with generics

fn fn is a collection of go functional operators with generics Getting Started P

Jul 8, 2022

Benchmarks to compare Go Generics

This is a collection of various sorts implemnted both as []int only and as const

Dec 8, 2022

Utility library that uses Go generics mechanism

golang-generics-util Utility library that explores Go generics (1.18) xsync Sync

Dec 11, 2022

CDN-like in-memory cache with shielding, and Go 1.18 Generics

cache CDN-like, middleware memory cache for Go applications with integrated shielding and Go 1.18 Generics. Usage package main import ( "context" "

Apr 26, 2022

Go 1.18 generics based slice and sorts.

genfuncs import "github.com/nwillc/genfuncs" Package genfuncs implements various functions utilizing Go's Generics to help avoid writing boilerplate c

Jan 2, 2023

F - Experimenting with Go 1.18 generics to write more functional Go code

f f is a simple library that leverages the new generics in Golang to create a tools for functional style of code. Pipe like '|' in Elixir or Elm. inp

Apr 12, 2022

A hands-on approach for getting started with Go generics.

Go Generics the Hard Way This repository is a hands-on approach for getting started with Go generics: Prerequisites: how to install the prerequisites

Dec 27, 2022
A library that provides Go Generics friendly "optional" features.

go-optional A library that provides Go Generics friendly "optional" features. Synopsis some := optional.Some[int](123) fmt.Printf("%v\n", some.IsSome(

Dec 20, 2022
Extremely flexible golang deep comparison, extends the go testing package, tests HTTP APIs and provides tests suite
Extremely flexible golang deep comparison, extends the go testing package, tests HTTP APIs and provides tests suite

go-testdeep Extremely flexible golang deep comparison, extends the go testing package. Latest news Synopsis Description Installation Functions Availab

Jan 5, 2023
Code Generation for Functional Programming, Concurrency and Generics in Golang

goderive goderive derives mundane golang functions that you do not want to maintain and keeps them up to date. It does this by parsing your go code fo

Dec 25, 2022
Experiments with Go generics

generics Quick experiments with Go generics algebra, a generic square root function for float, complex and and rational. future, a concurrent cache ("

Dec 31, 2022
Example code for Go generics

go-generics-example Example code for Go generics. Usage $ go build -gcflags=-G=3 Requirements Go 1.17 or later Advertise Go 言語にやってくる Generics は我々に何をも

Dec 30, 2022
Collection of unusual generics usecases in Go

Unusual Generics Type parameters or Generics in Go designed to reduce boilerplate for container data types like lists, graphs, etc. and functions like

Dec 14, 2022
Go Library for Competitive Programming with Generics

Go Library for Competitive Programming with Generics Go used to be a difficult language to use for competitive programming. However, with the introduc

Dec 21, 2022
Extended library functions using generics in Go.

Just few extended standard library functions for Golang using generics.

Dec 16, 2021
experimental promises in go1.18 with generics

async go a prototype of "promises" in go1.18. note: this is just an experiment used to test alternate patterns for dealing with asynchronous code in g

Dec 23, 2022
Go 1.18 generics use cases and examples

Go 1.18 generics use cases What are generics? See Type Parameters Proposal. How to run the examples? As of today, gotip is the simplest way to run the

Jan 10, 2022