1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
|
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/syntax.css">
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1">
<meta content="#ffffff" name="theme-color">
<meta name="HandheldFriendly" content="true">
<meta property="og:title" content="Gripes With Go">
<meta property="og:type" content="website">
<meta property="og:description" content="a static site {for, by, about} me ">
<meta property="og:url" content="https://peppe.rs">
<link rel="icon" type="image/x-icon" href="/favicon.png">
<title>Gripes With Go · peppe.rs</title>
<body>
<div class="posts">
<div class="post">
<a href="/" class="post-end-link">Home</a>
<span>/</span>
<a href="/posts" class="post-end-link">Posts</a>
<span>/</span>
<a class="post-end-link">Gripes With Go</a>
<a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/gripes_with_go.md
">View Raw</a>
<div class="separator"></div>
<div class="date">
01/08 — 2020
<div class="stats">
<span class="stats-number">
76.71
</span>
<span class="stats-unit">cm</span>
 
<span class="stats-number">
4.9
</span>
<span class="stats-unit">min</span>
</div>
</div>
<h1>
Gripes With Go
</h1>
<div class="post-text">
<p>You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.</p>
<ol type="1">
<li><a href="#lack-of-sum-types">Lack of sum types</a></li>
<li><a href="#type-assertions">Type assertions</a></li>
<li><a href="#date-and-time">Date and Time</a></li>
<li><a href="#statements-over-expressions">Statements over Expressions</a></li>
<li><a href="#erroring-out-on-unused-variables">Erroring out on unused variables</a></li>
<li><a href="#error-handling">Error handling</a></li>
</ol>
<h3 id="lack-of-sum-types">Lack of Sum types</h3>
<p>A “Sum” type is a data type that can hold one of many states at a given time, similar to how a boolean can hold a true or a false, not too different from an <code>enum</code> type in C. Go lacks <code>enum</code> types unfortunately, and you are forced to resort to crafting your own substitute.</p>
<p>A type to represent gender for example:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true"></a><span class="kw">type</span> Gender <span class="dt">int</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a><span class="kw">const</span> (</span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true"></a> Male Gender = <span class="ot">iota</span> <span class="co">// assigns Male to 0</span></span>
<span id="cb1-5"><a href="#cb1-5" aria-hidden="true"></a> Female <span class="co">// assigns Female to 1</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true"></a> Other <span class="co">// assigns Other to 2</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true"></a>)</span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true"></a>fmt.Println(<span class="st">"My gender is "</span>, Male)</span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true"></a><span class="co">// My gender is 0</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true"></a><span class="co">// Oops! We have to implement String() for Gender ...</span></span>
<span id="cb1-12"><a href="#cb1-12" aria-hidden="true"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true"></a><span class="kw">func</span> (g Gender) String() <span class="dt">string</span> {</span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true"></a> <span class="kw">switch</span> (g) {</span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true"></a> <span class="kw">case</span> <span class="dv">0</span>: <span class="kw">return</span> <span class="st">"Male"</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true"></a> <span class="kw">case</span> <span class="dv">1</span>: <span class="kw">return</span> <span class="st">"Female"</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true"></a> <span class="kw">default</span>: <span class="kw">return</span> <span class="st">"Other"</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true"></a> }</span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true"></a>}</span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true"></a></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true"></a><span class="co">// You can accidentally do stupid stuff like:</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true"></a>gender := Male + <span class="dv">1</span></span></code></pre></div>
<p>The Haskell equivalent of the same:</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode haskell"><code class="sourceCode haskell"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true"></a><span class="kw">data</span> <span class="dt">Gender</span> <span class="ot">=</span> <span class="dt">Male</span></span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a> <span class="op">|</span> <span class="dt">Female</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a> <span class="op">|</span> <span class="dt">Other</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true"></a><span class="fu">print</span> <span class="op">$</span> <span class="st">"My gender is "</span> <span class="op">++</span> (<span class="fu">show</span> <span class="dt">Male</span>)</span></code></pre></div>
<h3 id="type-assertions">Type Assertions</h3>
<p>A downcast with an optional error check? What could go wrong?</p>
<p>Type assertions in Go allow you to do:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true"></a><span class="kw">var</span> x <span class="kw">interface</span>{} = <span class="dv">7</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a>y, goodToGo := x.(<span class="dt">int</span>)</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a><span class="kw">if</span> goodToGo {</span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a> fmt.Println(y)</span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a>}</span></code></pre></div>
<p>The error check however is optional:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true"></a><span class="kw">var</span> x <span class="kw">interface</span>{} = <span class="dv">7</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true"></a><span class="kw">var</span> y := x.(<span class="dt">float64</span>)</span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>fmt.Println(y)</span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a><span class="co">// results in a runtime error:</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true"></a><span class="co">// panic: interface conversion: interface {} is int, not float64</span></span></code></pre></div>
<h3 id="date-and-time">Date and Time</h3>
<p>Anyone that has written Go previously, will probably already know what I am getting at here. For the uninitiated, parsing and formatting dates in Go requires a “layout”. This “layout” is based on magical reference date:</p>
<pre><code>Mon Jan 2 15:04:05 MST 2006</code></pre>
<p>Which is the date produced when you write the first seven natural numbers like so:</p>
<pre><code>01/02 03:04:05 '06 -0700</code></pre>
<p>Parsing a string in <code>YYYY-MM-DD</code> format would look something like:</p>
<div class="sourceCode" id="cb7"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true"></a><span class="kw">const</span> layout = <span class="st">"2006-01-02"</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true"></a>time.Parse(layout, <span class="st">"2020-08-01"</span>)</span></code></pre></div>
<p>This so-called “intuitive” method of formatting dates doesn’t allow you to print <code>0000 hrs</code> as <code>2400 hrs</code>, it doesn’t allow you to omit the leading zero in 24 hour formats. It is rife with inconveniences, if only there were a <a href="https://man7.org/linux/man-pages/man3/strftime.3.html">tried and tested</a> date formatting convention …</p>
<h3 id="statements-over-expressions">Statements over Expressions</h3>
<p>Statements have side effects, expressions return values. More often than not, expressions are easier to understand at a glance: evaluate the LHS and assign the same to the RHS.</p>
<p>Rust allows you to create local namespaces, and treats blocks (<code>{}</code>) as expressions:</p>
<div class="sourceCode" id="cb8"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true"></a><span class="kw">let</span> twenty_seven <span class="op">=</span> <span class="op">{</span></span>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true"></a> <span class="kw">let</span> three <span class="op">=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span><span class="op">;</span></span>
<span id="cb8-3"><a href="#cb8-3" aria-hidden="true"></a> <span class="kw">let</span> nine <span class="op">=</span> three <span class="op">*</span> three<span class="op">;</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a> nine <span class="op">*</span> three</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a><span class="op">};</span></span></code></pre></div>
<p>The Go equivalent of the same:</p>
<div class="sourceCode" id="cb9"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true"></a>twenty_seven := <span class="ot">nil</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a>three := <span class="dv">1</span> + <span class="dv">2</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a>nine := three * three</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a>twenty_seven = nine * three</span></code></pre></div>
<h3 id="erroring-out-on-unused-variables">Erroring out on unused variables</h3>
<p>Want to quickly prototype something? Go says no! In all seriousness, a warning would suffice, I don’t want to have to go back and comment each unused import out, only to come back and uncomment them a few seconds later.</p>
<h3 id="error-handling">Error handling</h3>
<div class="sourceCode" id="cb10"><pre class="sourceCode go"><code class="sourceCode go"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true"></a><span class="kw">if</span> err != <span class="ot">nil</span> { ... }</span></code></pre></div>
<p>Need I say more? I will, for good measure:</p>
<ol type="1">
<li>Error handling is optional</li>
<li>Errors are propagated via a clunky <code>if</code> + <code>return</code> statement</li>
</ol>
<p>I prefer Haskell’s “Monadic” error handling, which is employed by Rust as well:</p>
<div class="sourceCode" id="cb11"><pre class="sourceCode rust"><code class="sourceCode rust"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true"></a><span class="co">// 1. error handling is compulsory</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a><span class="co">// 2. errors are propagated with the `?` operator</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true"></a><span class="kw">fn</span> foo() <span class="op">-></span> <span class="dt">Result</span><span class="op"><</span><span class="dt">String</span><span class="op">,</span> <span class="pp">io::</span><span class="bu">Error</span><span class="op">></span> <span class="op">{</span></span>
<span id="cb11-4"><a href="#cb11-4" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> f <span class="op">=</span> <span class="pp">File::</span>open(<span class="st">"foo.txt"</span>)<span class="op">?;</span> <span class="co">// return if error</span></span>
<span id="cb11-5"><a href="#cb11-5" aria-hidden="true"></a> <span class="kw">let</span> <span class="kw">mut</span> s <span class="op">=</span> <span class="dt">String</span><span class="pp">::</span>new()<span class="op">;</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true"></a> f<span class="op">.</span>read_to_string(<span class="op">&</span><span class="kw">mut</span> s)<span class="op">?;</span> <span class="co">// return if error</span></span>
<span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true"></a> <span class="cn">Ok</span>(s) <span class="co">// all good, return a string inside a `Result` context</span></span>
<span id="cb11-10"><a href="#cb11-10" aria-hidden="true"></a><span class="op">}</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true"></a></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true"></a> <span class="co">// `contents` is an enum known as Result:</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true"></a> <span class="kw">let</span> contents <span class="op">=</span> foo()<span class="op">;</span></span>
<span id="cb11-15"><a href="#cb11-15" aria-hidden="true"></a> <span class="kw">match</span> contents <span class="op">{</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true"></a> <span class="cn">Ok</span>(c) <span class="op">=></span> <span class="pp">println!</span>(c)<span class="op">,</span></span>
<span id="cb11-17"><a href="#cb11-17" aria-hidden="true"></a> <span class="cn">Err</span>(e) <span class="op">=></span> <span class="pp">eprintln!</span>(e)</span>
<span id="cb11-18"><a href="#cb11-18" aria-hidden="true"></a> <span class="op">}</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div>
<h3 id="conclusion">Conclusion</h3>
<p>I did not want to conclude without talking about stylistic choices, lack of metaprogramming, bizzare export rules, but, I am too busy converting my <code>interface{}</code> types into actual generic code for Go v2.</p>
</div>
<div class="intro">
Hi.
<div class="hot-links">
<a href="https://peppe.rs/index.xml" class="feed-button">Subscribe</a>
<a href="https://liberapay.com/nerdypepper/donate" class="donate-button">Donate</a>
</div>
<p>I'm Akshay, I go by nerd or nerdypepper on the internet.</p>
<p>
I am a compsci undergrad, Rust programmer and an enthusiastic Vimmer.
I write <a href="https://git.peppe.rs">open-source stuff</a> to pass time.
I also design fonts:
<a href="https://git.peppe.rs/fonts/scientifica">scientifica</a>,
<a href="https://git.peppe.rs/fonts/curie">curie</a>.
</p>
<p>Send me a mail at [email protected] or a message at [email protected].</p>
</div>
<a href="/" class="post-end-link">Home</a>
<span>/</span>
<a href="/posts" class="post-end-link">Posts</a>
<span>/</span>
<a class="post-end-link">Gripes With Go</a>
<a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/gripes_with_go.md
">View Raw</a>
</div>
</div>
</body>
</html>
|