DEV Community

Cover image for Go's method is curried funtion
Yasuhiro Matsumoto
Yasuhiro Matsumoto

Posted on

Go's method is curried funtion

#go

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();
}
Enter fullscreen mode Exit fullscreen mode

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()
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

Top comments (4)

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 • • Edited

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
 
der_gopher 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 •

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)