Learning Go for PHP Programmers – Part 1

Golang mascot

I have been trying to learn Go (golang) this week a bit more formally. I have worked with Go in the past but I could do it because it has syntactical familiarity with other languages I use or have used–PHP, JavaScript, C#, C, etc. This time, I wanted to do it a bit more formally as I am thinking of using Go to write a non-trivial application. In this post, I compare Go with other languages I know, mainly PHP, to compare concepts and build understanding.

Go is a popular programming language used for many popular tools such as Docker, Kubernetes, Terraform, and many other tools, command-line applications, and scalable systems. Given its popularity, it was not hard to find resources to learn Go. Lately, I have first attempted to find resources on YouTube and then look into the project documentation. I did the same and found a 6.5-hour video on the FreeCodeCamp channel. (Sidenote: If you don’t know about FreeCodeCamp, you should definitely look them up. The effort they put in is admirable.)

6.5 hours is quite long and not practical to view at a stretch but I figured I could watch it at 2x or 3x the speed and cover it. I was watching the initial parts at even 4x the speed to just be able to spot any differences from what I knew about Go already. As they got into a bit more advanced topics, I slowed it down to 2x to be able to understand better. If you are already an experienced programmer, you can do that as well.

While watching the video, I also solved problems on Exercism to get some hands-on. This post is a return of my learnings from these coming from the perspective of a PHP programmer. There are lots of excellent Go tutorials out there, including the official ones, the video I linked to, and Exercism as well. I am going to summarise the differences from PHP here.

Hello, World!

This is what a Go program looks like.

package main

import "fmt"

func main() {
  fmt.Println("Hello, World!")
}

It shouldn’t be too hard for a PHP programmer to understand. The first line specifies the package which is somewhat like a PHP namespace. Notice I said “somewhat”. They behave similarly but a namespace is optional in PHP whereas it is required in Go. Similar to namespaces, all functions, variables, and types in a package may be accessed by another file with the same package.

The next line imports the "fmt" package because we want to use the Println function from that package. Think of this as the use keyword in PHP. It brings in the package’s exported members so that we may use it. Unlike use, you still have to specify the package name to use the type or method. You can see that from the body of the function.

Functions are very similar to functions in PHP. We will talk more about functions in the next section.

Concepts in Go

Before we talk about other syntactical differences, it is worth to talk about some of the conceptual differences so that we can understand this better. Go is a statically typed language built for reliability (type safety) and efficiency. It is quite close to the machine in the way C is, but it also brings in benefits of more advanced data structures, even a style of object-oriented programming. For example, Go has structs and interfaces which appear to do what you expect from other languages but there is a different ideology on how to use it in Go.

Classes (structs)

Go only supports structs and interfaces for its entire object paradigm. In C, structs are similar to PHP classes except that they cannot hold any functions, just properties. Go does the same thing, but then provides syntactic sugar to let you “attach” functions to structs. You cannot do this within the struct itself but anywhere outside the struct. For example:

type Cartesian struct {
  x int
  y int
}

func (c Cartesian) IsOrigin() bool {
  return c.x == 0 && c.y == 0
}

Here, Cartesian is a struct type with two properties. This, so far, is like a regular struct. But you can attach a function to this struct so that you can do something like this (like you would in PHP):

c := Cartesian{0, 0}
if (c.IsOrigin()) {
  // ...
}

The cool thing is you can attach functions to any of the types except primitives like int. For primitives, you can create a custom type which is the same as primitive and attach functions to that.

type Int int

func (i Int) IsPositive() {
  return i > 0
}

Interfaces

Interfaces are very similar to what they are in PHP. While structs can only hold data (or content), interfaces can only hold definitions of functions or behaviours. You also get the same benefits of interfaces as in other languages, i.e., an object satisfies a certain contract defined by the interfaces. So far, nothing different from PHP.

But Go does something really cool here. It supports implicit interface satisfaction. This means two things: First, there is no implements keyword. This means that a struct does not need to explicitly mention it satisfied a certain interface. It just needs to implement the method in the interface. More specifically, it should attach a function with the same definition like the one in the interface.

Second, packages are not encouraged to export interfaces, just concrete implementations. This is opposite of what you might expect from working in PHP. Any package that wants to use concrete implementations from another package should define its own interfaces that it wants to satisfy. This sounds weird, but someone suggested to me a video for this and it made complete sense. I would suggest just watch the video.

The video covers everything you need to know about interfaces but if you’re already versed with it from PHP or other languages, you could just skip to the 27:09 mark.

Access modifiers

I haven’t seen anything about access modifiers such as public, protected, or private yet. I don’t think Go supports this and it makes sense as there are no classes, just structs. There is just one type of access control I have seen so far and that is what the package exports. PHP doesn’t have anything similar to this (there are no private classes in PHP, just private members). In Go, there is just a convention of what can be accessed outside a package. Anything–type, variables, function–can be accessed outside the package if its name begins with a capital letter. So, for example, if you have a function named IsOrigin, it can be accessed from outside the package. But isOrigin may not be accessed.

What else is different?

I think this is a good place to stop for today.