Giter Site home page Giter Site logo

markphelps / optional Goto Github PK

View Code? Open in Web Editor NEW
208.0 4.0 20.0 284 KB

Optional is a library of optional Go types

Home Page: https://godoc.org/github.com/markphelps/optional

License: MIT License

Makefile 5.80% Go 94.20%
golang optional go go-generate

optional's Introduction

Hi, I'm Mark ๐Ÿ‘‹

Twitter URL GitHub Sponsors

  • Creator of Flipt, an open source, self-hosted feature flag solution
  • Former Staff Engineer @github
  • Dad x2, Husband, Human

๐Ÿ‘ท Check out what I'm currently working on

๐ŸŒฑ My latest projects

๐Ÿ“œ My recent blog posts

๐Ÿ“ซ How to reach me

optional's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

optional's Issues

JSON Marshal For Primitive Wrappers

I would like your primitive wrappers, such as optional.Bool, to marshal and unmarshal to json accordingly. Right now they are marshaled as objects.

package main

import (
	"encoding/json"
	"github.com/markphelps/optional"
	"os"
)

type Foo struct {
	Bar optional.Bool `json:"bar"`
}

func main() {
	json.NewEncoder(os.Stdout).Encode(&Foo{Bar:optional.Bool{}}) // {}
	json.NewEncoder(os.Stdout).Encode(&Foo{Bar:optional.NewBool(true)}) // {"bar": true}
	json.NewEncoder(os.Stdout).Encode(&Foo{Bar:optional.NewBool(false)}) // {"bar":false}
}

`Get` without error / `Unwrap` method useful ?

Hey,

thanks for this utility :)

Coming from other languages, I wondered that there was not Unwrap which would return the value (or else panic if not set).

My thinking was, that I wrote code like this:

if s.field.Present() {
  doSth(s.field.Unwrap())
}

And then it didn't make sense to me to check the presence again / call Get which could return an error but never would in this case.

Then it occurred to me that I could write:

if field, err := s.field.Get(); err == nil {
  doSth(field)
}

The fact that error would always be errors.New("value not present") and never anything "bad" made me think though if this isn't too complicated to understand for the next reader (who might wonder why we wouldn't log the error etc.)

So basically I have 2 questions:

  • Do you think it's worth to add this succinct if to the docs, or would that be obvious to most Go programmers? My thinking is, is that there is no general way to "handle the error", as mostly I would assume having an optional value not set is totally expected when using this library.
  • Do you think it makes sense to align Get() (or a new method) with the map's behavior of returning value, ok ? That seems a lot less "dramatic" to me, and consumers can still handle cases when they didn't get a value but required one in some branch of their code.

How do I actually create bottom values?

It's not clear to me at all from the README or from the generated code, how to create the bottom value (or Nothing in Haskell parlance).

I have this generated code:

// OptionalFlavor is an optional Flavor.
type OptionalFlavor struct {
        value *Flavor
}

// NewOptionalFlavor creates an optional.OptionalFlavor from a Flavor.
func NewOptionalFlavor(v Flavor) OptionalFlavor {
        return OptionalFlavor{&v}
}

so if I have a Flavor I know how to get an OptionalFlavor. What I expected to find here was a nullary function that returns the Nothing case.

Perhaps I don't understand how this is supposed to work, or the README needs clarification.

Combinators

Did you leave out combinators like Map, FlatMap, etc. on purpose?

Calling Get() on empty optional crashes

Calling Get() on an empty optional leads to a nil pointer dereference. It seems like it would be okay to return a zero value with a non-nil error in the case that Get() fails. I'm willing to do this work if you approve of my suggested fix, I also understand if crashing is the desired behavior. In the case that you want the crash the Get() method doesn't seem like it needs to call Present().

Crashing example:

package main

import (
	"fmt"
	"github.com/markphelps/optional"
)

func main() {
    valOpt := optional.Int64{}
    val, err := valOpt.Get() // crash here
    if err == nil {
        fmt.Println("Got expected nil err for empty optional")
    }
    fmt.Printf("Got value: '%d' from empty optional\n", val)
}

Suggested fix for int64 type:

func (i Int64) Get() (int64, error) {
	if !i.Present() {
		var zero int64
		return zero, errors.New("value not present")
	}
	return *i.value, nil
}

Unset() method would be natural

Would be handy to reset optional value (which present) to the state where it not present. Right now you have to create new value and that looks like incomplete/unnatural.

"generated by robots at {{ .Timestamp }}" Makes File Generation Non-Deterministic

Can we remove this comment or at least remove the timestamp from the generation tool?

Consider a project that has a lot of separate files containing types that need optional types generated. Ideally, one could run go generate on the whole directory and only files that changed would be updated, however, this comment will update every generated file with the new timestamp whether the type had any changes or not. This creates a mess that then needs cleaned up before committing to git. It's a really big annoyance for no real benefit, we don't need the timestamp comment, we have git for that.

// This file was generated by robots at {{ .Timestamp }}

Optional for sql.Null* types

It would be awesome to have wrappers for sql.Null* types. It will be different from the generated primitive types though.

Example:

o := optional.NewNullInt64(sql.NullInt64{Valid: true, Int64: 55})

The question is, use it like in my example, or just implement sql.Scanner and sql.Valuer interfaces?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.