sort.Search — and a question for lesson 13
You wrote a binary search by hand. The standard library already has one:
sort.Search(len(items), func(i int) bool { return items[i].Title >= target })
One line instead of ten, with every boundary case already thought through.
But it takes a function. Every comparison is a call through a func value.
That sounds more expensive.
$ algo std -n 127
comparisons ns/op
hand-rolled LowerBound 7 18
sort.Search 7 15
$ algo std -n 2254
hand-rolled LowerBound 12 38
sort.Search 12 37
$ algo std -n 100000
hand-rolled LowerBound 16 53
sort.Search 16 55
The comparison counts are identical — it is the same algorithm. And on the
clock, sort.Search is faster in three cases out of four, and never meaningfully
behind.
The function cost nothing.
The reason is the compiler. The closure is known at compile time, so Go inlines it straight into the loop. After optimisation there is no call left: what remains is the same loop you wrote by hand, just written by somebody else.
transit measured this more sharply still: 7.9 ns hand-rolled against 4.9 ns
for sort.Search. Our margin is smaller, but it points the same way.
So why write it by hand?
To understand the invariant. Step 3 showed ten places a hand-rolled search breaks — and you will not really know those places until you have fixed them yourself.
But in working code, use sort.Search. It is faster, shorter and already
tested.
A question we are not answering yet
In lesson 3 you built your own doubly-linked list and compared it with
container/list. The numbers matched to within one hop.
Here the standard library won.
Does that mean the standard library is always at least as good?
It sounds reasonable. But in lesson 13 you will build a heap by hand and compare
it with container/heap — and the answer will be the opposite, clearly and
measurably.
Do not settle on a conclusion yet. There is a rule that reconciles both cases, but it is not about the standard library. It is about what the compiler can see through. In this lesson it could see everything. Next time it will not.