Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New generic type option for nullable values #251

Closed
DylanRJohnston-FZ opened this issue Feb 9, 2023 · 1 comment
Closed

New generic type option for nullable values #251

DylanRJohnston-FZ opened this issue Feb 9, 2023 · 1 comment
Labels
enhancement New feature or request

Comments

@DylanRJohnston-FZ
Copy link
Contributor

DylanRJohnston-FZ commented Feb 9, 2023

Is your feature request related to a problem? Please describe.
Currently working on a codebase where we don't like using pointers for null values, but small types like booleans present problems with using the zero value for when it's absent. False is a perfectly valid value for a partial update of a boolean field in a larger struct.

Describe the solution you'd like
We have a custom built a generic optional value much you'd see in languages like Rust, Java, or Haskell that we'd like to use instead. I propose adding a third option to the optional configuration, something like generic, and then another configuration option much like context_type, optional_generic_type that can be used in place of pointers.

optional: generic
optional_generic_type: optional.Value

The question is whether to have the generic value without its generic parameter, or include some placeholder like optional.Value[A] or optional.Value[%].

Having this as a third option means you won't break compatibility with <1.18 unless someone opts into it.

Describe alternatives you've considered
The available alternatives of zero values, or pointers each have significant drawbacks.

Additional context
This is the full implementation of our generic optional type optional.Value, but the configuration options allow anyone else to sub their own in. Happen to open a Pull Request with the changes if you like the idea.

package optional

import (
	"encoding/json"
)

type Value[V any] struct {
	value V
	ok    bool
}

func Some[V any](value V) Value[V] {
	return Value[V]{value: value, ok: true}
}

func None[V any]() Value[V] {
	return Value[V]{ok: false}
}

func (v Value[V]) Unpack() (V, bool) {
	return v.value, v.ok
}

func (v Value[V]) Get(fallback V) V {
	if v.ok {
		return v.value
	}

	return fallback
}

func FromPtr[V any](ptr *V) Value[V] {
	if ptr == nil {
		return None[V]()
	}
	
	return Some(*ptr)
}

func (value Value[V]) MarshalJSON() ([]byte, error) {
	if value.ok {
		return json.Marshal(value.value)
	} else {
		return json.Marshal((*V)(nil))
	}
}

func (value *Value[V]) UnmarshalJSON(data []byte) error {
	v := (*V)(nil)

	err := json.Unmarshal(data, &v)
	if err != nil {
		return err
	}

	if v != nil {
		value.value = *v
		value.ok = true
	}

	return nil
}
@DylanRJohnston-FZ DylanRJohnston-FZ added the enhancement New feature or request label Feb 9, 2023
benjaminjkraft added a commit that referenced this issue May 6, 2023
…lable types (#252)

This is an implementation for #251, it adds a new `"generic"` option for
the `"optional"` configuration, and a companion type
`"optional_generic_type"` which is a fully qualified type with a
placeholder `%` for the generic parameter.

Co-authored-by: Dylan R. Johnston <[email protected]>
Co-authored-by: Ben Kraft <[email protected]>
@benjaminjkraft
Copy link
Collaborator

#252

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants