If go is such a fantastic language, then why …

I have recently run into numerous articles touting the virtues of the go language. It would be fantastic. The language would save you so much time! According to the afficionados of go, there is nothing better than their new darling.

Now, let us look at the following example and watch how the go world comes crashing down and starts burning like hellfire.

I am going to create a very little example that is trivially easy to implement in approximately any scripting language, such as javascript, php, lua, python, you name it. It will turn out to be a fully-fledged computer science engineering project, requiring multiple teams of highly-experienced go programmers to get this done in go, if it can be done at all.

Our example program will be doing something very simple. It will accept a SQL statement as argument on the commandline. Then, it will submit it to a sqlite database. Then, it will output the result in json on stdout.

This is an implementation in php:

 

#!/usr/bin/env php
<?php

if($argc!=2) {
    echo "error: usage {$argv[0]} [query]\n";
    exit(1);
}

$query=$argv[1];

try {
    $db = new PDO('sqlite:demo.sqlite');
    $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $result = $db->query($query);
    if(!is_bool($result)) {
        $result=$result->fetchAll(PDO::FETCH_ASSOC);
    }
    $output=json_encode($result,JSON_PRETTY_PRINT|JSON_UNESCAPED_SLASHES);
    echo "$output\n";
}
catch(PDOException $e) {
    echo 'Error : '.$e->getMessage()."\n";
    exit(1);
}

We will submit the following sql queries to populate our little database:

 

CREATE TABLE Dogs (Id INTEGER PRIMARY KEY, Breed TEXT, Name TEXT, Age INTEGER);
INSERT INTO Dogs (Breed, Name, Age) VALUES ('Labrador', 'Tank', 2);
INSERT INTO Dogs (Breed, Name, Age) VALUES ('Husky', 'Glacier', 7);
INSERT INTO Dogs (Breed, Name, Age) VALUES ('Golden-Doodle', 'Ellie', 4);

The program is called phplite and the file containing our SQL statements demo.sql. We can use the shell to submit the SQL statements one by one to the program:

 

$ while read s; do if [ ! "$s" = "" ]; then ./phplite "$s"; fi; done < demo.sql

 

Now we can use the program to arbitrarily query our little database and obtain our output in json:

 

$ ./phplite "SELECT * FROM Dogs where Id in (2,3)";
[
    {
        "Id": "2",
        "Breed": "Husky",
        "Name": "Glacier",
        "Age": "7"
    },
    {
        "Id": "3",
        "Breed": "Golden-Doodle",
        "Name": "Ellie",
        "Age": "4"
    }
]

 

How do you write the corresponding program in go?

The typical examples that you will find with programs in go that query a database, do something like this:

// In the previous step , we used Query() function to
// retrieve all rows of the employee table into rows* of type Rows.
// Now we will iterate through each one of them to get the values for each row.

for rows.Next() {

 var empID sql.NullInt64
 var empName sql.NullString
 var empAge sql.NullInt64
 var empPersonId sql.NullInt64

 if err := rows.Scan(&empID, &empName, &empAge, 
                           &empPersonId); err != nil {
          log.Fatal(err)
 }

 fmt.Printf("ID %d with personID:%d & name %s is age %d\n",       
                   empID.Int64, empPersonId.Int64, empName.String, empAge.Int64)
}

One of the advantages of the amazing virtues of typing statically, is that you must know all the types and therefore all the columns in your SQL resultset upfront, so that you can “scan” for them.

What if you want to deal with any arbitrary SQL query that can return columns of any type? How do you deal with them? The technique in use in this example would impossibly be able to deal with that. There must be a workaround, no?

Probably, but that is where your computer science engineering team kicks in. They will will work hard to find a viable but probably also complicated and unreadable solution. I just used the standard reference guide in php to figure out how to write the example program. There is no way that you will just use any standard reference guide in go to do the same.

Imagine that you manage to solve the problem of dealing with an arbitrary SQL resultset in go. Now you will hit the next problem. How to produce json output from it?

Have a look at the following example:

package main

import "encoding/json"
import "fmt"
import "os"
    
type Response1 struct {
    Page   int
    Fruits []string
}

func main() {

    res1D := &Response1{
        Page:   1,
        Fruits: []string{"apple", "peach", "pear"}}
    res1B, _ := json.Marshal(res1D)
    fmt.Println(string(res1B))
    
}

We see the same problem cropping up again: you must know the type of the data to encode upfront. It may be possible to throw arbitrarily nested lists and tables to the Marshal function, but it will again require a computer science engineering team to achieve that. There is no way that you are going to figure out how to do that, just by looking at the standard documentation.

I have never said that it was impossible to write the example program in go. That is not true either. You could even write it in assembler if you wanted to. Go is a Turing-complete language. In that sense, you can compute anything in it that is computable.

The problem lies elsewhere.

You see, the practice of typing statically is meaningful when the set of valid types in a program is pretty much static.

For example, in the context of kernel programming, you do not want to invent new types on the fly, if only because the overhead required to support this would come with unacceptable performance and resource consumption penalties.

But then again, since go automatically drags a garbage collector into the fray, it would not be suitable for kernel programming either. In the very same context that typing statically is considered to be the best choice, automatic garbage collection (and therefore go) will be rejected.

C does not come with automatic garbage collection and does not impose any other choices that would be considered arbitrary at that level, and that would prevent it from being used in any imaginable low-level programming situation. Go makes too many choices upfront and is too opinionated to be suitable for that kind of work. Linus Torvalds would never consider go (or even C++) a suitable language for the kernel. Seriously, go is not a valid bare-metal language.

The example program is a trivial counterexample as to why go is not suitable for higher-level application programming. For example, writing a basic query browser such as phpmyadmin is a relatively easy task in any scripting language. I do not claim that it cannot be done in go, but you will have to drag in special measures to work around all the limitations that go imposes when doing so. It will be a difficult project, requiring lots of effort.

My conclusion is that there is simply no valid use case for a language like go. There is always a better choice for any programming task, regardless whether it is low-level or high-level.

Advertisements

Published by

eriksank

I mostly work on an alternative bitcoin marketplace -and exchange applications. I am sometimes available for new commercial projects but rather unlikely right now.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s