In Go, you can define multiple init functions in a given package, all of which will be run prior to execution in unspecified order. One consequence of having multiples of such functions is that it's impossible to call or identify them in normal code. For example, the following will not compile:
func main() {
fmt.Println(init)
}
func init() { }
(see here for a Go playground example)
My question is - what advantage does being able to have multiple init functions give, and if there weren't multiple init functions, would we be able to reference or call init functions?
Advantage of being able to have multiple init functions is IMO mainly that it improves readability by locality: You can write the initialization function next to the stuff being initialized and not remotely if you would have to centralize all the init functions to one. Which, BTW, could be then even in a different source file.
Taking a function pointer of the hypothetical per-package-single init function would be probably prohibited as well. The reason is that having such pointer would allow, in some cases, to call the init function "out of order", ie. before running its dependencies - other init functions in other packages. That would break certain guarantees.
Related
I'm on my first Golang project, which consists of a small router for an MVC structure. Basically, what I hope it does is take the request URL, separate it into chunks, and forward the execution flow to the package and function specified in those chunks, providing some kind of fallback when there is no match for these values in the application .
An alternative would be to map all packages and functions into variables, then look for a match in the contents of those variables, but this is not a dynamic solution.
The alternative I have used in other languages (PHP and JS) is to reference those names sintatically, in which the language somehow considers the value of the variable instead of considering its literal. Something like: {packageName}.{functionName}() . The problem is that I still haven't found any syntactical way to do this in Golang.
Any suggestions?
func ParseUrl(request *http.Request) {
//out of this URL http://www.example.com/controller/method/key=2&anotherKey=3
var requestedFullURI = request.URL.RequestURI() // returns '/controller/method?key=2key=2&anotherKey=3'
controlFlowString, _ := url.Parse(requestedFullURI)
substrings := strings.Split(controlFlowString.Path, "/") // returns ["controller","method"]
if len(substrings[1]) > 0 {
// Here we'll check if substrings[1] mathes an existing package(controller) name
// and provide some error return in case it does not
if len(substrings[2]) > 0 {
// check if substrings[2] mathes an existing function name(method) inside
// the requested package and run it, passing on the control flow
}else{
// there's no requested method, we'll just run some fallback
}
} else {
err := errors.New("You have not determined a valid controller.")
fmt.Println(err)
}
}
You can still solve this in half dynamic manner. Define your handlers as methods of empty struct and register just that struct. This will greatly reduce amount of registrations you have to do and your code will be more explicit and readable. For example:
handler.register(MyStruct{}) // the implementation is for another question
Following code shows all that's needed to make all methods of MyStruct accessible by name. Now with some effort and help of reflect package you can support the routing like MyStruct/SomeMethod. You can even define struct with some fields witch can serve as branches so even MaStruct/NestedStruct/SomeMethod is possible to do.
dont do this please
Your idea may sound like a good one but believe me its not. Its lot better to use framework like go-chi that is more flexible and readable then doing some reflect madness that no one will understand. Not to mention that traversing type trees in go was newer the fast task. Your routes should not be defined by names of structures in your backend. When you commit into this you will end up with strangely named routes that use PascalCase instead of something-like-this.
What you're describing is very typical of PHP and JavaScript, and completely inappropriate to Go. PHP and JavaScript are dynamic, interpreted languages. Go is a static, compiled language. Rather than trying to apply idioms which do not fit, I'd recommend looking for ways to achieve the same goals using implementations more suitable to the language at hand.
In this case, I think the closest you get to what you're describing while still maintaining reasonable code would be to use a handler registry as you described, but register to it automatically in package init() functions. Each init function will be called once, at startup, giving the package an opportunity to initialize variables and register things like handlers and drivers. When you see things like database driver packages that need to be imported even though they're not referenced, init functions are why: importing the package gives it the chance to register the driver. The expvar package even does this to register an HTTP handler.
You can do the same thing with your handlers, giving each package an init function that registers the handler(s) for that package along with their routes. While this isn't "dynamic", being dynamic has zero value here - the code can't change after it's compiled, which means that all you get from being dynamic is slower execution. If the "dynamic" routes change, you'd have to recompile and restart anyway.
I'm trying to create a template method that should be executed a certain other method is called.
For example:
func main(){
onInit()
}
func onInit(){
var Instance entity.EntityInstance
Instance.Init()
//do something
}
Another source file, instance.go
type EntityInstance struct{
name string
version string
}
func (instance *EntityInstance) Init(){
// do some initialization
}
The main method is in different code base/app and uses the Instance app to invoke certain initializations.
Currently the user writing this above main method needs to explicitly call the Instance.init()
The objective is for the developers (in this case one who implements the main method) only concern themselves with any of their custom initializations and not worry about calling "Instance.Init()". The OnInit() invoke should take care of "Instance.Init()" implicitly.
Any help to get me started in the right direction ?
EDIT: I do understand that the exact OOP concepts cannot be translated here in Golang but all I'm looking for is the appropriate approach. Clearly, I need to change the way I think of design in here but just don't know how.
Your question is a little unclear, I suspect because you are trying to directly translate ideas and idioms from another language, you should resist doing that. However, if you want an implicit init for a package in Go, you can use the magic function name
func init(){}
https://golang.org/doc/effective_go.html#init
Finally, each source file can define its own niladic init function to
set up whatever state is required. (Actually each file can have
multiple init functions.) And finally means finally: init is called
after all the variable declarations in the package have evaluated
their initializers, and those are evaluated only after all the
imported packages have been initialized.
Be careful with this though, it is implicit behaviour and could cause mysterious bugs if your callers don't know it is happening when they import your package.
I know that golang allows multiple init in one package and even in one file.
I am wondering why?
For example, if a pkg has many files, we could write multiple init then we could get lost in where to we should put init, and we could be also confused about the init order if we have multiple init in one pkg. (I mean is this better? we can only have 1 init, then we can have some initXXX, then put them into init, it seems quite clean.)
What's the advantage of doing this in code struct view?
This question may be somewhat opinion based, but using multiple package init() functions can make your code easier to read and maintain.
If your source files are large, usually you arrange their content (e.g. types, variable declarations, methods etc.) in some logical order. Allowance of multiple init() functions gives you the possibility to put initialization code near to the parts they ought to initialize. If this would not be allowed, you would be forced to use a single init() function per package, and put everything in it, far from the variables they need to initialize.
Yes, having multiple init() functions may require some care regarding the execution order, but know that using multiple init() functions is not a requirement, it's just a possibility. And you can write init() functions to not have "side" effects, to not rely on the completion of other init() functions.
If that is unavoidable, you can create one "master" init() which explicitly controls the order of other, "child" init() functions.
An example of a "master" init() controlling other initialization functions:
func init() {
initA()
initB()
}
func initA() {}
func initB() {}
In the above example, initA() will always run before initB().
Relevant section from spec: Package initialization.
Also see related question: What does lexical file name order mean?
Another use case for multiple init() functions is adding functionality based on build tags. The init() function can be used to add hooks into the existing package and extend its functionality.
The following is a condensed example demonstrating the addition of more commands to a CLI utility based on build tags.
package main
import "github.com/spf13/cobra"
var rootCmd = &cobra.Command{Use: "foo", Short: "foo"}
func init() {
rootCmd.AddCommand(
&cobra.Command{Use: "CMD1", Short: "Command1"},
&cobra.Command{Use: "CMD2", Short: "Command2"},
)
}
func main() {
rootCmd.Execute()
}
The above is the "vanilla" version of the utility.
// +build debugcommands
package main
import "github.com/spf13/cobra"
func init() {
rootCmd.AddCommand(&cobra.Command{Use: "DEBUG-CMD1", Short: "Debug command1"})
}
The contents of the second file extends the standard command with additional commands that are mostly relevant during development.
Compiling using go build -tags debugcommands will produce a binary with the added commands, while omitting the -tags flag will produce a standard version.
Given a package containing the following local variable and functions:
var bucket *gocb.Bucket
func Init(b *gocb.Bucket) {
bucket = b
}
func DoSomething() {
// do something with 'bucket'
}
Is it acceptable to call the Init function, passing in an instance of bucket, before calling DoSomething, which is dependent on the bucket variable?
Or, should DoSomething instead explicitly accept a bucket parameter, as follows:
func DoSomething(bucket *gocb.Bucket) {
// do something with 'bucket'
}
I would prefer to instantiate a single instance of bucket at a package-level, and use it throughout the application life-cycle, as opposed to managing at a function-level. Is this acceptable from design, performance, etc., perspectives, or is there a preferred means of achieving this? Bearing in mind that bucket need only be instantiated once.
DoSomething will be called from a HTTP context; I would prefer that the HTTP handlers not have visibility on the bucket parameter, and instead instantiate bucket on application start-up.
In Go, if your package depends on something external you import said thing. So, unless it's impossible for some reason, you should import the package that instantiates bucket and take it from there, either directly assigning it or in your package's init function.
import "my/other/pkg"
var bucket = pkg.InitBucket()
However, if it's impossible to determine what package will provision bucket, then your way is the way to Go. As an example, consider database/sql where SQL drivers have to be registered before they can be used.
In general, IoC does not apply to Go packages if that's what you had in mind.
Suppose that I have a type type T intand I want to define a logic to operate on this type.
What abstraction should I use and When ?
Defining a method on that type:
func (T t) someLogic() {
// ...
}
Defining a function:
func somelogic(T t) {
// ...
}
Some situations where you tend to use methods:
Mutating the receiver: Things that modify fields of the objects are often methods. It's less surprising to your users that x.Foo will modify X than that Foo(x) will.
Side effects through the receiver: Things are often methods on a type if they have side effects on/through the object in subtler ways, like writing to a network connection that's part of the struct, or writing via pointers or slices or so on in the struct.
Accessing private fields: In theory, anything within the same package can see unexported fields of an object, but more commonly, just the object's constructor and methods do. Having other things look at unexported fields is sort of like having C++ friends.
Necessary to satisfy an interface: Only methods can be part of interfaces, so you may need to make something a method to just satisfy an interface. For example, Peter Bourgon's Go intro defines type openWeatherMap as an empty struct with a method, rather than a function, just to satisfy the same weatherProvider interface as other implementations that aren't empty structs.
Test stubbing: As a special case of the above, sometimes interfaces help stub out objects for testing, so your stub implementations might have to be methods even if they have no state.
Some where you tend to use functions:
Constructors: func NewFoo(...) (*Foo) is a function, not a method. Go has no notion of a constructor, so that's how it has to be.
Running on interfaces or basic types: You can't add methods on interfaces or basic types (unless you use type to make them a new type). So, strings.Split and reflect.DeepEqual must be functions. Also, io.Copy has to be a function because it can't just define a method on Reader or Writer. Note that these don't declare a new type (e.g., strings.MyString) to get around the inability to do methods on basic types.
Moving functionality out of oversized types or packages: Sometimes a single type (think User or Page in some Web apps) accumulates a lot of functionality, and that hurts readability or organization or even causes structural problems (like if it becomes harder to avoid cyclic imports). Making a non-method out of a method that isn't mutating the receiver, accessing unexported fields, etc. might be a refactoring step towards moving its code "up" to a higher layer of the app or "over" to another type/package, or the standalone function is just the most natural long-term place for it. (Hat tip Steve Francia for including an example of this from hugo in a talk about his Go mistakes.)
Convenience "just use the defaults" functions: If your users might want a quick way to use "default" object values without explicitly creating an object, you can expose functions that do that, often with the same name as an object method. For instance, http.ListenAndServe() is a package-level function that makes a trivial http.Server and calls ListenAndServe on it.
Functions for passing behavior around: Sometimes you don't need to define a type and interface just to pass functionality around and a bare function is sufficient, as in http.HandleFunc() or template.Funcs() or for registering go vet checks and so on. Don't force it.
Functions if object-orientation would be forced: Say your main() or init() are cleaner if they call out to some helpers, or you have private functions that don't look at any object fields and never will. Again, don't feel like you have to force OO (à la type Application struct{...}) if, in your situation, you don't gain anything by it.
When in doubt, if something is part of your exported API and there's a natural choice of what type to attach it to, make it a method. However, don't warp your design (pulling concerns into your type or package that could be separate) just so something can be a method. Writers don't WriteJSON; it'd be hard to implement one if they did. Instead you have JSON functionality added to Writers via a function elsewhere, json.NewEncoder(w io.Writer).
If you're still unsure, first write so that the documentation reads clearly, then so that code reads naturally (o.Verb() or o.Attrib()), then go with what feels right without sweating over it too much, because often you can rearrange it later.
Use the method if you are manipulating internal secrets of your object
(T *t) func someLogic() {
t.mu.Lock()
...
}
Use the function if you are using the public interface of the object
func somelogic(T *t) {
t.DoThis()
t.DoThat()
}
if you want to change T object, use
func (t *T) someLogic() {
// ...
}
if you donn't change T object and would like a origined-object way , use
func (t T) someLogic() {
// ...
}
but remeber that this will generate a temporay object T to call someLogic
if your like the way c language does, use
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
or
func somelogic(t T) {
t.DoThis()
t.DoThat()
}
one more thing , the type is behide the var in golang.