I am in the process of writing a binary search tree implementation and in order to minimise maintenance problems, I needed to use parametric polymorphism - so I could specify part of the algorithm concretely, where it is in common regardless of the data type in a subclass, and which parts were not in common.
The issue that I came across and I only just finally understood how to do this type of code in Go yesterday, so this is fresh and an issue that I want to raise regarding the Golang 2.0 specification.
Currently, this is how you do OOP in go:
type Objectname struct {
privateVariable typename
PublicVariable typename
}
type objectname interface {
privateFunction(parameterTuple) typenameTuple
PublicFunction(parameterTuple) typenameTuple
NonImplementedFunction(parameterTuple) typenameTuple
}
func (o *Objectname) privateFunction(parameterTuple) typenameTuple {
// ...Implementation
return typenameTuple
}
func (o *Objectname) PublicFunction(parameterTuple) typenameTuple {
// ...Implementation
return typenameTuple
}
func (o *Objectname) NonImplementedFunction(parameterTuple) typenameTuple {
// put nothing in here
return typenameTuple
}
Now, it's not excessively complicated, but it does lead to readability issues by not prescribing a metastructure for this. What I have composed here is essentially what you have to do, but you can see that the only things that tie everything together are repeating strings, the objectname, function signatures, the type binding declarations in the functions.
It is a purely 'syntactic sugar' issue, really, but an important one. If there was instead a sectioned structure for this, you could avoid scattering the connected elements of the type amongst non-typebound accessory functions and variables. A simple example of how this can happen is with a binary tree library - you need to have a cursor type for tracking walks and moving data into other functions and variables, but it's a second type and really should be kept together with the class that requires it. This is just a simple case, it would get worse the more necessary accessories tie together but are not big enough to be separated into distinct files (what purpose would a cursor library have without the implied context of the tree mapping system?).
I would like to see it become possible to rewrite the above code like this:
class Objectname {
struct {
privateVariable typename
PublicVariable typename
}
methods {
privateFunction(parameterTuple) typenameTuple
PublicFunction(parameterTuple) typenameTuple
}
interfaces {
NonImplementedFunction(parameterTuple) typenameTuple
}
// below specifies the binding reference name for functions
bind o {
func privateFunction(parameterTuple) typenameTuple {
// ...Implementation
return typenameTuple
}
func (o *Objectname) PublicFunction(parameterTuple) typenameTuple {
// ...Implementation
return typenameTuple
}
}
}
It is superficial, and could be implemented using a preprocessor, in fact (so it fills all the necessary non-implemented functions with dummies), but it would encourage more careful structuring of source files, and make it easier also to see when it makes more sense to split a source into two or more separate files.
Also note that go fmt could potentially help you by matching the bind section's ordering with the methods section.