-
Notifications
You must be signed in to change notification settings - Fork 12
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
Optional-types API #150
Comments
I see such pattern already in But what would be the downsides of replacing: // OptionalInt64 is an optional int64. Optional types must be used for out
// parameters when a shape field is not required.
type OptionalInt64 struct {
val int64
isSet bool
}
// Get returns the value and a boolean indicating if the value is present.
func (o *OptionalInt64) Get() (int64, bool) { return o.val, o.isSet }
// Set sets the value.
func (o *OptionalInt64) Set(val int64) *OptionalInt64 {
o.val = val
o.isSet = true
return o
}
// Unset marks the value as missing.
func (o *OptionalInt64) Unset() *OptionalInt64 {
o.val = 0
o.isSet = false
return o
} with // OptionalInt64 is an optional int64. Optional types must be used for out
// parameters when a shape field is not required.
type OptionalInt64 struct {
Val int64
IsSet bool
} I initially thought that API is heavily based around // OptionalInt64 is an optional int64. Optional types must be used for out
// parameters when a shape field is not required.
type OptionalInt64 struct {
Optional
Val int64
} In this way, all Optional- types would have |
Thanks for the feed back @divan! The primary concern with this API is correctness. If the fields in an Optional- type are public then it is much easier to forget to check There should be a convenience function for all scalar types similar to The |
@fmoor I think we need to improve our error messages to instead suggest the user to use the correct |
@fmoor agree on correctness priority.
From my experience with API described above, I virtually never had to set Yet, I'm trying to think about better tradeoff between being explicit and concise, and keep returning to the idiomatic Go patterns, including ones found in stdlib. One example is os.Getenv and os.LookupEnv which resembles situation with Optional- types. First method returns env var or empty string, second – provides extra bool for distinguishing missing value from empty value. Granted, second method was added later, but still – I use mostly os.Getenv, because it's not very often that I expect the different behavior in "empty value" vs "missing value". Less correct, but works 99.999% and always has a 'better' version. Or using pointers for optional types, like: type Entity struct {
First string
Second *string // this is optional
} thus having Another thoughts are revolving around using tags. I.e. type Entity struct {
First string `edgedb:"first"`
Second string `edgedb:"second,some_smart_tag_name_to_show_that_default_value_means_missing"`
} Can't come up with a good tag name at the moment, sorry :) But in line with So, no clear suggestions for now, just throwing some random thoughts, maybe they will be useful. |
It is somewhat verbose to create an optional type variable and set its value before using it. ```go optional := edgedb.OptionalBool{} optional.Set(true) SomeStruct{ field: optional, } ``` This change adds convenience functions for creating a new optional value and setting its value. ```go SomeStruct{ field: edgedb.NewOptionalBool(true), } ``` related to #150
It is somewhat verbose to create an optional type variable and set its value before using it. ```go optional := edgedb.OptionalBool{} optional.Set(true) SomeStruct{ field: optional, } ``` This change adds convenience functions for creating a new optional value and setting its value. ```go SomeStruct{ field: edgedb.NewOptionalBool(true), } ``` related to #150
@fmoor Frederick, can we close this one now? |
I've re-read the discussion and I agree, the current API is a bit too verbose. That said, I want us to run with it for a month or two before iterating further. I'm gonna close this issue, but @divan please feel free to open new one (or reopen this one) if you have any new ideas or feature proposals! |
Just leaving here hilarious discussion about similar problem in protobuf v3. protocolbuffers/protobuf#1606 And actual docs page on field presense: https://github.com/protocolbuffers/protobuf/blob/master/docs/field_presence.md As for today, official Go proto generator plugins generates struct fields as scalar types ( PS. I'm using EdgeDB with protobuf3, so have to sync the structs definitions and will be able to compare on-hands experience with both approaches :) |
Hi,
I just switched to 1-beta.3, and all Go types that I used for optional fields started to return error in queries about implementing OptionalMarshaller, so had to look into those and have couple of thoughts.
It would be handy for Optional- types to have an easy access to the "zero value". I.e. empty string for OptionalStr. It's an idiomatic Go pattern to have useful zero value, and some other optional/null implementations leverage this and (at least to me) it worked pretty well in practice.
Most of them have form of:
which is simple and concise, and allows using zero value for cases where default value is a good replacement for missing value (like empty string).
But with current API this change is not easy:
Required definition:
Optional definition:
Required read (to be used in other struct, with default zero value):
Optional read (to be used in other struct, with default zero value):
Required set:
Optional set:
And while I like the explicitness and verbosity of that approach, I end up writing own wrappers for all those optional types.
With that "standard" approach, the following code would be:
and
accordingly.
What do you think?
I know it'll be hard to change API, but maybe at least add getters/setters for default value for basic types? (i.e.
String()
/NewOptionalStr()
)Or I'm missing something behind the current Optional- types design?
The text was updated successfully, but these errors were encountered: