I'm new to Golang. I understand the basics of defining new types like below:
type MyCondition bool
I know this implies that whenever I state a function takes an instance of MyCondition
it cannot be a bool
, and that's great. However, I would like to treat an instance of MyCondition
as if it was a bool
, and I've found I can't always do that:
package main
import (
"fmt"
)
type MyCondition bool
func main() {
var b1 MyCondition
var b2 = true
fmt.Println(!b1) // OK!
fmt.Println(b1 || b1) // OK
fmt.Println(b1 || b2)
}
This doesn't compile, throwing:
./prog.go:13:17: invalid operation: b1 || b2 (mismatched types MyCondition and bool)
From what I've observed, MyCondition
works as a bool on its own, but the problem occurs when I "mix" it with an actual bool
.
Questions are:
You cannot do that. You have to convert MyCondition
to bool
explicitly, i.e. bool(b1) || b2
.
From Go spec:
Logical operators apply to boolean values and yield a result of the same type as the operands.
If the left operand and the right operand have different types, the compiler can't decide the result type. So these two operands must be of the same type.
1.Why does this happen?
Go is strongly typed language. So this is by design. This ensures code correctness, and definitely excludes certain classes of programming errors.
- What's a workaround for this? I'd really like to treat it like a bool without the need of casting, polymorphically.
Workarounds:
1. Don't use new named type, just use bool
instead, if you don't need benefits.
2. Use type conversion, e.g. bool(b1)
or MyCondition(b2)
aptly.
3. Use Method set to convert or do more jobs aptly.
4. Use Go type alias (since Go 1.9): type MyCondition = bool
.
When you are using new type name for bool
you are asking compiler to strongly check for type and this classes of programming errors. So if you don't need such compiler help, don't use new named type, just use bool
instead.
And it is good to note here about Method sets and its use:
You may use new method e.g. ToBool
to do this type conversion and more if you need, try this:
package main
import "fmt"
type MyCondition bool
func (c MyCondition) ToBool() bool {
return bool(c)
}
func main() {
var b1 MyCondition
var b2 = true
fmt.Println(b2) // true
b2 = b1.ToBool() // b1.bool()
fmt.Println(b2) // false
}
Relevant references:
Type Conversion:
A conversion changes the type of an expression to the type specified by the conversion. A conversion may appear literally in the source, or it may be implied by the context in which an expression appears.
An explicit conversion is an expression of the form T(x) where T is a type and x is an expression that can be converted to type T.
Conversion = Type "(" Expression [ "," ] ")" .
Type assertions for interface types.
You can use aliases(pay attention to type definition) as a workaround, but in this case, you will lose guarantees of safety of types.
package main
import (
"fmt"
)
type MyCondition = bool
func main() {
var b1 MyCondition
var b2 = true
fmt.Println(!b1) // OK!
fmt.Println(b1 || b2)
fmt.Println(foo(b2))
}
func foo(b MyCondition) bool {
return !b
}