DEV Community

MSKhodadady
MSKhodadady

Posted on

Inspection, on the go

Hello everyone.
I just learnt the go language, and I want to share my experience of using it.
At first, golang was just an "Oh, just another programming language" for me, but as I go throw, I found noticeable points about that.
I am also a functional programming enthusiast and I'll compare go with FP rules and methods.

Syntax

It's syntax is c-like, and borrowed some features from python, like range, for and if without parentheses, being free of semicolons, and more.

:=

It's a good simplifier. No more writing type for values. It's like var in java or C#.

Core Library

Like python, go has a rich core library with many useful stuff in it. One of them I worked with is database/sql. It provides good interface for implementing libraries that work with dbs.

Interface

Interfaces are a big point of difference. They are really good, that C lacks them. They provide us significant "polymorphism", without needing OOP's inheritance, that one state at 10th parent may change, and causes your program explode and you don't know why!

Some words of polymorphism:

Polymorphism means you can we can share on behaviour between different types. A great pure FP language like Haskell also has it, with the name of 'type-class'.
Inheritance also provides polymorphism, but inheritance also causes great unpredictability to our apps, and that's also because it breaks apart our app's state and spreads them in different places of our app. But with interfaces, it just shares behaviours between types, and leaves the state in our hands.

Error Handling

Error Handling in go is interesting. Errors (or in another term, "Exceptions") are just values and will be handled like values, in contrast with another languages that handles errors with syntax.
But there is a problem with the bunch of if err != nil parts in code. If there was syntaxic sugar for that, it will be far far better for code to be clean and readable. Maybe something like this:

// when you see err:
// panic
ra, (err; panic) := res.RowsAffected()
// run a func, e.g. handle
ra, (err;handle()) := res.RowsAffected()
// return something
ra, (err;return whatToDoWith(err)) := res.RowsAffected()
Enter fullscreen mode Exit fullscreen mode

Go has another type of errors too. In some rare cases that you don't know what to do with an error and it's totally unexpected, you just need to panic, and if you found a way, you can recover.

Goroutines and Channels

Goroutines are one of the top points in go, maybe the apex point. They really simplify concurrency, but in my opinion, not more simplifier than async programming.
They are like threads in java, and somehow like async-await and coroutines (in C#, python, js, ...), because you must wait for a channel to send something so you receive it and continue.
Goroutines are also a way of having streams. For example, in a http server, you will receive the requests, send them to a goroutine via channel with a handler, that goroutine processes them and will send response. Also we can have some middlewares.

Generics

Generics are advanced but crucial feature that I think, every modern language must have, as many languages have. Go added this feature in 1.18. Go Generics have two usage, Generics like other language, and most wanted UNIONS. Unions are very useful, they make many values typed that couldn't be typed before. For example, a function takes a parameter that can be string or integer. Before generics, we should mention interface {} for that parameter, then check if its type is integer or string, and if it isn't, make error.

func testFun(a interface{}) error{
    switch a.(type) {
    case string, int:
        // do sth ...
    default:
        return errors.New("not integer nor string")
    }
    return nil
}
Enter fullscreen mode Exit fullscreen mode

But now, with generics:

func testFun2[T string|int](a T) {
    // do sth ...
}
Enter fullscreen mode Exit fullscreen mode

Generics also leverage type inference for inferring type of value and omitting type arguments. As a simple example:

s := "hello"
// without inference
testFun2[string](s)
// with inference
testFun2(s)
Enter fullscreen mode Exit fullscreen mode

This is a simple example but type inference has more complicated aspects. You can read more about them and also other things about generics in go, in this article: An Introduction To Generics.
Also mention that type inference is the characteristic of FP languages, and now we see it in many other languages like Go, C++, C#, Java, … .

What about FP in go

Go is not a specifically FP language, but you can obey FP rules in your own. You can do not changing variables, you can use recursive functions instead of loops and you can have pure functions.

Thanks to generics, you can have some abstractions like Maybe, Either, ... , that exists in some FP languages, and this is really a good point. I saw a lib that implemented some of them that you can use them: github.com/samber/mo.

But something extremely lacks. Three loopy function, map-filter-fold aren't part of language itself but they very needed. You can use libraries for having them (like one mentioned above), but I think we need them in core language because of their usefulness.

There are something like if-else expressoin, switch expression, pattern matching, ... for completing the full taste of functional programming in go, that I hope to see them in an early future.

Last Words

Go is a good simple nifty language. I like to use it more. Also I like to learn its rival, rust lang.

Thanks for reading my article. Please comment me if you have opinions or critics about my article.

Goodbye!

Top comments (0)