4

I have a service, written in golang, that can be initialized with some options. Options are passed as a struct to a constructor function. The constructor function uses default values for option fields that weren't included. Here's an example:

type Service struct {
  options Options
}

type Options struct {
  BoolOption bool
  StringOption string
}

const (
  DefaultBoolOption = true
  DefaultStringOption = "bar"
)

func New(opts Options) *Service {
  if !opts.BoolOption {
    opts.BoolOption = DefaultBoolOption
  }

  if len(opts.StringOption) < 1 {
    opts.StringOption = DefaultStringOption
  }

  return &Service{options: opts,}
}

...

// elsewhere in my code
o := Options{BoolOption: false,}

// sets s.options.BoolOption to true!!!
s := New(o)

My problem is that for bool or int option types, I can't tell whether or not a field value was set in the Options struct. For example, was BoolOption set to false or just not initialized?

One possible solution would be to use strings for all of my Options fields. For instance, BoolOption would be "false" rather than false. I could then check the length of the string to check if it was initialized.

Are there better solutions?

Adam
  • 3,142
  • 4
  • 29
  • 48
  • 1
    Related / possible duplicate of [How do I represent an Optional String in Go?](http://stackoverflow.com/questions/30731687/how-do-i-represent-an-optional-string-in-go/30741287#30741287) – icza May 08 '17 at 18:04
  • 1
    If you want it to be explicitly optional (and you care about uninitialized vs default value), you probably want to use `*bool` instead of `bool`. It makes things a bit harder to deal with though, so make sure you need to. – captncraig May 08 '17 at 18:55
  • @OliviaRuth: yeah, I think that's my only real solution. But like you said, it makes things slightly more complicated. Maybe it's not that important for me to have optional inputs. – Adam May 08 '17 at 20:01
  • 3
    Worth noting that if the default for the boolean is "true", you should probably invert the boolean. For example, if the boolean is "logInput", and you want it to default to on, you should probably make the boolean option instead be "noLog" and default to false. This follows the Go axiom of making default values useful. – Kaedys May 08 '17 at 20:34
  • You have two options in here, one is use pointer for fields, the second is encapsulate the `Options` struct and generate `Get` and `Set` methods for the fields that record/check if is set. – Motakjuq May 09 '17 at 01:40

2 Answers2

4

For detecting uninitialized struct fields, as a rule certain types have zero values, they are otherwise nil (maps and channels need to be maked):

var i int     // i = 0
var f float64 // f = 0
var b bool    // b = false
var s string  // s = ""
var m chan int// c = nil

There is a tour slide which is useful.

I think you're problem involves creating a default boolean value of true


For your sake, however, if you are passing an Option struct into that function, and the user did not specify the options, then yes they will be false and "" by default.

One solution is to create a(nother) constructor: func NewOptions(b bool, s string) Options

This constructor would make the bool default true.

You could also try an enum to simulate a boolean; the zero value will be 0. So instead of type bool for the Options struct value BoolOption, you could use int:

const (
        TRUE
        FALSE
)

You could also have a UNINITIALIZED as zero, but I think you just want to switch the default value, rather than detecting that it is uninitialized.

So when checking a value of Options, you could write:

if opt.BoolOption == FALSE {
    // Do something with the option
} else {
    // The default option
}

A bit simpler would be to make the BoolOption into notBoolOption, and have the default be false.


Or, as Olivia Ruth points out, if you have the field as a pointer to a boolean, it will be remain nil until "initialized".

Nevermore
  • 7,141
  • 5
  • 42
  • 64
  • Thanks for this. I think the only other option, as @Olivia Ruth points out, I could use a pointer inside by options struct and check for nil. – Adam May 09 '17 at 16:32
1

The default value for a bool is false. If you notice that you are overwriting the options value to true every time you run the code.

The default values of a strings variable is "". So if check the string with len(opts.StringOption) == 0 or opts.StringOption == "" that would work as well.

https://play.golang.org/p/jifZZvoBVZ

JT.
  • 490
  • 1
  • 3
  • 9