Skip to content

Instantly share code, notes, and snippets.

@gonutz
Last active December 27, 2018 13:26
Show Gist options
  • Save gonutz/bcc89f0474fae455f4c05943f08d615d to your computer and use it in GitHub Desktop.
Save gonutz/bcc89f0474fae455f4c05943f08d615d to your computer and use it in GitHub Desktop.
Readability is Paramount

Readability is Paramount

I was pointed to a blog post about some new features in C++, the first language that I learnt when I started programming 15 years ago.

The author, a member of the C++ Standardization Committee, gives us an example of some basic algorithm to illustrate the use of a new C++ feature that he worked on. The task is rather simple: find triplets of integers a, b and c where a²+b²=c². Here are some examples:

3 4 5
6 8 10
5 12 13

This can be done in a simple way:

  • Step through all pairs of a and b where a < b, this can be done in a nested for-loop.
  • For each of these pairs go through all numbers c where is less or equal to a²+b² and see if a²+b²=c² holds true. No need to even compute a square root or anything like that.

Haskell version: 6 lines, 130 characters

main = print (take 10 triples)
 
triples = [(x, y, z) | z <- [1..]
                     , x <- [1..z]
                     , y <- [x..z]
                     , x^2 + y^2 == z^2]

Go version: 30 lines, 350 characters

package main

import (
	"fmt"
)

func main() {
	var a, b, c int
	for i := 0; i < 10; i++ {
		a, b, c = nextTriple(a, b, c)
		fmt.Println(a, b, c)
	}
}

func nextTriple(a, b, c int) (int, int, int) {
	for {
		a++
		if a >= b {
			b++
			a = 1
		}
		want := a*a + b*b
		c = a + 1
		for c*c < want {
			c++
		}
		if c*c == want {
			return a, b, c
		}
	}
}

C++ version: 50 lines, 1200 characters

#include <iostream>
#include <optional>
#include <ranges>

using namespace std;

template<Semiregular T>
struct maybe_view : view_interface<maybe_view<T>> {
	maybe_view() = default;
	maybe_view(T t) : data_(std::move(t)) {}
	T const *begin() const noexcept {
		return data_ ? &*data_ : nullptr;
	}
	T const *end() const noexcept {
		return data_ ? &*data_ + 1 : nullptr;
	}
private:
	optional<T> data_{};
};

inline constexpr auto for_each =
	[]<Range R, Iterator I = iterator_t<R>,
			IndirectUnaryInvocable<I> Fun>(R&& r, Fun fun)
			requires Range<indirect_result_t<Fun, I>> {
		return std::forward<R>(r)
			| view::transform(std::move(fun))
			| view::join;
	};

inline constexpr auto yield_if =
	[]<Semiregular T>(bool b, T x) {
		return b ? maybe_view{std::move(x)} : maybe_view<T>{};
	};

int main() {
	using view::iota;
	auto triples =
		for_each(iota(1), [](int z) {
			return for_each(iota(1, z+1), [=](int x) {
				return for_each(iota(x, z+1), [=](int y) {
					return yield_if(x*x + y*y == z*z, make_tuple(x, y, z));
				});
			});
		});
	for(auto triple : triples | view::take(10)) {
		cout << '('
			<< get<0>(triple) << ','
			<< get<1>(triple) << ','
			<< get<2>(triple) << ')' << '\n';
	}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment