Hacker News new | ask | show | jobs
by AnIdiotOnTheNet 3143 days ago
Yes, it is minor. Go has interfaces, so you just write a Comparer interface and sorter that takes two Comparers and then anything implementing Comparer is sortable.

*Note: author has written basically nothing in Go and only has a passing familiarity.

2 comments

So you define the Comparer interface with a Compare method. What does it look like?

If I have a struct X, then I might write it as:

    interface Comparer {
        Compare(other X)
    }
But wait, now I have to define a new interface for every type since "Compare" takes the type X in its signature so it doesn't work for type Y... If only I could define an interface that was for an unknown type T and then Compare was for that.

But that's exactly what generics are.

You know how Java has .equals? Go doesn't have an equivalent concept. Test code is neigh unreadable because there is no generic way to compare two structs of the same type. This is a similar problem.

I am admittedly thinking of an interface from how they work in Java, so I may be making incorrect assumptions about how they work in Go, but wouldn't I have to do that anyway? In what sense can the compiler work out how I want to compare my types? If I hand it some vec3s, for instance, does it know I want them sorted by x value, or by length?

By defining an interface that assures the compiler each type has a compare(x) method, I can write a generic sort function that takes any two comparable objects and sorts them based on whatever the class of those objects decided was the ordering criteria.

If your `Comparer` is an element type (as opposed to Go's `sort.Interface` abstraction over collections), this is going to be horribly unperformant. Suppose your `Foo` type implements `Comparer`, and you have a large `[]Foo`. Then you'll first have to iterate over each element in `[]Foo` and add it to your `[]Comparer`, probably with an allocation per element. Then each invocation of `foo.Compare()` is going to be indirect as well (in other words, an interface lookup and a function call, i.e. no inlining). Mind you, this is still faster than many languages, but it's not the kind of performance people expect from Go.
From this description, I'm getting the impression that Go's interfaces are not as much like Java interfaces as I had assumed.

Never the less, I find that generics usually are just an over-engineered solution to any given problem.

The primary differences (I think) are that everything in Java is already a pointer, so there isn't an extra alloc to make an interface. The same is true in Go if your comparables are all pointers. Probably the more significant difference is that Java has a JIT compiler, which may be able to inline all of those calls to Compare(). This is largely why Go's `sort` package abstracts over the collection, not over the element.
I don't see any reason why the interface lookup couldn't be done at compile time in this instance.
I don't think there is a technical reason. It's probably not something they'll do for a while because it probably requires some significant reorganization of the compiler and making a passably fast implementation is probably quite hard (the Go community places a premium on fast compiler times, rightly or wrongly). Also they seem to value predictable optimizations. Not sure how keen they would be to add an optimization that works until a seemingly inoccuous code change prevents the compiler from guaranteeing that all elements in the slice have the same concrete type, making performance (probably) significantly worse.

Again, I don't necessarily agree with the Go team; I'm just guessing the are some of the concerns they're weighing.

Ah I misunderstood the previous comment. Sure, if you have a list of pointers to values that satisfy a given interface, dispatching at compile time would not be trivial.