2026/08/10
02:16 Go is a terrible CP language
Last time I did competitive programming was a while ago, I used to do that in C++. I have an important call soon which will probably include coding, and I'm getting prepared. Usually I would do that in Lisp, because I feel most proficient at. Sadly Lisp is not very readable by people who are not experienced with it, that's why I have to pick a language that its syntax is more common (c-family like). For me that's Go (since I have almost forgot how to deal with most of C++ quirks). I learnt (perhaps too late) that Go is not a good pick for CP.
This also comes with a realization that Go's philosophy of Clear better than clever comes with many tradeoffs when writing code. Some examples from top of my mind;
Heap in C++:
#include
priority_queue pq;
pq.push(5);
pq.push(2);
pq.push(10);
pq.top(); // 10
pq.pop(); The equivalent in Go requires implementing heap.Interface yourself:
Heap in Go:
import "container/heap"
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x any) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[:n-1]
return x
}
func main() {
h := &IntHeap{}
heap.Init(h)
heap.Push(h, 5)
heap.Push(h, 2)
heap.Push(h, 10)
x := (*h)[0] // 2
heap.Pop(h)
} And if you want a max-heap, you also have to change Less:
func (h IntHeap) Less(i, j int) bool {
return h[i] > h[j]
}Compare that with:
priority_queue pq;Sets in C++
C++ has a proper ordered set:
#include
set s;
s.insert(5);
s.insert(10);
s.insert(3);
s.erase(5);
if (s.count(10)) {
// exists
} A C++ set is also ordered, so you get operations such as lower_bound:
auto it = s.lower_bound(7);Go doesn't have a built-in set type.
The common solution is to use a map:
s := map[int]bool{}
s[5] = true
s[10] = true
s[3] = true
delete(s, 5)
if s[10] {
// exists
} You can also use map[int]struct{}, which is the more idiomatic representation when the value itself doesn't matter:
s := map[int]struct{}{}
s[5] = struct{}{}
s[10] = struct{}{}
delete(s, 5)
if _, ok := s[10]; ok {
// exists
} This works well for a hash set, but it is not equivalent to C++'s ordered set.
If you need the elements sorted in Go, you have to do it yourself:
keys := make([]int, 0, len(s))
for x := range s {
keys = append(keys, x)
}
sort.Ints(keys)Whereas in C++ the ordering is part of the data structure itself.
Multiset in C++
C++ also has multiset, which allows duplicate values while keeping them ordered:
multiset ms;
ms.insert(5);
ms.insert(5);
ms.insert(10);
ms.insert(3);
ms.erase(ms.find(5)); // erase one occurrence
if (ms.count(5)) {
// exists
}You can also get the number of occurrences directly:
ms.count(5);Lower bound / upper bound
C++:
vector v = {1, 3, 3, 5, 7, 10};
auto it = lower_bound(v.begin(), v.end(), 5);
int index = it - v.begin();Go:
v := []int{1, 3, 3, 5, 7, 10}
index := sort.Search(len(v), func(i int) bool {
return v[i] >= 5
})C++'s STL was designed around of generic algorithmic programming.
Go's "clear is better than clever" philosophy can sometimes result in writing more for relatively smaller algorithmic ideas.
Take for example:
"Put everything in a min-heap and repeatedly take the smallest element."In C++:
priority_queue, greater> pq;In go that has to go through some boilerplate first.