Friday 17 April 2020

Go language: When shall a method be a function?

I came across a method which was basically a helper method doing some data filtering. Its input data are struct's data members and the output is some collection used by another method. It didn't look right to me that this method does not use or modify receiver's state but is still bound to it. As it only takes some data from it and spits out a result, with no side effects, I decided to turn it into a function with parameters.

When deciding if Go method should actually be a function ask yourself: does it change or depends on the state of its receiver? If it doesn't, it should be a function. One immediate benefit is that it's easier to set up its unit tests.

Reddit user krocos summarized the rules in post When we should use a method receiver instead of a function argument and vice versa? : golang:

There are some rules already to use a receiver: 
  • when you implement an interface 
  • when the function mutate some state (encapsulated in the receiver) 
  • when your function querying some state to work (i.e.: might calling the same method with the same arguments produce a different result) 
  • when you want to chain method calls 
In all other cases it's necessary to use an argument.

From my old C++ days I remember the advice from Scott Meyers (from his Effective C++ book and also this article How Non-Member Functions Improve Encapsulation | Dr Dobb's):

  • classes should contain no more member functions than are absolutely necessary
  • non-friend non-member functions should be preferred to member functions

This can generally be applied to Go language as well. Ideally, interface members should be methods, they are struct's public API and should be set in stone. All other routines should be made functions if possible.

Further reading:

Go Best Practices: Should you use a method or a function?
When we should use a method receiver instead of a function argument and vice versa? : golang
When to use methods? : golang
How Non-Member Functions Improve Encapsulation | Dr Dobb's
Non-Member Functions in OOP - CodeProject

No comments: