Learning Golang (part 2)

It’s been several months since I started to look at Golang, but I’ve been picking it back up again. The design decisions in the language are starting to make me like this language more and more. It’s clear there were decisions made to address many pet peevs with other languages. Here’s a few I’ve noticed:

  • standard formatting and the ‘go fmt’ tool. In many other languages there’s endless debates about where your { and } should go, and honestly it really doesn’t matter. Go addresses this by requiring a single style where the opening { is syntactically required at the end of the line (and not allowed on the following line) in order for your code to compile. End of argument. Done
  • a single for loop for iteration. Other languages support for and while in a few different variations (while condition at the beginning of a block or at the end), but Go has a ‘for’ statement and that’s it. Keep it simple.
  • much time has been wasted in Java arguing about whether exceptions should be checked or unchecked. Go’s approach, no exceptions, no exception handling. You have an ‘error’ type which you can chose to return as the last return value from a function if needed

Here’s my notes following on from my earlier Part 1.

Imports

Imports are each on a separate line, with the package in quotes:

import "fmt"
import "unicode/utf8"

Variables

Variable types are defined after the variable name, both in variable declaration and function parameters:

func ExampleFunc(x int, y int) int {
var example int
var example2 string
...
return 1
}

This function takes 2 params, both ints, and returns an int.

Unlike other languages where you can pass many params but only return a single result, Go functions allows you to return multiple results, e.g.

func ExampleFunc(x int, y int) (int, int) {
var example int
var example2 string
...
return a, b
}

To call this function and receive the multiple results:

x, y := ExampleFunc(1, 2)

If you’re only interested in one of the return values you can use the blank identified to ignore one of the returned values:

_, y := ExampleFunc(1, 2)

Functions with a capital first letter are exported so they can be imported elsewhere, functions with a lowercase first letter are not.

Solving a Quora programming homework question in ARM Assembly

It makes me sad when students ask the online communities to ‘please write me a program that does the following’. Not only is this flat out dishonest to ask someone else to do your homework for you, the opportunity for learning is in the process of solving the problem and writing the code yourself. If someone else writes the code, you’ve missed that opportunity. There’s little to be learned if someone else does the hard work and gives you the final result.

Most communities police these types of questions pretty well. Reviewers on Stackoverflow for example are quick to respond to these types of questions to help developers restructure a generic request for help into a specific question about a specific problem that the developer need help with. The guides that are usually referred to on suggestions to restructure these questions are actually very good advice and reminders for us all on how to ask good questions:

On other community sites, the community response goes in a different direction. This question for help on how to write a program was responded to be some of the funniest and bizarre approaches to solve the askers problem in all sorts of obscure language from Brainfuck to Whitespace and plenty of other weirdness inbetween.

Not to be left out but a little later to the party, I realized I hadn’t done any ARM assembly for a while, so here’s my solution in ARM Assembly that I developed on my Raspberry Pi:

.global main

main:
MOV R4, #3 @ init outer line counter =3

_outerloop:
MOV R3, R4 @ init word loop counter with current value of outer counter

_wordloop:
MOV R7, #4 @ syscall 4: output to stdout
MOV R0, #1 @ stdout
MOV R2, #6 @ length of string
LDR R1, =output
SWI 0

SUB R3, R3, #1 @ decrement word loop counter
CMP R3, #0
BNE _wordloop

@print newline
MOV R7, #4 @ syscall 4: output to stdout
MOV R0, #1 @ stdout
MOV R2, #1 @ length of string
LDR R1, =eol
SWI 0

SUB R4, R4, #1 @ decrement outer counter
CMP R4, #0
BNE _outerloop

_exit:
MOV R1, #0
MOV R7, #1
SWI 0

.data
output:
.asciz "Smile!"
eol:
.asciz "\n"

AWS S3 error: “The bucket you are attempting to access must be addressed using the specified endpoint”

Most errors on AWS are explicit and self explanatory, but once in a while you run into something that tells you something went wrong, but not how to fix it.

When setting up an S3 bucket to serve a static website, I got this error being returned as 301s for referenced files:

<Error>
<Code>PermanentRedirect</Code>
<Message>The bucket you are attempting to access must be addressed using the specified endpoint. Please send all future requests to this endpoint.</Message>
<Endpoint>s3.amazonaws.com</Endpoint>
<Bucket>static</Bucket>
...
</Error>

If you click an object in a bucket and click the overview tab, you can get a URL direct to the object, for example:

To load a static site from S3 though, you need to use a URL referencing the bucket in the server name, so instead of this:

https://s3-us-west-1.amazonaws.com/react-sudoku-solver/index.html

You should use this:

http://react-sudoku-solver.s3-us-west-1.amazonaws.com/index.html

(I’m currently working on a React app as a Sudoku Solver – more on this later)

Kubernetes: creating a hostPath PersistentVolume in a single node cluster

To create a ‘hostPath’ PersistentVolume in a single node cluster (do not use in a cluster with more than 1 node):

kind: PersistentVolume
apiVersion: v1
metadata:
name: pv1
labels:
type: local
spec:
storageClassName: manual
capacity:
storage: 1Gi
accessModes:
- ReadWriteOnce
hostPath:
path: "/your-path-for-vol1"

If the above is pv1.yaml, apply with:

kubectl apply -f pv1.yaml

For more info, see the docs here.