diff options
Diffstat (limited to 'docs/posts/gripes_with_go')
-rw-r--r-- | docs/posts/gripes_with_go/index.html | 173 |
1 files changed, 173 insertions, 0 deletions
diff --git a/docs/posts/gripes_with_go/index.html b/docs/posts/gripes_with_go/index.html new file mode 100644 index 0000000..b527b4a --- /dev/null +++ b/docs/posts/gripes_with_go/index.html | |||
@@ -0,0 +1,173 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html lang="en"> | ||
3 | <head> | ||
4 | <link rel="stylesheet" href="/style.css"> | ||
5 | <link rel="stylesheet" href="/syntax.css"> | ||
6 | <meta charset="UTF-8"> | ||
7 | <meta name="viewport" content="initial-scale=1"> | ||
8 | <meta content="#ffffff" name="theme-color"> | ||
9 | <meta name="HandheldFriendly" content="true"> | ||
10 | <meta property="og:title" content="Gripes With Go"> | ||
11 | <meta property="og:type" content="website"> | ||
12 | <meta property="og:description" content="a static site {for, by, about} me "> | ||
13 | <meta property="og:url" content="https://peppe.rs"> | ||
14 | <link rel="icon" type="image/x-icon" href="/favicon.png"> | ||
15 | <title>Gripes With Go · peppe.rs</title> | ||
16 | <body> | ||
17 | <div class="posts"> | ||
18 | <div class="post"> | ||
19 | <a href="/" class="post-end-link">⟵ Back</a> | ||
20 | <a class="stats post-end-link" href="https://raw.githubusercontent.com/nerdypepper/site/master/posts/gripes_with_go.md | ||
21 | ">View Raw</a> | ||
22 | <div class="separator"></div> | ||
23 | <div class="date"> | ||
24 | 01/08 — 2020 | ||
25 | <div class="stats"> | ||
26 | <span class="stats-number"> | ||
27 | 76.71 | ||
28 | </span> | ||
29 | <span class="stats-unit">cm</span> | ||
30 |   | ||
31 | <span class="stats-number"> | ||
32 | 4.9 | ||
33 | </span> | ||
34 | <span class="stats-unit">min</span> | ||
35 | </div> | ||
36 | </div> | ||
37 | <h1> | ||
38 | Gripes With Go | ||
39 | </h1> | ||
40 | <div class="post-text"> | ||
41 | <p>You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.</p> | ||
42 | <ol type="1"> | ||
43 | <li><a href="#lack-of-sum-types">Lack of sum types</a></li> | ||
44 | <li><a href="#type-assertions">Type assertions</a></li> | ||
45 | <li><a href="#date-and-time">Date and Time</a></li> | ||
46 | <li><a href="#statements-over-expressions">Statements over Expressions</a></li> | ||
47 | <li><a href="#erroring-out-on-unused-variables">Erroring out on unused variables</a></li> | ||
48 | <li><a href="#error-handling">Error handling</a></li> | ||
49 | </ol> | ||
50 | <h3 id="lack-of-sum-types">Lack of Sum types</h3> | ||
51 | <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> | ||
52 | <p>A type to represent gender for example:</p> | ||
53 | <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> | ||
54 | <span id="cb1-2"><a href="#cb1-2" aria-hidden="true"></a></span> | ||
55 | <span id="cb1-3"><a href="#cb1-3" aria-hidden="true"></a><span class="kw">const</span> (</span> | ||
56 | <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> | ||
57 | <span id="cb1-5"><a href="#cb1-5" aria-hidden="true"></a> Female <span class="co">// assigns Female to 1</span></span> | ||
58 | <span id="cb1-6"><a href="#cb1-6" aria-hidden="true"></a> Other <span class="co">// assigns Other to 2</span></span> | ||
59 | <span id="cb1-7"><a href="#cb1-7" aria-hidden="true"></a>)</span> | ||
60 | <span id="cb1-8"><a href="#cb1-8" aria-hidden="true"></a></span> | ||
61 | <span id="cb1-9"><a href="#cb1-9" aria-hidden="true"></a>fmt.Println(<span class="st">"My gender is "</span>, Male)</span> | ||
62 | <span id="cb1-10"><a href="#cb1-10" aria-hidden="true"></a><span class="co">// My gender is 0</span></span> | ||
63 | <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> | ||
64 | <span id="cb1-12"><a href="#cb1-12" aria-hidden="true"></a></span> | ||
65 | <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> | ||
66 | <span id="cb1-14"><a href="#cb1-14" aria-hidden="true"></a> <span class="kw">switch</span> (g) {</span> | ||
67 | <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> | ||
68 | <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> | ||
69 | <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> | ||
70 | <span id="cb1-18"><a href="#cb1-18" aria-hidden="true"></a> }</span> | ||
71 | <span id="cb1-19"><a href="#cb1-19" aria-hidden="true"></a>}</span> | ||
72 | <span id="cb1-20"><a href="#cb1-20" aria-hidden="true"></a></span> | ||
73 | <span id="cb1-21"><a href="#cb1-21" aria-hidden="true"></a><span class="co">// You can accidentally do stupid stuff like:</span></span> | ||
74 | <span id="cb1-22"><a href="#cb1-22" aria-hidden="true"></a>gender := Male + <span class="dv">1</span></span></code></pre></div> | ||
75 | <p>The Haskell equivalent of the same:</p> | ||
76 | <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> | ||
77 | <span id="cb2-2"><a href="#cb2-2" aria-hidden="true"></a> <span class="op">|</span> <span class="dt">Female</span></span> | ||
78 | <span id="cb2-3"><a href="#cb2-3" aria-hidden="true"></a> <span class="op">|</span> <span class="dt">Other</span></span> | ||
79 | <span id="cb2-4"><a href="#cb2-4" aria-hidden="true"></a> <span class="kw">deriving</span> (<span class="dt">Show</span>)</span> | ||
80 | <span id="cb2-5"><a href="#cb2-5" aria-hidden="true"></a></span> | ||
81 | <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> | ||
82 | <h3 id="type-assertions">Type Assertions</h3> | ||
83 | <p>A downcast with an optional error check? What could go wrong?</p> | ||
84 | <p>Type assertions in Go allow you to do:</p> | ||
85 | <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> | ||
86 | <span id="cb3-2"><a href="#cb3-2" aria-hidden="true"></a>y, goodToGo := x.(<span class="dt">int</span>)</span> | ||
87 | <span id="cb3-3"><a href="#cb3-3" aria-hidden="true"></a><span class="kw">if</span> goodToGo {</span> | ||
88 | <span id="cb3-4"><a href="#cb3-4" aria-hidden="true"></a> fmt.Println(y)</span> | ||
89 | <span id="cb3-5"><a href="#cb3-5" aria-hidden="true"></a>}</span></code></pre></div> | ||
90 | <p>The error check however is optional:</p> | ||
91 | <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> | ||
92 | <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> | ||
93 | <span id="cb4-3"><a href="#cb4-3" aria-hidden="true"></a>fmt.Println(y)</span> | ||
94 | <span id="cb4-4"><a href="#cb4-4" aria-hidden="true"></a><span class="co">// results in a runtime error:</span></span> | ||
95 | <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> | ||
96 | <h3 id="date-and-time">Date and Time</h3> | ||
97 | <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> | ||
98 | <pre><code>Mon Jan 2 15:04:05 MST 2006</code></pre> | ||
99 | <p>Which is the date produced when you write the first seven natural numbers like so:</p> | ||
100 | <pre><code>01/02 03:04:05 '06 -0700</code></pre> | ||
101 | <p>Parsing a string in <code>YYYY-MM-DD</code> format would look something like:</p> | ||
102 | <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> | ||
103 | <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> | ||
104 | <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> | ||
105 | <h3 id="statements-over-expressions">Statements over Expressions</h3> | ||
106 | <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> | ||
107 | <p>Rust allows you to create local namespaces, and treats blocks (<code>{}</code>) as expressions:</p> | ||
108 | <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> | ||
109 | <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> | ||
110 | <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> | ||
111 | <span id="cb8-4"><a href="#cb8-4" aria-hidden="true"></a> nine <span class="op">*</span> three</span> | ||
112 | <span id="cb8-5"><a href="#cb8-5" aria-hidden="true"></a><span class="op">};</span></span></code></pre></div> | ||
113 | <p>The Go equivalent of the same:</p> | ||
114 | <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> | ||
115 | <span id="cb9-2"><a href="#cb9-2" aria-hidden="true"></a></span> | ||
116 | <span id="cb9-3"><a href="#cb9-3" aria-hidden="true"></a>three := <span class="dv">1</span> + <span class="dv">2</span></span> | ||
117 | <span id="cb9-4"><a href="#cb9-4" aria-hidden="true"></a>nine := three * three</span> | ||
118 | <span id="cb9-5"><a href="#cb9-5" aria-hidden="true"></a>twenty_seven = nine * three</span></code></pre></div> | ||
119 | <h3 id="erroring-out-on-unused-variables">Erroring out on unused variables</h3> | ||
120 | <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> | ||
121 | <h3 id="error-handling">Error handling</h3> | ||
122 | <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> | ||
123 | <p>Need I say more? I will, for good measure:</p> | ||
124 | <ol type="1"> | ||
125 | <li>Error handling is optional</li> | ||
126 | <li>Errors are propagated via a clunky <code>if</code> + <code>return</code> statement</li> | ||
127 | </ol> | ||
128 | <p>I prefer Haskell’s “Monadic” error handling, which is employed by Rust as well:</p> | ||
129 | <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> | ||
130 | <span id="cb11-2"><a href="#cb11-2" aria-hidden="true"></a><span class="co">// 2. errors are propagated with the `?` operator</span></span> | ||
131 | <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> | ||
132 | <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> | ||
133 | <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> | ||
134 | <span id="cb11-6"><a href="#cb11-6" aria-hidden="true"></a></span> | ||
135 | <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> | ||
136 | <span id="cb11-8"><a href="#cb11-8" aria-hidden="true"></a></span> | ||
137 | <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> | ||
138 | <span id="cb11-10"><a href="#cb11-10" aria-hidden="true"></a><span class="op">}</span></span> | ||
139 | <span id="cb11-11"><a href="#cb11-11" aria-hidden="true"></a></span> | ||
140 | <span id="cb11-12"><a href="#cb11-12" aria-hidden="true"></a><span class="kw">fn</span> main() <span class="op">{</span></span> | ||
141 | <span id="cb11-13"><a href="#cb11-13" aria-hidden="true"></a> <span class="co">// `contents` is an enum known as Result:</span></span> | ||
142 | <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> | ||
143 | <span id="cb11-15"><a href="#cb11-15" aria-hidden="true"></a> <span class="kw">match</span> contents <span class="op">{</span></span> | ||
144 | <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> | ||
145 | <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> | ||
146 | <span id="cb11-18"><a href="#cb11-18" aria-hidden="true"></a> <span class="op">}</span></span> | ||
147 | <span id="cb11-19"><a href="#cb11-19" aria-hidden="true"></a><span class="op">}</span></span></code></pre></div> | ||
148 | <h3 id="conclusion">Conclusion</h3> | ||
149 | <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> | ||
150 | |||
151 | </div> | ||
152 | |||
153 | <div class=intro> | ||
154 | Hi. | ||
155 | <div class=hot-links> | ||
156 | <a href=https://peppe.rs/index.xml class=feed-button>Subscribe</a> | ||
157 | <a href=https://liberapay.com/nerdypepper/donate class=donate-button>Donate</a> | ||
158 | </div> | ||
159 | <p>I'm Akshay, I go by nerd or nerdypepper on the internet.</p> | ||
160 | <p> | ||
161 | I am a compsci undergrad, Rust programmer and an enthusiastic Vimmer. | ||
162 | I write open-source stuff to pass time. I also design fonts: scientifica, curie. | ||
163 | </p> | ||
164 | <p>Send me a mail at [email protected] or a message at [email protected].</p> | ||
165 | </div> | ||
166 | |||
167 | <a href="/" class="post-end-link">⟵ Back</a> | ||
168 | <a class="stats post-end-link" href="https://raw.githubusercontent.com/nerdypepper/site/master/posts/gripes_with_go.md | ||
169 | ">View Raw</a> | ||
170 | </div> | ||
171 | </div> | ||
172 | </body> | ||
173 | </html> | ||