We have below code scenario:
func f(a, b, c *int) *int {
check := c == nil
switch check {
case true:
if g(a) {
return nil
}
return h(a)
case false:
return k(a, b, c)
}
return nil // non reachable code
}
return nil is non-reachable code. Reproducible code: https://play.golang.org/p/lIrTxZkNbg6
Why Go compiler complains about non-reachable code? How to avoid non-reachable code? Is switch-case syntax causing non-reachable code?
Your switch statement is evaluating a boolean which has just 2 possible choices, so there is no possibility for it to ever reach the final return statement.
In this specific case it is more readable to use if instead of switch
if check {
if g(a) {
return nil
}
return h(a)
}
return k(a, b, c)
rewrite your function in more simple terms (using if).
func f(a, b, c *int) *int {
if c == nil {
if g(a) {
return nil
}
return h(a)
}
return k(a, b, c)
}
The compiler only knows that the statement is unreachable if it follows a terminating statement. Terminating switch statements are:
A "switch" statement in which:
there are no "break" statements referring to the "switch" statement,
there is a default case, and
the statement lists in each case, including the default, end in a terminating statement, or a possibly labeled "fallthrough" statement.
So, the rules aren't comprehensive enough to determine this case where every possible value of the switched data type has a terminating case (as you have here). This rule would add needless complexity to the compiler and language as, practically, it would only apply to the exact situation you've shown here, which can (and should) easily be replaced by if/else statements.
Keep in mind that case values in a switch statement don't necessarily need to be constant or unique, and bool is arguably the only data type that has few enough unique values that you might realistically cover all of them in a switch statement.
Related
I just got started with Golang, and I saw the typical swap function example:
func swap(x, y string) (string, string) {
return y, x
}
I automatically thought that the named returns could have solved it and that it was a sweeter example, so I tried the shorter version:
package main
import "fmt"
func swap(z, y int) (z, y int) {
return
}
func main() {
fmt.Println(swap(2, 3))
}
But to by my surprise it didn't compile complaining about a duplicate argument. Why is not possible to return an input argument? Am I doing something wrong or it is just not supported?
I thought this was a totally valid use case and that it could have been many other examples for this usage.
I'm also a Golang beginner. Here's what I managed to find out.
The problem is essentially, that you declare two variables named z, then expect them to be unified. This is not supported, and in fact would go against the main goal of named return types, which is to document the meaning of the values returned.
To explain in more detail, this is a bit like writing the following code:
func badFunction(a int) int {
var a int = 0
return a
}
A variable is declared twice, and this is confusing for Go. If we look at what the 'tour of go' has to say about named return values, we can see the issue. It's not the greatest source, but it's a source nonetheless:
Go's return values may be named. If so, they are treated as variables defined at the top of the function.
That is to say, your example is almost exactly like badFunction. To the compiler, it looks a bit like this:
func swap(a, b int) (int, int) {
var a int = 0
var b int = 0
return b, a
}
Naturally, the compiler complains about a redeclared in block, which is a related though admittedly not equal error. The error message you receive there appears to essentially be a pre-check to prevent the user from seeing the code produced when desugared.
As this Stackoverflow question reports, named return values should essentially be for documentation only. However, it does mention the possibility of accidental shadowing. It may be that an earlier Go version supported this, but has since been changed to prevent bugs due to this kind of name collision, however I have not found anything pertaining to this.
The effective go section on the topic also has something to say:
The return or result "parameters" of a Go function can be given names and used as regular variables, just like the incoming parameters. When named, they are initialized to the zero values for their types when the function begins; if the function executes a return statement with no arguments, the current values of the result parameters are used as the returned values.
The names are not mandatory but they can make code shorter and clearer: they're documentation.
TL;DR: The compiler doesn't unify names in the way you might expect. This kind of implicit shadowing not supported, and should be actively avoided to prevent certain easily avoidable bugs.
I guess problem is not in returning input argument, but in names duplication: y and z are declared twice on the same level and compiler cannot distinguish.
When you declare a variable in return type, Go compiler would consider that, you are declaring the variable there for future use.
Now when the compiler sees the same variable name in both input & return part, it will report a duplicate argument issue.
You can try the working example below, if you want to
func swap(x, y string) (a string, b string) {
a = y
b = x
return
}
You can do this way
func checkError(err *error) (bool, *error) {
if err != nil {
return false, err
} else {
return false, nil
}
}
or if you really want to use variable, this way
func checkError(err *error) (result bool, err_msg *error) {
if err != nil {
return false, err
} else {
return false, nil
}
}
The following code generates a syntax error (unexpected ++ at end of statement) in Go 1.6 or 1.7:
package main
import "fmt"
var x int
func increment() int {
return x++ // not allowed
}
func main() {
fmt.Println( increment() )
}
Shouldn't this be permitted?
It's an error, because the ++ and -- in Go are statements, not expressions: Spec: IncDec Statements (and statements have no results that would be returned).
For reasoning, see Go FAQ: Why are ++ and -- statements and not expressions? And why postfix, not prefix?
Without pointer arithmetic, the convenience value of pre- and postfix increment operators drops. By removing them from the expression hierarchy altogether, expression syntax is simplified and the messy issues around order of evaluation of ++ and -- (consider f(i++) and p[i] = q[++i]) are eliminated as well. The simplification is significant. As for postfix vs. prefix, either would work fine but the postfix version is more traditional; insistence on prefix arose with the STL, a library for a language whose name contains, ironically, a postfix increment.
So the code you wrote can only be written as:
func increment() int {
x++
return x
}
And you have to call it without passing anything:
fmt.Println(increment())
Note that we would be tempted to still try to write it in one line using an assignment, e.g.:
func increment() int {
return x += 1 // Compile-time error!
}
But this also doesn't work in Go, because the assignment is also a statement, and thus you get a compile-time error:
syntax error: unexpected += at end of statement
The accepted solution is right that the OP's code does not work because in go increment/decrement(x++/x--) statements are expressions that don't return a value.
However the solution presented has a slightly different effect than the original request.
x++ would return the value of x then increment in C like syntax.
however the opposite would happen if you do it this way:
x++
return x
You can negate that issue by reducing your initial value by one or by using a defer statement as written here:
func incr() int {
defer func() { counter++ }()
return counter
}
https://play.golang.org/p/rOuAv7KFJQw
Go's interface{} type is both the best and most annoying feature of the language, I find. I'm trying to create a simple user-customisable validation rule solution where the user can define:
The comparison operator.
The comparison operand.
The map key that leads to the value to test.
As well as a simple Boolean expression parser that allows the user to combine multiple rules using AND and OR. So far it all works well, the expressions can be parsed, tokenised, and evaluated successfully, but it's running the rules on the given data that causes problems.
This is the current version of the function that actually evaluates the data:
/*
validate returns a boolean value denoting whether a test was successful. This
function will panic if the type assertions fail.
*/
func (sfvre standardFieldValidationRuleEntry) validate(fieldValue interface{}) bool {
switch sfvre.Operator() {
case VROP_EQUAL:
return fieldValue == sfvre.ComparisonOperand()
case VROP_NEQUAL:
return fieldValue != sfvre.ComparisonOperand()
case VROP_GT:
return fieldValue.(int) > sfvre.ComparisonOperand().(int)
case VROP_LT:
return fieldValue.(int) < sfvre.ComparisonOperand().(int)
case VROP_GTET:
return fieldValue.(int) >= sfvre.ComparisonOperand().(int)
case VROP_LTET:
return fieldValue.(int) <= sfvre.ComparisonOperand().(int)
case VROP_CONTAINS:
return strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
case VROP_NCONTAINS:
return !strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
default:
return false
}
}
At the moment the operator implies whether the data is numeric (greater than, less than, etc.). The type assertion to int did the job while building the other parts of the package, but the finished system should also be able to take float64 and be able to handle mixed type comparisons.
The only way I can see of doing this at the moment is by having multiple nested type switches, a level for each of:
The operator.
The type of the field value given.
The type of the comparison operand.
But this has the potential to become very large and not easily manageable. Is there a 'cleaner' way to do this that I can't see, or am I stuck using nested switches?
The solution I've got as of now (thanks to #Volker for the suggestion) does a quick type switch on the values that need comparing and then instead of using the originals in the Operator() switch, it uses the concrete float values:
/*
validate returns a boolean value denoting whether a test was successful. This
function will panic if the type assertions fail.
*/
func (sfvre standardFieldValidationRuleEntry) validate(fieldValue interface{}) bool {
var floatFieldVal, floatCompVal float64
//If the interface is int or float, convert it to a statically typed float64.
switch fieldValue.(type) {
case int:
floatFieldVal = float64(fieldValue.(int))
case float64:
floatFieldVal = fieldValue.(float64)
}
//Do the same with the comparison value.
switch sfvre.ComparisonOperand().(type) {
case int:
floatCompVal = float64(sfvre.ComparisonOperand().(int))
case float64:
floatCompVal = sfvre.ComparisonOperand().(float64)
}
switch sfvre.Operator() {
case VROP_EQUAL:
return fieldValue == sfvre.ComparisonOperand()
case VROP_NEQUAL:
return fieldValue != sfvre.ComparisonOperand()
case VROP_GT:
return floatFieldVal > floatCompVal
case VROP_LT:
return floatFieldVal < floatCompVal
case VROP_GTET:
return floatFieldVal >= floatCompVal
case VROP_LTET:
return floatFieldVal <= floatCompVal
case VROP_CONTAINS:
return strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
case VROP_NCONTAINS:
return !strings.Contains(fieldValue.(string), sfvre.ComparisonOperand().(string))
default:
return false
}
}
It doesn't catch everything, but restricting what operators the user can choose based on what field they're comparing can mitigate this, but that's part of the larger solution so irrelevant here.
I have a type method that mutates the type's fields. It takes no arguments and returns nothing. The bulk of the method is a switch block. I want to be able to "short-circuit" out of the switch block with a no-op. Before I refactored it into a type method, I would've just returned out of the function, but that's out. Removing the case would break the logic of the method--the default case mutates state, which I don't want to do if this case is matched. I need the equivalent of Python's pass, basically.
Code:
func (parser *Parser) endSectionName () {
state = parser.State
buffer = parser.buffer
results = parser.results
switch {
case state.HasFlag(IN_ESCAPED) {
// ???
}
case !inSection(state) {
return state, NotInSectionError
}
case !state.HasFlag(IN_SECTION_NAME) {
state.Reset()
return state, errors.New("Parsing error: Not in section name")
}
default {
state.RemoveFlag(IN_SECTION_NAME)
s := buffer.String()
results[s] = new(Section)
buffer.Reset()
return state, nil
}
}
}
Unlike in other languages, in Go the control flow breaks at each case of a switch statement, control doesn't flow into the next case unless it is explicitly "asked" for with the fallthrough statement.
And also a statement is not required after the case (it can be empty). See this example:
i := 3
switch i {
case 3:
case 0:
fmt.Println("Hello, playground")
}
It will print nothing even though i==3 and there is no statement after case 3.
Same as this:
i := 3
switch {
case i == 3:
case i == 0:
fmt.Println("Hello, playground")
}
Try it on the Go Playground.
Normal use of function variables in Go allows them to be compared only to nil, not to one another. The reason for this (as it's been explained to me) is that, since Go has closures, the definition of equality is fuzzy. If I have two different closures with different values bound to local variables, but which use the same underlying function, should they be considered equal or unequal?
However, I do want to be able to make such a comparison. In particular, I have code like this (except, in my real code, the check is actually necessary - this is just a dummy example), where I compare a function pointer to a function literal:
func getFunc(which bool) (func ()) {
if which {
return func1
} else {
return func2
}
}
func func1() { }
func func2() { }
f := getFunc(true)
if f == func1 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
Is there any way, for example using the reflect or unsafe packages, to get this to work?
You could compare the functions by name:
f := getFunc(true)
f1 := runtime.FuncForPC(reflect.ValueOf(f).Pointer()).Name()
f2 := runtime.FuncForPC(reflect.ValueOf(func1).Pointer()).Name()
if f1 == f2 {
fmt.Println("func1")
} else {
fmt.Println("func2")
}
But this relies on both the reflect and runtime packages. Probably not a good idea to do this.
Do you really need to compare functions? I would consider an alternative if possible.
Extending upon #Luke's answer, it appears that I can directly test pointer equality. Note that this is really iffy. To quote the reflect.Value.Pointer() documentation:
If v's Kind is Func, the returned pointer is an underlying code
pointer, but not necessarily enough to identify a single function
uniquely. The only guarantee is that the result is zero if and only if
v is a nil func Value.
That said, here's what you can do:
f := getFunc(true)
f1 := reflect.ValueOf(f).Pointer()
f2 := reflect.ValueOf(func1).Pointer()
eq := f1 == f2
Note that I did run a battery of tests (which I had used to regression-test the code that resulted from #Luke's answer) against this new version, and they all passed, which leads me to believe that the warning issued in the reflect documentation may be OK to ignore, but then, ignoring documentation is really never a good idea...
If all the functions you want to compare have the same signature, you could do something like this:
type cmpFunc struct {
f func()
id uint64
}
func (c *cmpFunc) call() { c.f() }
func (c *cmpFunc) equals(other *cmpFunc) { return c.id == other.id }
makeComparable(f func()) *cmpFunc {
return &cmpFunc{f, get_uniq_id()}
}
Where get_uniq_id does what it says on the box. This gets a bit uglier because Go doesn't have () overloading, and it's more or less impossible without generics if you want to do this for functions in general. But this should work pretty well for your purposes.