-1

In GO, rule is, methods can be defined only on named type and pointer to named type.


In C, below code, operations are defined on type(say List),

typedef struct List List; //list.h
typedef struct {

         bool(*canHandle)(ImplType);
        List*(*createList)();
        ....  
        const void*(*listGetItem)(List*, const int);
         .....
         void(*swap)(List*, int, int);
}ListHandler;


typedef struct{

  ListHandler *handler;
}ListRtti;


typedef struct List{

  ListRtti rtti; // operation on type List
  const void **array;
  /* For housekeeping - Array enhancement/shrink */
  int lastItemPosition;
  int size;
}List;

In Java, operations are defined on type(say DList),

public class DList {
  private DListNode sentinel;
  private int size;
  public void addItem(Object item){
    ...
  }
  ....
}

But in GO, code below, operations are allowed on named type and pointer to named type.

package main

type Cat struct {
}

func (c Cat) foo() {
   // do stuff_
}

func (c *Cat) foo() {
  // do stuff_
}

func main() {

}

Question:

1)

What is the idea of defining a method on a pointer to named type?

2)

How can a programmer know before hand, if foo() has to work as pass by value/reference? Why GO compiler restrict defining method on both named typed and pointer to named type?

  • 2
    In Java you can only define methods that take a reference (roughly equivalent to a pointer), not the value itself, because classes are reference types. So Java supports the equivalent of func(c *Cat) but not func(c Cat). – CodesInChaos Jan 30 '17 at 16:40
  • @CodesInChaos Yes, it is like opaque pointers in C. But, using references is by declaring a reference variable for a class from user code. But when we define methods in a class, we define methods for class X. Same holds good for C – overexchange Jan 30 '17 at 16:53
3

Most OOP languages pass the current object (“invocant”) as a pointer or equivalent kind of reference. In Java and C++ the invocant is called this, in Python it's an explicit argument called self. In Java and Python this is zero-cost because their objects already are reference types. In C++, using a pointer (or reference) is necessary because that language has value semantics. If this were a value instead of a reference, the class defining the method could not be subclassed.

Like C++, Go has value types but it doesn't really have inheritance and can't override methods, so using a pointer is not necessary.

However, using a pointer is useful when:

  • you want to modify the invocant, e.g. assign to a field of a struct.

  • the type is large so a copy would be more expensive than using a pointer.

Conversely, using a non-pointer type for the invocant is useful if that type is very small and if you don't want to modify that object. In general, you'd use a non-pointer invocant for “primitive” types since they are fairly small. This should be treated as a micro-optimization; in most cases you do want a pointer for user-defined types.

  • So as per GO syntax(above), Cat c is non-reference type unlike java – overexchange Jan 30 '17 at 17:17
  • @overexchange exactly. As in C, structs are value types. You can see the difference by adding a name field to Cat, and creating a method func (c Cat) rename(newName string) { c.name = newName } – this method won't do anything, unless you change it to accept a *Cat instead. – amon Jan 30 '17 at 17:20
  • 1) In GO, as implicit(this, self), not getting passed, I would need explicit mentioning of receiver type(c *Cat) in the operation(reName) unlike Java and C++, which explains usage of pointer to named type.Understood. My first question is answered. 2) Any idea on second question. why do I get method:redeclared error? Why GO allow either but not both? – overexchange Jan 30 '17 at 17:39
  • @overexchange Because Go let's you invoke pointer-methods on values, i.e. object.method() may be a shortcut for (&object).method(). To avoid ambiguity between those cases, you can't declare the same method for a pointer and non-pointer type. – amon Jan 30 '17 at 18:13
  • 1) I see the call resolutions, but, implicitly func foo(c *Cat){..} is not same as func (c Cat) foo(c Cat){..}. So, there is no function overloading. 2) Programmer should take a call, whether to define pointer method or non-pointer method. Obviously, pointer method is better efficient for small/big objects. – overexchange Jan 30 '17 at 18:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.