loading...
Cover image for Go's method is curried funtion

Go's method is curried funtion

#go
mattn profile image Yasuhiro Matsumoto ・1 min read

Go's method is not same in other languages. In C++, this should not be null.

class Foo {
  public:
    void doSomething() {}
};

int
main() {
  Foo *foo = nullptr;
  foo->doSomething();
}

Go's method does not require that the receiver is instanciated.

package main

import (
    "fmt"
)

type Foo struct {
}

func (f *Foo) doSomething() {
    fmt.Println(f)
}

func main() {
    var foo *Foo
    foo.doSomething()
}

And the method hold receiver value. This is called Method Values.

package main

import (
    "fmt"
)

type Foo struct {
    Value string
}

func (f *Foo) WhatsUp() {
    fmt.Println(f.Value)
}

func doSomething(f func()) {
    f()
}

func main() {
    foo := &Foo{Value: "Hello, World"}
    doSomething(foo.WhatsUp)
}

The WhatsUp is evaulated with the receiver.

package main

import (
    "fmt"
)

type Foo int

func (f Foo) doSomething() {
    fmt.Println(f)
}

func main() {
    Foo.doSomething(123)
}

So this code is valid. Foo.doSomething is the function object. It can be called with let the function object to a variable. The function type should take an first argument which is type of the receiver.

package main

import (
    "fmt"
)

type Foo int

func (f Foo) doSomething() {
    fmt.Println(f)
}

func main() {
    var fn func(Foo)

    fn = Foo.doSomething
    fn(123)
}

This idiom is useful to call runtime.SetFinalizer to Close something resource must be closed.

package main

import (
    "log"
    "os"
    "runtime"
    "myresource"
)

func main() {
    f := myresource.OpenSomethingMustBeClosed()
    if err != nil {
        log.Fatal(err)
    }
    runtime.SetFinalizer(f, (*myresource.Writer).Close)
}

Discussion

pic
Editor guide
Collapse
nekketsuuu profile image
Takuma Ishikawa

Interesting! However, what do you mean by the words "curried function" in the title? I think Foo.doSomething is not curried. For example, if doSomething takes one argument, Foo.doSomething(123) causes an error.

func (f Foo) doSomething(b bool) {
    fmt.Println(f, b)
}

func main() {
    Foo.doSomething(123)  // error: not enough arguments
}

Maybe you want to say that Go can pass a receiver to a method value as an argument?

Collapse
mattn profile image
Yasuhiro Matsumoto Author

Yes, in strictly, as you think, this is not currying. The currrying is a transform taking one less argument.

package main

import (
    "fmt"
)

func add(n int) func(int) int {
    return func(v int) int {
        return n + v
    }
}

func main() {
    add10 := add(10)
    fmt.Println(add10(5))
}

Just metaphor :)

If this function object for currying, you can try this.

package main

import (
    "fmt"
)

type number int

func (f number) add(b number) number {
    return f + b
}

func main() {
    fmt.Println(number(3).add(4))
    fmt.Println(number.add(3, 4))
}
Collapse
plutov profile image
Alex Pliutau

I never saw Go people use Foo.doSomething(123) ... Can you point to some open source projects doing this?

Collapse
mattn profile image
Yasuhiro Matsumoto Author

Yes, most of cases, the function will not be called directly. As I wrote in above, it is often used as function object. See os/exec.go in Go repository.

runtime.SetFinalizer(p, (*Process).Release)