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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
|
<!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.72
</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" tabindex="-1"></a><span class="kw">type</span> Gender <span class="dt">int</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="kw">const</span> <span class="op">(</span></span>
<span id="cb1-4"><a href="#cb1-4" aria-hidden="true" tabindex="-1"></a> Male Gender <span class="op">=</span> <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" tabindex="-1"></a> Female <span class="co">// assigns Female to 1</span></span>
<span id="cb1-6"><a href="#cb1-6" aria-hidden="true" tabindex="-1"></a> Other <span class="co">// assigns Other to 2</span></span>
<span id="cb1-7"><a href="#cb1-7" aria-hidden="true" tabindex="-1"></a><span class="op">)</span></span>
<span id="cb1-8"><a href="#cb1-8" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-9"><a href="#cb1-9" aria-hidden="true" tabindex="-1"></a>fmt<span class="op">.</span>Println<span class="op">(</span><span class="st">"My gender is "</span><span class="op">,</span> Male<span class="op">)</span></span>
<span id="cb1-10"><a href="#cb1-10" aria-hidden="true" tabindex="-1"></a><span class="co">// My gender is 0</span></span>
<span id="cb1-11"><a href="#cb1-11" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a></span>
<span id="cb1-13"><a href="#cb1-13" aria-hidden="true" tabindex="-1"></a><span class="kw">func</span> <span class="op">(</span>g Gender<span class="op">)</span> String<span class="op">()</span> <span class="dt">string</span> <span class="op">{</span></span>
<span id="cb1-14"><a href="#cb1-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">switch</span> <span class="op">(</span>g<span class="op">)</span> <span class="op">{</span></span>
<span id="cb1-15"><a href="#cb1-15" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">0</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Male"</span></span>
<span id="cb1-16"><a href="#cb1-16" aria-hidden="true" tabindex="-1"></a> <span class="cf">case</span> <span class="dv">1</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Female"</span></span>
<span id="cb1-17"><a href="#cb1-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">default</span><span class="op">:</span> <span class="cf">return</span> <span class="st">"Other"</span></span>
<span id="cb1-18"><a href="#cb1-18" aria-hidden="true" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb1-19"><a href="#cb1-19" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb1-20"><a href="#cb1-20" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb1-21"><a href="#cb1-21" aria-hidden="true" tabindex="-1"></a><span class="co">// You can accidentally do stupid stuff like:</span></span>
<span id="cb1-22"><a href="#cb1-22" aria-hidden="true" tabindex="-1"></a>gender <span class="op">:=</span> Male <span class="op">+</span> <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" tabindex="-1"></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" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Female</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a> <span class="op">|</span> <span class="dt">Other</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>y<span class="op">,</span> goodToGo <span class="op">:=</span> x<span class="op">.(</span><span class="dt">int</span><span class="op">)</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="cf">if</span> goodToGo <span class="op">{</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a> fmt<span class="op">.</span>Println<span class="op">(</span>y<span class="op">)</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="op">}</span></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" tabindex="-1"></a><span class="kw">var</span> x <span class="kw">interface</span><span class="op">{}</span> <span class="op">=</span> <span class="dv">7</span></span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="kw">var</span> y <span class="op">:=</span> x<span class="op">.(</span><span class="dt">float64</span><span class="op">)</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>fmt<span class="op">.</span>Println<span class="op">(</span>y<span class="op">)</span></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">// results in a runtime error:</span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a><span class="kw">const</span> layout <span class="op">=</span> <span class="st">"2006-01-02"</span></span>
<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>time<span class="op">.</span>Parse<span class="op">(</span>layout<span class="op">,</span> <span class="st">"2020-08-01"</span><span class="op">)</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" tabindex="-1"></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" tabindex="-1"></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" tabindex="-1"></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" tabindex="-1"></a> nine <span class="op">*</span> three</span>
<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a>twenty_seven <span class="op">:=</span> <span class="ot">nil</span></span>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a>three <span class="op">:=</span> <span class="dv">1</span> <span class="op">+</span> <span class="dv">2</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a>nine <span class="op">:=</span> three <span class="op">*</span> three</span>
<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a>twenty_seven <span class="op">=</span> nine <span class="op">*</span> 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" tabindex="-1"></a><span class="cf">if</span> err <span class="op">!=</span> <span class="ot">nil</span> <span class="op">{</span> <span class="op">...</span> <span class="op">}</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" tabindex="-1"></a><span class="co">// 1. error handling is compulsory</span></span>
<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a><span class="co">// 2. errors are propagated with the `?` operator</span></span>
<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></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" tabindex="-1"></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" tabindex="-1"></a></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a></span>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a><span class="op">}</span></span>
<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb11-12"><a href="#cb11-12" aria-hidden="true" tabindex="-1"></a><span class="kw">fn</span> main() <span class="op">{</span></span>
<span id="cb11-13"><a href="#cb11-13" aria-hidden="true" tabindex="-1"></a> <span class="co">// `contents` is an enum known as Result:</span></span>
<span id="cb11-14"><a href="#cb11-14" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></a> <span class="cf">match</span> contents <span class="op">{</span></span>
<span id="cb11-16"><a href="#cb11-16" aria-hidden="true" tabindex="-1"></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" tabindex="-1"></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" tabindex="-1"></a> <span class="op">}</span></span>
<span id="cb11-19"><a href="#cb11-19" aria-hidden="true" tabindex="-1"></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, programmer and pixel-artist.</p>
<p>
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/about">scientifica</a>,
<a href="https://git.peppe.rs/fonts/curie/about">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>
|