Is there any profits of using Methods rather than Functions? - function

I'm developing "Matrix" struct and related methods for the purpose of practicing Go.
I made a lot of methods but I realized that all these methods can be changed into functions
I'm used to C++ and in C++, if I make a function whose parameter is a type of class, the function cannot use the class' private variable(information hiding)
However, when I built a similar code using "Go", a function can access a struct's variable.
So I don't get what is different between methods and functions in Go.
Are there any profits using methods rather than functions or vice versa?
First one is my original "Matrix" code(not all of it)
It used a method "Tr".
It doesn't have problems.
package main
import "fmt"
//definition of "Array"
type Array struct{
component [][]float32
row int
col int
}
//constructor of Array, "Ones"; making an array setting all component as one
func Ones(m int, n int) Array{
var a Array
a.component = make([][]float32, m)
a.row=m
a.col=n
for i:=0; i<m; i++{
a.component[i] = make([]float32, n)
for j:=0; j<n; j++{
a.component[i][j]=1
}
}
return a
}
//Tr function; find trace of an Array
func (a Array) Tr() float32{
var sum float32 = 0
for i:=0; i<a.row; i++{
sum += a.component[i][i]
}
return sum
}
func main(){
a := Ones(3,3)
fmt.Println(a.Tr())
}
The second one is another similar code. (Everything is same but "Tr" part)
It used only functions.
It also doesn't have problems.
package main
import "fmt"
//definition of "Array"
type Array struct{
component [][]float32
row int
col int
}
//constructor of Array, "Ones"; making an array setting all component as one
func Ones(m int, n int) Array{
var a Array
a.component = make([][]float32, m)
a.row=m
a.col=n
for i:=0; i<m; i++{
a.component[i] = make([]float32, n)
for j:=0; j<n; j++{
a.component[i][j]=1
}
}
return a
}
//Tr function; find trace of an Array
func Tr(a Array) float32{
var sum float32 = 0
for i:=0; i<a.row; i++{
sum += a.component[i][i]
}
return sum
}
func main(){
a := Ones(3,3)
fmt.Println(Tr(a))
}

If you just want to call the function or method, it doesn't matter, you may create a function with a signature where the receiver is a normal, regular parameter. There won't be any performance penalty (there could be if methods could be virtual, but in Go there are no virtual methods).
One advantage might be the "visual appeal". Calling a method makes it obvious it belongs to the receiver. I also find chained code easier to understand if methods are used.
Compare this solution without methods:
type Circle struct{}
type Point struct{}
func Center(Circle) Point { return Point{} }
func Abs(Point) float64 { return 0 }
func main() {
var c Circle
fmt.Println(Abs(Center(c)))
}
Abs(Center(c)) isn't that intuitive. But if you add methods instead of using functions:
func (Circle) Center() Point { return Point{} }
func (Point) Abs() float64 { return 0 }
func main() {
var c Circle
fmt.Println(c.Center().Abs())
}
c.Center().Abs() is easier to understand.
Methods are a must if you want to implement interfaces. If an interface contains some methods, only types that have those methods can implement it. See related: Why are interfaces needed in Golang? It should also be noted that you may only create methods defined in the same package, so if you want to "arm" a type from a different package, you can't "use" methods.
One thing that I would call "profit" for using methods: you can't call functions by name, but you can access and call methods by name. For details, see Call functions with special prefix/suffix.

Related

Can I create an alias for a generic function? I get error "Cannot use generic function without instantiation"

I can define a generic function:
package hello
func IsZero[T int64|float64](value T) bool {
return value == 0
}
Then if I try to alias that function in another package, it fails:
package world
import "hello"
var IsZero = hello.IsZero
The above doesn't compile with:
cannot use generic function hello.IsZero without instantiation
Instead this works:
var IsZero = hello.IsZero[int64]
Is it possible to do this, using some other syntax?
That's not an alias. And you already have your answer, actually. But if you want a formal reference, from the language specs, Instantiations:
A generic function that is is not called requires a type argument list for instantiation
So when you attempt to initialize a variable of function type, the function hello.IsZero is not called, and therefore requires instantiation with specific type parameters:
// not called, instantiated with int64
var IsZero = hello.IsZero[int64]
At this point the variable (let's give it a different name for clarity) zeroFunc has a concrete function type:
var zeroFunc = IsZero[int64]
fmt.Printf("type: %T\n", zeroFunc)
Prints:
type: func(int64) bool
This might or might not be what you want, as this effectively monomorphises the function.
If you just want to have a local symbol, with the same implementation (or a tweaked version thereof), declaring a "wrapper" function works. Just remember that the type parameters of your wrapper can only be as strict or stricter than the wrapped one's
E.g. Given
IsZero[T int64 | float64](v T)
your wrapper can not be
WrapIsZeroPermissive[T int64 | float64 | complex128](v T) bool {
return IsZero(v) // does not compile, T's type set is a superset
}
but can be
WrapIsZeroStricter[T int64](v T) bool {
return IsZero(v) // ok, T's type set is a subset
}
If the function is small, like in the question, it's probably easier to just vendor it:
package vendor
func thisIsJustCopy[T int64|float64](value T) bool {
return value == 0
}
but if the function is big, you can do it like this:
package world
import "hello"
func IsZero[T int64|float64](value T) bool {
return hello.IsZero(value)
}
I try to alias that function in another package
Aliases work for types only. Your code just tries to declare a variable.
Is it possible to do this, using some other syntax?
No.

what is the specific reason to differentiate functions and methods in Go?

I have read about what is the difference between functions and methods. I have gone through some previous answers on stack-overflow. However, I could not understand why exactly they are kept different. According to my understanding: whatever can be done using methods can also be done using functions in Go. I know methods are also functions. To further clarify my questions and I have added an example:
package main
import (
"fmt"
)
type Point struct {
a, b int
}
func (p *Point) sumM() int {
return p.a + p.b
}
func sumF(p *Point) int {
return p.a + p.b
}
func (p *Point) mulM(n int) int {
return (p.a + p.b) * n
}
func mulF(p *Point, n int) int {
return (p.a + p.b) * n
}
func main() {
p := Point{2, 3}
fmt.Println("sumM is: ", p.sumM())
fmt.Println("sumF is: ", sumF(&p))
fmt.Println("mulM is: ", p.mulM(2))
fmt.Println("mulF is: ", mulF(&p, 2))
}
where M and F represent method and function respectively.
I want to know if I am missing something; if there is some authentic reasoning behind these different implementations. e.g. pros and cons for each.
Some tips from Golang Methods:
A method is just a function with a receiver argument.
Methods help you write object-oriented style code in Go.
Method calls are much easier to read and understand than function calls.
Methods help you avoid naming conflicts. Since a method is tied to a particular receiver, you can have the same method names on different receiver types.
The thumb of the rule is that do not define methods if:
Dependency on the state is not required
You can perform this function on any type that implements a specific interface which means you don’t need to restrict this function to belong to a specific type.

Confused on how Swift nested functions work

For example, take this code:
func jediTrainer () -> ((String, Int) -> String) {
func train(name: String, times: Int) -> (String) {
return "\(name) has been trained in the Force \(times) times"
}
return train
}
let train = jediTrainer()
train("Obi Wan", 3)
I am completely confused as to what is going on in this function. jediTrainer takes no parameters, and returns a function called train. When we say "train = jediTrainer()" are we now storing the FUNCTION "train" into the variable called "train", as it returned that function that's now stored in the variable? Can you please break down what exactly is going on here into steps? Thank you so much!
In Swift functions are first class objects that means functions can be referenced by variables, passed as parameters and returned from other functions.
In your case jediTrainer() returns a function which is a nested function in itself. So let train is referring to train() function in jediTrainer. Now you could call that train function using train variable.
For more information on this please refer to Function Types and related topics here.
You also have an opinion of definining functions inside a bodies of other functions.These are called nested function .
By default Nested functions is hidden from outside world .It can still be called and used by its enclosing function .An enclosing function can also return one of nested functions ,thus allowing the nested function to be used in another scope .
func aFunc (flag:Book)->(Int)->Int
{
func plus ( input:Int )->Int
{
return input + 1
}
func minus ( input:Int )->Int
{
return input - 1
}
if (flag)
{
return plus
}
else
{
return minus
}
}

Empty interface{} in function type

An object of any type can be assigned to an empty interface. For example, we have the following function
func Println(i interface{} ) {
fmt.Println(i)
}
We can call it by
Println(3)
Println(1.5)
Println("Hello")
But I can't achieve the same thing for function type
func Map(fn func( interface{} )) {
......
}
I cannot call this with
Map( func( i int) {......} )
because the type func(int) is different from the type func( interface{} ).
But when I define func( interface{} ), I really mean any type of the input parameters. How can I achieve this in Go?
It fails because the signatures don't match.
When you call Println(3), the function isn't taking an integer as its first argument. Rather the integer gets packed inside an interface{} variable (an automatic conversion, since integers conform to the interface), and that variable is passed to the function. This conversion happens on the calling side, so the process of calling the function is different to calling a function matching func(i int).
If you want to write a function that accepts arbitrary unary functions, you will need to declare it to take an interface{} variable as its argument and then check the value using the reflect package. The reflect package can also help you call arbitrary functions where you don't know the signature at compile time.
For example:
func Map(f, v interface{}) interface{} {
fn := reflect.ValueOf(f)
fnType := fn.Type()
if fnType.Kind() != reflect.Func || fnType.NumIn() != 1 || fnType.NumOut() != 1 {
panic("Expected a unary function returning a single value")
}
res := fn.Call([]reflect.Value{reflect.ValueOf(v)})
return res[0].Interface()
}
This will call the given function f with the argument v and return the result. Provided v is assignable to f's first argument the call will succeed without a panic. You can experiment with this example here: http://play.golang.org/p/kkBu56JYb8
I do realise its an old discussion, but came across the post and wanted to play around with the concept of having arbitrary function func (interface{}) within another function, instead of interface{}.
I could write a simple implementation, by providing an inline implementation of a function which would accept interface{}. And we can call this function from within another function
varForGenFunc := func(in interface{}) int {
fmt.Println("type of this object: ",reflect.TypeOf(in))
return 1}
TakeGenericFunc(varForGenFunc, variableForGen)
Going by this, we can write any implementations of func(interface{}) and pass it as parameter to TakeGenericFunc
You can play around with it here:
https://play.golang.org/p/f5UUhyhEx7u

What are the problems that are mitigated by not allowing nested function declarations in Go?

Lambdas work as expected:
func main() {
inc := func(x int) int { return x+1; }
}
However, the following declaration inside a declaration is not allowed:
func main() {
func inc(x int) int { return x+1; }
}
For what reason are nested functions not allowed?
I think there are 3 reasons why this obvious feature isn't allowed
It would complicate the compiler slightly. At the moment the compiler knows all functions are at the top level.
It would make a new class of programmer error - you could refactor something and accidentally nest some functions.
Having a different syntax for functions and closures is a good thing. Making a closure is potentially more expensive than making a function so you should know you are doing it.
Those are just my opinions though - I haven't seen an official pronouncement from the language designers.
Frequently Asked Questions (FAQ)
Why does Go not have feature X?
Every language contains novel features and omits someone's favorite
feature. Go was designed with an eye on felicity of programming, speed
of compilation, orthogonality of concepts, and the need to support
features such as concurrency and garbage collection. Your favorite
feature may be missing because it doesn't fit, because it affects
compilation speed or clarity of design, or because it would make the
fundamental system model too difficult.
If it bothers you that Go is missing feature X, please forgive us and
investigate the features that Go does have. You might find that they
compensate in interesting ways for the lack of X.
What would justify the complexity and expense of adding nested functions? What do yau want to do that you can't do without nested functions? Et cetera.
Here's a way to implement nested functions and functions within nested functions
package main
import "fmt"
func main() {
nested := func() {
fmt.Println("I am nested")
deeplyNested := func() {
fmt.Println("I am deeply nested")
}
deeplyNested()
}
nested()
}
Nested functions are allowed in Go. You just need to assign them to local variables within the outer function, and call them using those variables.
Example:
func outerFunction(iterations int, s1, s2 string) int {
someState := 0
innerFunction := func(param string) int {
// Could have another nested function here!
totalLength := 0
// Note that the iterations parameter is available
// in the inner function (closure)
for i := 0; i < iterations; i++) {
totalLength += len(param)
}
return totalLength
}
// Now we can call innerFunction() freely
someState = innerFunction(s1)
someState += innerFunction(s2)
return someState
}
myVar := outerFunction(100, "blah", "meh")
Inner functions are often handy for local goroutines:
func outerFunction(...) {
innerFunction := func(...) {
...
}
go innerFunction(...)
}
You just have to call it immediately by adding () to the end.
func main() {
func inc(x int) int { return x+1; }()
}
Edit: cannot have function name...so it's just a lambda func getting called right away:
func main() {
func(x int) int { return x+1; }()
}