My thoughts about programming languages
By: Michele Riva
Tags: Haskell, Nodejs, Elixir, Golang, PHP

My personal thoughts about JavaScript, PHP, Golang, Haskell, and Elixir. Which is the best one?

Photo by Thomas Kelley on Unsplash

During the last years, I had the opportunity to experiment with different programming languages.

I really like to learn different languages, approaches, and paradigms. I’m an inquisitive person, and programming languages have always fascinated me.

Every language is different, and here I’d like to add some considerations about what I liked and what I hated about the five languages that I’ve worked with.

JavaScript

Haskell

Go

PHP

Elixir

JavaScript

The good

Quick prototyping: JavaScript enables you to write quick and dirty prototypes to validate your ideas. With Node.js, you can even build backend proof of concepts in a minimal amount of time.

Flexibility: with ES6 metaprogramming features (Proxies, Symbols, etc.) JavaScript is becoming a compelling language.

But even if you don’t use those features, it allows you to write some very generic functions and utilize them both on the client, server, and even mobile apps (React Native, for instance).

Community: the JavaScript community is awesome. Every time you have a problem, there’s always someone who asked for that on StackOverflow :D

Jokes apart, the npm registry is an incredible source of useful packages that enables you to write an application using just one language.

Functional programming: as someone may know, in the beginning, JavaScript had to be “a Scheme-like programming language for the browser, but with Java syntax.”

Even if today JavaScript is not a purely functional programming language, it preserves some useful FP features such as higher-order functions, anonymous functions (using arrow functions in ES6+), and so on.

Syntax: the latest versions of JavaScript introduced some syntactic sugars that make it easy to write more readable code. Object/Array destructuring, arrow functions, spread operator, to name a few.

Asynchronous: once you get how to handle async code, you’ll begin to think async. And you’ll like it.

The bad

Dynamic typing: JavaScript’s dynamic typing is atrocious. Yes, I know why 10 + "10" === "1010" , but I’m not too fond of it. Type coercion is something that will likely break your code runtime instead of building/compile time.

Other compiled languages (such as ReasonML or Haskell) don’t actually require type annotation; they can infer types at compile time. But they will throw an error if you're trying to make the sum of an integer and a string, and that’s just a silly example.

By the way, both TypeScript and Flow can fix that.

General nonsense: JavaScript nonsense features are often caused by type coercion.

[] + {} === [object object] but {} + [] === 0 .

typeof NaN === "number" , but NaN actually means “Not a Number.”

If you’re a JavaScript programmer, you know what I mean by general nonsense.

Tail call optimization: even if EcmaScript specifies TCO for recursive functions, it seems to be only supported by WebKit.

Object/Array constants are mutable: just like Java’s final , you can modify both objects and arrays after their initialization, even if they are constants.

Haskell

The good

It changes your mind: after getting in touch with Haskell, you’ll begin to think about code in a completely different way.

Performances: Haskell is a compiled language, and thanks to its purely functional nature, the compiler can adopt a lot of optimizations at compile time.

Type system: the Hindley–Milner type system is awesome. Type declarations are unequivocal and easy to understand. Also, the Haskell type system can infer types and check for bugs during compile time.

Syntax: once you get used to, Haskell code is a pleasure to read.

Classes: really similar to Java’s interfaces, but more powerful thanks to their hierarchic design.

Well designed: Haskell doesn’t show typical design errors (such as JavaScript ones) and prefers software correctness over “having X feature at all costs” (read more about that in the PHP section)

Pattern matching: self-explanatory. Haskell pattern matching is both fun and powerful:

sayMe :: (Integral a) => a -> String

sayMe 1 = "One!"

sayMe 2 = "Two!"

sayMe 3 = "Three!"

sayMe 4 = "Four!"

sayMe 5 = "Five!"

sayMe x = "Not between 1 and 5"

(learn more here)

Lazy evaluation: functions won’t be evaluated until strictly needed.

The bad

It makes you feel stupid: Haskell is a compelling language, but sometimes it seems that you won’t be able to do anything with it without a Ph.D. in Category Theory. The learning curve is really steep.

Lack of valid resources: learning Haskell is really, really hard. I have read 5 different books and took 3 online courses, but it begins to lose sense after some time. Finding a mentor is hard.

Monads: basically just monoids in the category of endofunctors. Clear, isn’t it? By the way, the problem isn’t with monads: but the difficulty to understand wtf they are.

Jargon: forget everything you know about programming jargon. You’ll spend more time talking about monads, monoids, functors, applicative than lists, integers, loops, and other common programming keywords in Haskell. It feels like learning programming from scratch.

Go

The good

Easy to learn: I’ve built my first Go webserver in like an hour. The C-like syntax makes it really easy to get started with this language from JavaScript, PHP, Java, C.

Outstanding performances: even without caring a lot about how you write your code, you can end up with some decent performances.

Concurrency made easy: it is straightforward to get started with goroutines and make your code concurrent.

Incredible ecosystem: the Go ecosystem is huge and full of high-quality packages.

Go modules: with the introduction of go modules, most of the time, you can finally forget the $GOPATH . They also make it easier to manage your application dependencies.

The bad

No generics: Go doesn’t support generic typing, which makes it difficult to build reusable functions such as filter , sort and so on.

There are no arrow functions: while it’s technically possible to write an anonymous function in Go, I miss the arrow function form.

No ternary operator: seems not important, but this:

myVar := 10 > 5 ? "foo" : "bar"

is way better than this:

var myVar string if 10 > 5 {

myVar = "foo"

} else {

myVar = "bar"

}

Error handling: after some time coding in Go, the error handling still seems a bit strange to me:

val, err := someFunc("foo")

if err != nil {

handleError(err)

}

PHP

The good

Easy language to start with: PHP has been my first programming language, and I have built many things thanks to it.

Easy to deploy: with Node.js, Ruby, Python, Elixir, you have to set up an application server to make your website available on the internet. PHP makes it incredibly easier just by using Apache or NGINX.

Rich ecosystem: just like JavaScript, many developers have built incredible things out of this language.

Quick prototyping: Like Node.js, it allows us to build an MVP or a POC in just a few hours.

It just works: PHP sometimes feels like the spiritual ancestor of Node.js. You can write some code in it, and it just works without any major problem. The same wouldn’t apply in OCaml, Haskell, Elm, and other strongly typed languages, where you actually spend more time thinking about how to write the code than actually writing it.

The bad

.htaccess: I still can’t find a single reason why I should use this file. Write a typo once, fuck up your website forever, thanks to the browser cache.

Module system: PHP itself doesn’t have a proper module system. You need to include() (read: copy, and paste) entire files into another PHP source file.

You can avoid using PHP’s OOP features, but this will force you to adopt the OOP approach.

Also, all regular functions are accessible from the global scope (if you’re not using namespaces).

Bad design: there are several design errors in the language itself, such as:

trigger_error can’t be handled using try/catch .

can’t be handled using . Doesn’t support dynamic scope.

Static variables inside instance methods are not instance-scoped. That means that once you set a variable, it is set as a global variable for all the instances.

Integer byte sizes are different depending on the operating system.

and so on…

JavaScript-style nonsense: just like JavaScript, the language has some serious nonsense:

"foobar" == 0 is true, "foobar" == true is true, but 0 == true is false

is The following code breaks the ternary operator:

<?php

$initial = 'M';

$name = (

($initial == 'M') ? 'Mitch'

: ($initial == 'K') ? 'Kevin'

: ($initial == 'J') ? 'John'

: ($initial == 'A') ? 'Andrew'

: 'unknown');

echo $name; // Andrew

?>

Doesn’t support Unicode: the PHP committee is still discussing supporting Unicode natively. PHP 7 introduces the Unicode escape syntax

Syntax: I find procedural PHP hard to read. OOP PHP makes a bit more sense, maybe because it’s more organized. Have you tried reading the WordPress source code?

Bad features? Rasmus Lerdorf once said, “We’d rather have an ugly feature than not having a feature at all” (source)… well, I do disagree.

I mean, you can say that if you’re building a blog, an MVP, or other stuff, not a whole programming language.

Software correctness > community-wanted features.

Elixir

The good

OTP: the Open Telecom Platform has everything you need to create massively scalable soft real-time and distributed systems.

Performances: Elixir's performances are outstanding. When compared to Java, a single function may be a bit slower. But once you try to parallelize and scale horizontally, Elixir performances will easily overcome Java.

Metaprogramming: Elixir metaprogramming features are outstanding.

Syntax: its Ruby-like syntax is a pleasure to read and write.

The bad

Dynamic typing: Elixir is a dynamically typed language. That means that you’re missing the strong typing advantages that you can find using Haskell.

Given that Erlang engineers are brilliant people, they’ve to build Dyalizer, which is a “static analysis tool that identifies software discrepancies, such as definite type errors, code that has become dead or unreachable because of a programming error, and unnecessary tests, in single Erlang modules or entire (sets of) applications.”

It is a native module of the Erlang VM, so you don’t need to install any third-party library for that.

Magic: Elixir metaprogramming capabilities sometimes can hide the way a program works behind a macro.

Parenthesis: they are optional, but Elixir requires them most of the time. I prefer the Haskell way of handling parenthesis.