How to call unexported function within package? - go

I'm trying to write a package to work with. Here is sample code:
package redis
import (
"fmt"
"github.com/gomodule/redigo/redis"
"log"
"os"
)
var conn redis.Conn
func init() {
// code to set conn variable
}
func do(command string, args ...interface{}) (interface{}, error) {
init()
return conn.Do(command, args)
}
This code does not compile and compilator says undefined: init. When I change init() to Init() it works, but I don't want it to be available outside of package.
Wherever I read about this problem, it says about calling unexported function from another package, but here I'm calling it from same one.
Also, Goland IDE marks function call as unresolved reference and suggests to create it. But when I do (by IDE itself), it still doesn't see it.

init() is a special function. From the language spec:
func init() { … }
Multiple such functions may be defined per package, even within a
single source file. In the package block, the init identifier can
be used only to declare init functions, yet the identifier itself
is not declared. Thus init functions cannot be referred to from
anywhere in a program.
Use init() for package level initializations.

In Go, init is reserved for initializing work that needs to be done in a package, eg. adding some implementation to some registry.
To solve this problem, you need to use another name.
Take a look at this question to learn more about init if you are interested.

Related

Go package Global Variable usage within imports

I am creating a package that will be called from other services that I have in Go. If a service imports this package, and this package has global variables, will the component store the global variables in its' own memory?
So if my package looks something like this,
var global1 = ""
var global2 = ""
var global3 = ""
var global4 = ""
func setAllGlobalValues() error {
// some logic that checks if globals are nil
// if not setting it to a value after some computation.
// returns nil or an actual error.
}
func DoesSomethingUsingGlobalVars() (bool, error) {
// sets and uses the global vars.
// Does some sort of computation and returns a bool, nil or nil,error
}
Then in the service I would import this package and use the doesSomethingUsingGlobalVars function.
Will the component using this package store the global variables in its own memory? I can't really test it now with my services with the way things are set up so I'm just curious if anyone knows.
Essentially, will this work or will the global vars be nil each and every-time anything is called from a service that imports this package?
Thanks in advance all!
When your program imports this package, the globals will be set when you call SetAllGlobalValues(), and later, when you call DoesSomethingUsingGlobalVars(), those values will already be set. Note that the first letter of those function names must be capitalized so that they are exported and available for use by other packages. If the variables are not exported, as shown in your code snippet, you will not be able to access them directly from the caller.
It seems as if you are trying to reinvent objects. Instead of your code, do
something like this:
package some
import "fmt"
type Thing struct {
One string
Two string
Three string
Four string
}
func NewThing() Thing {
return Thing{"One", "Two", "Three", "Four"}
}
func (t Thing) Print() {
fmt.Println(t.One, t.Two, t.Three, t.Four)
}
Then, the "global variables" are only calculated once, when you call NewThing.

Create equivalent interface of another package with an interface as argument

I am practicing writing idiomatic Go code and discovered that interfaces should be declared in packages which are consuming them since they're implicit. However I came to this situation where by in the second package (package b) I want a function to call the receiver function of a struct in package a without coupling it tightly.
So naturally, I declare an interface in package b with the signature of the function I want to call from package a. The problem is that this function accepts an argument of a certain type which is an interface declared in package a. As I don't want package b to import package a, I defined an interface in package b with the exact same signature as the one which exists in package a. The playground link below shows the example code.
Playground
package main
import (
"fmt"
"log"
)
func main() {
manager := &Manager{}
coach := NewRunnerCoach(manager)
fmt.Println("Done")
}
// package a
type Runner interface {
Run()
}
type Manager struct {
}
func (o *Manager) RegisterRunner(runner Runner) {
log.Print("RegisterRunner")
}
func (o *Manager) Start() {
log.Print("Start")
}
// package b
type RunnerCoach struct {
runner *FastRunner
}
func NewRunnerCoach(registerer runnerRegisterer) *RunnerCoach {
runnerCoach := &RunnerCoach{&FastRunner{}}
registerer.RegisterRunner(runnerCoach.runner)
return runnerCoach
}
type FastRunner struct {
}
func (r *FastRunner) Run() {
log.Print("FastRunner Run")
}
// define ther registerer interface coach is accepting
type runnerRegisterer interface {
RegisterRunner(runner RunnerB)
}
// declaring a new interface with the same signature because we dont want to import package a
// and import Runner interface
type RunnerB interface {
Run()
}
This code does not compile. So the question here is that, am I using interface wrongly or should concrete types be defined in a separate package or lastly, is there a better code pattern for the problem I'm trying to solve?
EDIT: To clarify, package a and b does not import each other. The main() code exists in a separate package which connects these two.
IIUC, your question is not about packages but boils down to whether a function (or method)
can be typecast to another function which takes arguments with equivalent, but
not the same interface types.
Something like this: (Go Playground)
package main
type I1 interface{}
func f1(x I1) {}
func main() {
f := (func(interface{}))(f1)
f(nil)
}
Compilation error: ./g.go:8:26: cannot convert f1 (type func(I1)) to type func(interface {})
The answer appears to be no, because Go doesn't consider func (I1) to be
equivalent to func (interface{}). The Go spec says this
A function type denotes the set of all functions with the same parameter and result types.
The types func (I1) and func (interface{}) do not take the same parameters, even though
I1 is defined as interface{}. Your code fails to compile for a similar
reason because func (runner RunnerB) is not the same as func (runner Runner) and hence the method set of *Manager is not a superset of the
interface runnerRegisterer.
Coming to your original question:
I am practicing writing idiomatic Go code and discovered that interfaces
should be declared in packages which are consuming them since they're
implicit.
Yes, the idea is good but it doesn't apply to your implementation the way you
think it does. Since you're expecting to have different implementations of
runnerRegisterer and they must all have a method with the same signature
using the Runner interface, it makes sense to define Runner in a common
place. Also, as seen above Go wouldn't allow you to use a different interface
in the method signatures anyway.
Based on my understanding of what you're trying to achieve, here's how I think
you should re-arrange your code:
Define RunnerRegisterer (note: this is public) and Runner in one
package.
Implement your RunnerCoach in the same package and use the above
interfaces. Your RunnerCoach consumes types that implement the interfaces,
so it defines them.
Implement your runners in another package. You don't define the Runner
interface here.
Implement your Manager in another package, which uses the interface
Runner defined in RunnerCoach's package because it must take that type
as an argument if it wants to be used as a RunnerRegisterer.
The Solution
You've got a type that is used in two packages, A and B. Package A imports package B.
You have to avoid circular dependencies, so you have three choices:
Define the type in package B, so it will be available in both
packages.
Define the type in package C and have both A and B import package C.
Change your design such that the type is not used in both A and B.
These are your choices whether that type is an interface or any other type.
Choose the option that best fits your design goals.
The Rule / Idiom
I am practicing writing idiomatic Go code and discovered that
interfaces should be declared in packages which are consuming them
since they're implicit.
I get the impulse/idea - the problem is it's not very practical. Interfaces would be less useful if they could only be consumed in the package in which they are defined. The standard library is full of code that violates this axiom. Therefore I do not think the rule as presented -- applying to all interfaces in all situations, designs and contexts -- is idiomatic.
For example, look at the bytes package. func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) consumes io.Reader, an interface defined in another package. func (r *Reader) WriteTo(w io.Writer) (n int64, err error) consumes io.Writer, an interface defined in another package.

Viper, cannot get the value initialized outside the functions

I have a problem using a viper, I have assigned variable by viper method, so when I try to get value inside any function I have a null value. Does anybody have any idea why does it happen so? Any other variables initialization works fine, but not viper GetString method.
Structure:
main.go
package main
import (
"project/Model"
"github.com/spf13/viper"
...
)
func main() {
//Config handling
viper.SetConfigName("main")
viper.AddConfigPath("/config/")
err = viper.ReadInConfig()
...
}
Package Model
package Model
import ("github.com/spf13/viper"
...
)
var sqlhost = viper.GetString("db.host")
func foo() {
log.Println(sqlhost)
}
I suspect that doing package variable initialization as you show will lead to the viper configuration not being complete before performing the GetString(), and therefore the zero (empty) string value is what is returned. Without seeing how you initialize your viper config, I'm guessing that it's not in an init() function, but is in a main() function that hasn't run yet when the package variable is assigned.
You should probably retrieve the viper.GetString("db.host") inside the highest level function that needs it rather than during package initialization.

Why can't you name a function in Go "init"?

So, today while I was coding I found out that creating a function with the name init generated an error method init() not found, but when I renamed it to startup it all worked fine.
Is the word "init" preserved for some internal operation in Go or am I'm missing something here?
Yes, the function init() is special. It is automatically executed when a package is loaded. Even the package main may contain one or more init() functions that are executed before the actual program begins: http://golang.org/doc/effective_go.html#init
It is part of the package initialization, as explained in the language specification: http://golang.org/ref/spec#Package_initialization
It is commonly used to initialize package variables, etc.
You can also see the different errors you can get when using init in golang/test/init.go
// Verify that erroneous use of init is detected.
// Does not compile.
package main
import "runtime"
func init() {
}
func main() {
init() // ERROR "undefined.*init"
runtime.init() // ERROR "unexported.*runtime\.init"
var _ = init // ERROR "undefined.*init"
}
init itself is managed by golang/cmd/gc/init.c:
Now in cmd/compile/internal/gc/init.go:
/*
* a function named init is a special case.
* it is called by the initialization before
* main is run. to make it unique within a
* package and also uncallable, the name,
* normally "pkg.init", is altered to "pkg.init·1".
*/
Its use is illustrated in "When is the init() function in go (golang) run?"

go how to check if a function exists

Is there any way to check if a func exists in Go?
In PHP I might do something like
if(function_exists('someFunction')) {
//...
}
but I have not been able to figure out how to do this in Go
Any help on this will be greatly received.
A little more context on what you're trying to do would help.
As you note in your own comment, if you try to call a function Go checks at compile-time if the function exists, most of the times.
One exception that comes to my mind is when you use interface{} and you want to check that a method exists before calling it. For this you can use type checks.
Example:
package main
import "fmt"
// a simple Greeter struct
// with a Hello() method defined
type Greeter struct {
Name string
}
func (m *Greeter) Hello() string {
return "hello " + m.Name
}
var x interface{}
func main() {
x = Greeter {Name:"Paolo"} // x is a interface{}
g,ok := x.(Greeter) // we have to check that x is a Greeter...
if ok {
fmt.Println(g.Hello()) // ...before being able to call Hello()
}
}
Another scenario I can think of is that you're creating your own tool for Go that requires parsing go files before compiling them. If so, Go provides help in the for of the parser package
There's no way to do that (and for good!). The reason is that Go is a compiled language and does not support loadable modules (yet, at least) so functions can't come and go at runtime, and hence whether or not a top-level function exists, you know by defintion: if a given source file imports a package containing the function of interest1, that function is visible in this source file. Or this function is declared in the same package this source file belongs to and hence it's also available. In all the other cases the function is not available. Note that a function might be compiled in the program but still not visible in a given source file while compiling, so the whole definition of visibility as you put it does not exist in Go.
On the other hand you might want some generality. Generality in Go is achieved via interfaces. You might define an interface and then require a type to implement it. Checking that a type implements an interface is done via a neat trick.
An update from 2021-12-29.
The support for loadable modules was added in Go 1.8 in the form of the plugin package and has since then matured to support most mainline platforms except Windows.
Still, this solution is not without problems—for instance, see #20481.
1Without renaming that module to nothing, but let's not touch this for now.
Provided your thing is an interface value, type assert, something like this:
if Aer, ok := thing.(interface{MethodA()}); ok {
Aer.MethodA()
}
If thing is a struct, assign it to an interface variable first,
because type assertions only work on interface values.
It wouldn't hurt to define a named interface instead of using the
nonce one, but for simple cases like this it's not worth it.
Recently I had a need for figuring out if a struct has a particular function or not.
Here is another way using reflection :
package main
import (
"fmt"
"reflect"
)
type FuncRegistry struct {}
func (fr FuncRegistry) Hi() {
fmt.Println("function Hi")
}
func (fr FuncRegistry) Hello() {
fmt.Println("function Hello")
}
func functionExists(obj interface{},funcName string) bool {
mthd := reflect.ValueOf(obj).MethodByName(funcName)
if mthd.IsValid() {
fmt.Printf("Function '%s' exists \n",funcName)
return true
}
fmt.Printf("Function '%s' does not exist\n",funcName)
return false
}
// Main function
func main() {
var fr FuncRegistry
functionExists(fr,"Hi")
functionExists(fr,"Hello")
functionExists(fr,"Fail")
}
This sounds a lot like a XY problem. Please tell what you are trying to do. As far as I know, this is something you can't really do the same way as in PHP.
However, you could create a map with function names as keys. Add the functions there manually or generate the contents by parsing the source files before the compilation or at run time. Parsing the source seems like a dirty hack though.

Resources