Go MinGW compiler complains about if-else statement - go

Consider the following (useless) Go function:
func domagic(n int) int {
if n > 10 {
return n;
} else {
return 0;
}
}
This gives me the following compiler error:
main.go:15: function ends without a return statement
However, if i return a value outside the if-else block (before the end of the function), it compiles without errors.
Is this behavior by design, or is it something simply not yet implemented in the Go MinGW compiler?

Simple googling for the exact compiler error message yields this bugtracker issue. So I'd not say it's "by design" as it looks more like "it'd just happened to be implemented this way". See also this thread.

It's by design. Write:
package main
import "fmt"
func domagic(n int) int {
if n > 10 {
return n
}
return 0
}
func main() {
fmt.Println(domagic(7), domagic(42))
}
Output:
0 42

Related

Go Tour flowcontrol #5: understand the return keyword

In the slide #5 of the flow control Go Tour I don't understand how the return keyword is working inside the function sqrt().
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
I understand the code with a else clause like this
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}else{
return fmt.Sprint(math.Sqrt(x))
}
}
This code executes without problems, but the linter, golint, in VsCode complains about the else clause.
Does the statement return sqrt(-x) + "i" inside the first if block ends the execution of the function ?
how is it exactly working ?
As with most (if not all?) the first return statement the compiler hits will exit the function and not continue.
It's warning reported by go linter. Code underneath is valid.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
}
return fmt.Sprint(math.Sqrt(x))
}
This one below is also valid, but will generate some warning.
func sqrt(x float64) string {
if x < 0 {
return sqrt(-x) + "i"
} else {
return fmt.Sprint(math.Sqrt(x))
}
}
Basically if there is if statement and the body contains return statement, better not to use else block.
The Go Programming Language Specification
Return statements
A "return" statement in a function F terminates the execution of F,
and optionally provides one or more result values. Any functions
deferred by F are executed before F returns to its caller.
The specification defines the language. return terminates the function.
Go Code Review Comments
Indent Error Flow
Try to keep the normal code path at a minimal indentation, and indent
the error handling, dealing with it first. This improves the
readability of the code by permitting visually scanning the normal
path quickly. For instance, don't write:
if err != nil {
// error handling
} else {
// normal code
}
Instead, write:
if err != nil {
// error handling
return // or continue, etc.
}
// normal code
While either will work, as a matter of style, remove the unnecessary else and indentation. It's a similar to error flow indentation.

Calling a function with Go Reflect

I was wondering if it was possible to not know a function name but call it anyway and get values from it. This lead me to the reflection package and I got pretty close but I’m not sure about the last step - if there is one. Again please forgive me if I am missing something obvious, this is my first attempt at doing anything in Go other than getting it setup.
Of course being a compiled language there is no need to iterate through things to find function names, I know them all, but this is something I want to see if it is possible… I’m playing and learning.
Below is the code. What I would really like to do is in the main line extract the values set in ModuleBoot() <“1.0012”, 23> and SomethingBoot() <“1.0000”, 10> but so far all as I can get is structure information. Perhaps that’s just the way it is but perhaps there is a step or change that can make it go the next step.
Hopefully I copied all the relevant code over correctly so it compiles as is:
// Using: go version go1.9.7 linux/amd64
=======================================
FILE: main.go
=======================================
package main
import (
"fmt"
"reflect"
"playing/modules/core"
)
func main() {
miType := reflect.TypeOf(core.ModuleInfo{})
fmt.Println("")
for i := 0; i < miType.NumMethod(); i++ {
method := miType.Method(i)
fmt.Println(method.Name)
in := make([]reflect.Value, method.Type.NumIn())
in[0] = reflect.ValueOf(core.ModuleInfo{})
//fmt.Println("Params in:", method.Type.NumIn(), "Params out:", method.Type.NumOut())
mi := method.Func.Call(in)
fmt.Println("mi:", mi)
fmt.Println("")
}
}
=======================================
FILE: playing/modules/core/something.go
=======================================
package core
func (mi ModuleInfo) SomethingBoot() ModuleInfo {
mi.Version = "1.0000"
mi.Priority = 10
return mi
}
=======================================
FILE: playing/modules/core/modules.go
=======================================
package core
type ModuleInfo struct {
Version string
Priority int
}
func (mi ModuleInfo) ModuleBoot() ModuleInfo {
mi.Version = "1.0012"
mi.Priority = 23
return mi
}
The output I got from this was:
Started delve with config "Debug"
SomethingBoot
mi: [<core.ModuleInfo Value>]
ModuleBoot
mi: [<core.ModuleInfo Value>]
delve closed with code 0
To get the return value as a ModuleInfo, get the underlying value of the first return value and type assert that interface value to ModuleInfo:
// mi has type core.ModuleInfo
mi := method.Func.Call(in)[0].Interface().(core.ModuleInfo)
Run it on the Playground.
You can cut some of the reflect code by type asserting the method to a function with the correct signature and calling that function directly:
for i := 0; i < miType.NumMethod(); i++ {
method := miType.Method(i).Func.Interface().(func(core.ModuleInfo) core.ModuleInfo)
mi := method(core.ModuleInfo{})
fmt.Println("Version", mi.Version)
fmt.Println("Priority", mi.Priority)
fmt.Println("")
}
Run it on the Playground
Go natively supports functions as values; you don't need reflection to do this.
In particular, if you make your two functions top-level functions (not specifically tied to a struct):
package core
type ModuleInfo struct { ... }
func SomethingBoot() ModuleInfo
func ModuleBoot() ModuleInfo
Then you can write a function that takes a function as a parameter:
func PrintVersion(func booter() core.ModuleInfo) {
mi := booter()
fmt.Printf("version %s\n", mi.Version)
}
And you can just pass the pre-existing functions as parameters:
PrintVersion(core.SomethingBoot)
PrintVersion(core.ModuleBoot)
Notice that there aren't parentheses after the function name: you are passing the function itself as a parameter, not calling the function and passing its return value.

Print string X number of times without using loops or conditions

I was asked this question and could not come up with a solution, hope to find it here.
We need a function that receives a number (X) and a string, it needs to print that string X number of times, without using any loops or if-else conditions.
It's more about a generic algorithm not a specific programming language.
My initial response was recursion, but it requires an IF clause.
func (int x, string namme)
{
if(x>0)
{
print (name);
func(x-1);
}
}
In general case, you cannot do that. Even recursion's terminal case requires condition. The only solution in such case is ... Template magic (surprise!)
Here is the solution:
template <int times>
void print(const string& str);
template <>
void print<0>(const string& str)
{
}
template <int times>
void print(const string& str)
{
cout << str << " ";
print<times - 1>(str);
}
Such approach requres from you compile time value of number of times. But result code will not contain any conditions (you can see asm code)
Example of usage:
print<5>("Yeah!");
You can use a little trick in c++:
§4.7/4 (Integral Conversion)
If the source type is bool, the value false is converted to zero and the value true is converted to one.
This means you can index an array using a boolean value. If your array contains function pointers you implemented an if/else statement.
void noop(int,std::string) {}
void print_n_times(int times, std::string text) {
void (*next_function[])(int,std::string) = {
noop,
print_n_times
};
next_function[(times-1)>0](times-1, text);
std::cout << times << ' ' << text << '\n';
}
See it live
You can do the same thing in python:
Python 2.7.12 (default, Oct 10 2016, 12:56:26)
[GCC 5.4.0] on cygwin
Type "help", "copyright", "credits" or "license" for more information.
>>> def noop(times,text):
... pass
...
>>> def print_n_times(times,text):
... next_function = [noop, print_n_times]
... print(text);
... next_function[int((times-1)>0)](times-1, text)
...
>>> print_n_times(4, "Hello World!")
Hello World!
Hello World!
Hello World!
Hello World!
Here is a complete program demonstrating this. I would not recommend writing anything like this in Real Life.
This takes advantage of the fact that subtracting 1 from 0 will set the most significant bit in an integer. I shift bit 63 down to 0 to get either a 1 or 0 (i.e. to avoid a conditional) and call one of two functions. runtime.Goexit will terminate a goroutine, but will call all deferred functions in the process. This unlocks a mutex that lets the sillyString function terminate only after all of the prints have happened.
package main
import (
"fmt"
"runtime"
"sync"
)
func main() {
sillyString("omg", 10)
}
func sillyString(s string, n int) {
var m sync.Mutex
m.Lock()
go func() {
defer m.Unlock()
mustGoDeeper(s, uint64(n-1), []func(){runtime.Goexit, func() {}})
}()
m.Lock()
}
func mustGoDeeper(s string, n uint64, fs []func()) {
sig := (1 - int(n>>63))
fs[sig]()
fmt.Printf("%s\n", s)
mustGoDeeper(s, n-1, fs)
}
Recursion looks like a good way to go, but we need to stop an infinite recursion. That means being sneaky. Using a try ... catch can do the job, at least in a language which supports that construct:
void printXtimes(String text, int x) {
try {
int z = 100 / x;
} catch (Exception ex) {
// Zero divide so exit program.
exit(0);
}
println(text);
printXtimes(text, x-1);
} // end printXtimes()
That is a Java-like pseudocode. In real Java the compiler gives a warning about infinite recursion, but it compiles and runs correctly, printing the text message the given number of times. An interesting problem.

Using testing.Benchmark does not produce any output

I'm using testing.Benchmark to manually run a couple benchmarks but the result object is always empty.
Am I missing something here?
Here's an example:
package main
import "testing"
func main() {
result := testing.Benchmark(func(parentB *testing.B) {
parentB.Run("example", func(b *testing.B) {
for n := 0; n < b.N; n++ {
println("ok")
}
})
})
println(result.String())
}
This will print ok a couple times and then 0 0 ns/op but the benchmark clearly did run something.
I think you are doing everything right. Doc of testing.Benchmark() says:
Benchmark benchmarks a single function. Useful for creating custom benchmarks that do not use the "go test" command.
If f calls Run, the result will be an estimate of running all its subbenchmarks that don't call Run in sequence in a single benchmark.
Looking into the implementation (Go 1.7.4):
func Benchmark(f func(b *B)) BenchmarkResult {
b := &B{
common: common{
signal: make(chan bool),
w: discard{},
},
benchFunc: f,
benchTime: *benchTime,
}
if !b.run1() {
return BenchmarkResult{}
}
return b.run()
}
This line:
if !b.run1() {
return BenchmarkResult{}
}
b.run1() is supposed to run your passed function once, and detect if it has sub-benchmarks. Yours has. It returns a bool whether more runs are needed. Inside run1():
if b.hasSub || b.finished {
// ...
return true
}
It properly tells it has sub-benchmark, and Benchmark() –with noble simplicity– just returns an empty BenchmarkResult:
if !b.run1() {
return BenchmarkResult{}
}
I do believe that either this is a bug (or rather "incomplete" feature), or doc is incorrect. I suggest to file an issue here: https://github.com/golang/go/issues
Eddited the answer to clarify:
My guess is that you are using go run to run the test. That will not produce any result. In order to run the code exatly as it is written you need to use
go test -bench=. and I think it should work.
The file must be named test_xxx.go where xxx is whatever you want.
If you restucture you code a litle bit it can be run as a single function benchmark:
package main
import "testing"
func main() {
myTest()
}
func myTest() {
fn := func(b *testing.B) {
for n := 0; n < b.N; n++ {
println("ok")
}
}
result := testing.Benchmark(fn)
println(result.String())
}

Shorthand return

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

Resources