Theory

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.