From 366df8852f503523cc4f9046d82ba9a99dd51d7f Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 12 Feb 2023 12:13:49 +0530 Subject: new art: lapse --- docs/posts/gripes_with_go/index.html | 85 +++++++++++++++++++++++++----------- 1 file changed, 59 insertions(+), 26 deletions(-) (limited to 'docs/posts/gripes_with_go') diff --git a/docs/posts/gripes_with_go/index.html b/docs/posts/gripes_with_go/index.html index 1551fe6..74d6995 100644 --- a/docs/posts/gripes_with_go/index.html +++ b/docs/posts/gripes_with_go/index.html @@ -28,7 +28,7 @@ 01/08 — 2020
- 76.71 + 76.72 cm   @@ -42,17 +42,24 @@ Gripes With Go
-

You’ve read a lot of posts about the shortcomings of the Go programming language, so what’s one more.

+

You’ve read a lot of posts about the shortcomings of the Go +programming language, so what’s one more.

  1. Lack of sum types
  2. Type assertions
  3. Date and Time
  4. -
  5. Statements over Expressions
  6. -
  7. Erroring out on unused variables
  8. +
  9. Statements over +Expressions
  10. +
  11. Erroring out on unused +variables
  12. Error handling

Lack of Sum types

-

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 enum type in C. Go lacks enum types unfortunately, and you are forced to resort to crafting your own substitute.

+

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 enum type in C. Go lacks +enum types unfortunately, and you are forced to resort to +crafting your own substitute.

A type to represent gender for example:

type Gender int
 
@@ -67,17 +74,18 @@
 // Oops! We have to implement String() for Gender ...
 
 func (g Gender) String() string {
-    switch (g) {
-    case 0: return "Male"
-    case 1: return "Female"
-    default: return "Other"
+    switch (g) {
+    case 0: return "Male"
+    case 1: return "Female"
+    default: return "Other"
     }
 }
 
 // You can accidentally do stupid stuff like:
 gender := Male + 1

The Haskell equivalent of the same:

-
data Gender = Male
+
data Gender = Male
             | Female
             | Other
             deriving (Show)
@@ -88,7 +96,7 @@
 

Type assertions in Go allow you to do:

var x interface{} = 7
 y, goodToGo := x.(int)
-if goodToGo {
+if goodToGo {
     fmt.Println(y)
 }

The error check however is optional:

@@ -98,18 +106,32 @@ // results in a runtime error: // panic: interface conversion: interface {} is int, not float64

Date and Time

-

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:

+

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:

Mon Jan 2 15:04:05 MST 2006
-

Which is the date produced when you write the first seven natural numbers like so:

+

Which is the date produced when you write the first seven natural +numbers like so:

01/02 03:04:05 '06 -0700
-

Parsing a string in YYYY-MM-DD format would look something like:

+

Parsing a string in YYYY-MM-DD format would look +something like:

const layout = "2006-01-02"
 time.Parse(layout, "2020-08-01")
-

This so-called “intuitive” method of formatting dates doesn’t allow you to print 0000 hrs as 2400 hrs, it doesn’t allow you to omit the leading zero in 24 hour formats. It is rife with inconveniences, if only there were a tried and tested date formatting convention …

+

This so-called “intuitive” method of formatting dates doesn’t allow +you to print 0000 hrs as 2400 hrs, it doesn’t +allow you to omit the leading zero in 24 hour formats. It is rife with +inconveniences, if only there were a tried and +tested date formatting convention …

Statements over Expressions

-

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.

-

Rust allows you to create local namespaces, and treats blocks ({}) as expressions:

-
let twenty_seven = {
+

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.

+

Rust allows you to create local namespaces, and treats blocks +({}) as expressions:

+
let twenty_seven = {
     let three = 1 + 2;
     let nine = three * three;
     nine * three
@@ -120,17 +142,25 @@
 three := 1 + 2
 nine := three * three
 twenty_seven = nine * three
-

Erroring out on unused variables

-

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.

+

Erroring out on unused +variables

+

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.

Error handling

-
if err != nil { ... }
+
if err != nil { ... }

Need I say more? I will, for good measure:

  1. Error handling is optional
  2. -
  3. Errors are propagated via a clunky if + return statement
  4. +
  5. Errors are propagated via a clunky if + +return statement
-

I prefer Haskell’s “Monadic” error handling, which is employed by Rust as well:

-
// 1. error handling is compulsory
+

I prefer Haskell’s “Monadic” error handling, which is employed by +Rust as well:

+
// 1. error handling is compulsory
 // 2. errors are propagated with the `?` operator
 fn foo() -> Result<String, io::Error> {
     let mut f = File::open("foo.txt")?; // return if error
@@ -144,13 +174,16 @@
 fn main() {
     // `contents` is an enum known as Result:
     let contents = foo();
-    match contents {
+    match contents {
         Ok(c) => println!(c),
         Err(e) => eprintln!(e)
     }
 }

Conclusion

-

I did not want to conclude without talking about stylistic choices, lack of metaprogramming, bizzare export rules, but, I am too busy converting my interface{} types into actual generic code for Go v2.

+

I did not want to conclude without talking about stylistic choices, +lack of metaprogramming, bizzare export rules, but, I am too busy +converting my interface{} types into actual generic code +for Go v2.

-- cgit v1.2.3