Opinions on some technologies

Back to homepage


Programming languages

C

#include <stdio.h>
int main()
{
	puts("Why hello there, neat little language!");
}

C is a really elegant and simple, yet powerful and unforgiving language. Anyone who's programmed in C knows that it often takes a bit more time to get things working than in other languages, yet the performance gain and low-level library support is amazing. The fact that it's so simple means that there's very little linguistical cruft of the kind that's visible in C++.

It's a shame that the C standard library doesn't support basic things like directory structures, although POSIX of course adds support for all that jazz. Unfortunately linking against a POSIX library means getting your code running on non-POSIX outcast-platforms is a bit of a pain, although on Windows even MinGW adds support for pthreads and things like dirent.h.

C99 adds really useful features to the C language. I use intermingled declarations all over the place, as well as for-loop initial declarations. Variable-length arrays (VLAs) can be useful for small dynamic stack arrays. Last time I checked though, Microsoft Visual C did not have any support for VLAs, which is sad. It's also sad that VLAs have become an optional feature in C11. stdint.h also adds really useful quasi-portable fixed-width integer types.

On a different note, it's often quite amusing to show people who've just started learning C, or are still getting familiar with it, that the following compiles with gcc's default options:

main(argc, argv)
	int argc;
	char **argv;
{
	puts("hello, world");
}

C++

C++' goals were noble, however its implementation is primitive and strange to the point that it's in a league of its own as far as object-oriented languages are concerned. C++ is the evidence of the fact that complex low-level object-oriented languages can't be pretty. C++11 has worsened this issue by implementing things like "smart pointers" and "move semantics". The latter is a construct infamously difficult to grasp, and is absent from every other language I know, or know of.

C++ also suffers from a lot of design flaws, mostly involving things happening around your back. For instance, what does the following code do?

	vec3 my_vec3;

Without knowing the behaviour of vec3::vec3(), there's nothing that forbids that code from trying to find a counterexample to the Riemann-hypothesis. In virtually any other C-like language it's completely obvious what that code would do: create an instance my_vec3 of type vec3, possibly initialising it to "zero". Nothing more.

Now consider the following snippet:

	vec3 my_vec3 = vec3(0.0f, 0.0f, 0.0f);

This code could also have all kinds of interesting behaviour, because it consists of two non-trivial operations. In most languages there's only one, namely a constructor call: after all that's all behaviour that's clearly visible in that code. In C++ there's two constructor calls, namely the constructor vec3::vec3(float, float, float) and the copy constructor vec3::vec3(const vec3 &), which is implied by the equals sign.

A similar thing happens in code like f(x), where it's legal behaviour for the value of x directly before the function call to differ from the value it has directly after the function call.

C++ should simply have been C99 with inheritance, type polymorphisms, function overriding (not even function overloading!) and templates. Other features like constructors, copy-constructors, destructors, call-by-reference and move semantics are what makes C++ practically unusable as a low-level language, in my opinion.

As a high-level language there are better languages like C# and Python. Both are at least a hundred times better than C++ for high-level development, albeit somewhat slower (C# often not noticeably so).

C#

As a language C# is one of my favourites. It can basically be described as Java and C++: The good bits. It allows for fully-fledged object orientation with garbage collection, as well as fast simple datastructures using struct.

Features that really set it apart are the LINQ libraries and its powerful generics. LINQ basically means that a significant part of functional language functionality (lazyness, essentially) is present. Take for instance the following code:

	var values = someList.Where(x => x < 10)
	                     .Select(x => x * 2);
	foreach (var value in values)
		...

The above example is trivial: given a list of numbers it first discards the ones that are not less than 10, then it multiplies all of them by two, without affecting the original list, and not evaluating the values until they are needed.

In C, C++ or Java such a task would take one or more loops, becoming even more cumbersome if a more complex operation is needed. In C# and most functional langauges the support for dealing with collections is incredibly convenient.

C# also supports property syntax. This provides a way to circumvent common boilerplate code used to have a public getter but a private setter wrapped around some field. In C# the code for this is simply:

	public int CantSetMe { get; private set; }

I understand that in C# 6 these auto-properties now finally have initializers, so that you can now finally give auto-properties an intial value like so:

	public int CantSetMe { get; private set; } = 5;

Some things that are not to like about C# (and .NET in general) are the UTF-16 strings. These are an artifact of Windows using UTF-16 internally. Also the bulk of the code tends to be indented three levels (once for the namespace, once for the class, once for the method). In C I consider three indents the maximum, in C# it's the minimum. Java in this respect does better than C#; it uses a package directive at the top of the file, rather than namespace blocks.

As far as the .NET platform is concerned: it's a shame that it's so tainted by Microsoft, and possible patents concerning WinForms and the likes. The core libraries are very sound.

Java

Continuing this alternating series, I find Java to be somewhat lacking. Don't get me wrong: Java is a fine language, but after you've tasted what C# can do, Java often just feels flimsy and incomplete.

One feature that's utterly broken in Java is its generics. In C# a method called reification is used for generics, in C++ generics are implemented at compile-time. In Java, however, the method chosen is type erasure, which is an insult to the concept of generic types. It means that an ArrayList<T> is really just an ArrayList<Object> with a different name. This has the awful consequence that primitve types cannot be used as generic type parameters: they have to be boxed. Boxing and unboxing are very expensive operations, adding garbage collection and heap access overhead.

Also the lack of value-types as seen in C# means that besides performance disadvantages, interacting with hardware or external libraries is very difficult. The LWJGL for instance adds class Vector3f, which practically always lives on the heap. Such a type has to be converted to an array of floats in order to be passed to OpenGL functions. Also, in a situation where you need to do thousands of vector operations per second, such an implementation starts to show the disadvantages of heap-allocation and garbage collection.

A feature that Java could've done without is checked exceptions. They basically introduce one of the many instances of Java boilerplate: throws Exception if you're a lazy bad person, or:

	try {
		...
	} catch (WhateverException e) {
		e.printStackTrace();
	}

C# decided it could simply do without checked exceptions, while it manages to produce programs that are just as stable. The reason is that you know where your code might throw exceptions and you handle those cases. If your code throws an exception anywhere else you're screwed anyway, and a central exception catcher somewhere will make sure the program exits somewhat nicely. In practice, I feel as though checked exceptions might cause more of a hassle than the hassle they were meant to solve.

Haskell

Haskell is the first language in this list that has a well-functioning REPL, which is a blessing. It's also evidently very powerful, albeit sometimes somewhat on the ill-performing side of things. I have not completely delved into functors and monads yet, but I'm sure they're powerful. The power of the language can be demonstrated by a function I recently came across, which takes a list of songs and returns their combined duration:

totalDuration = sum . (map duration)

Among my favourites are also these efficient interdependent prime-number and prime factorisation algorithms:

primes :: Integral a => [a]
primes = 2 : filter (null . tail . primeFactors) [3,5..]

primeFactors :: Integral a => a -> [a]
primeFactors n = factors n primes
    where factors n (x:xs)
             | x*x > n          = [n]
             | (n `mod` x) == 0 = x : factors (n `div` x) (x:xs)
             | otherwise        = factors n xs

This can be fun in GHCi:

Prelude> primes
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,
107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,
...

However, the programs I write are usually quite IO-intensive, and functional languages seem to be less advantageous in those scenarios. However, when I occassionaly wander into the world of Project Euler, I usually use Haskell.


Operating systems

Linux

I sometimes call it Linux. I sometimes call it GNU/Linux. Depends on my mood. The whole issue seems to be around the definition of an operating system; Stallman uses the definition operating system = kernel + userland, whereas Torvalds uses the definition operating system = kernel. Both are valid in my opinion, so I don't adhere to a particular one.

GNU/Linux is a really, really, really powerful operating system. The userland is one of the most powerful you'll ever do. With a terminal window on your screen you have the entire machine at your very fingertips, and working is often so much easier and natural than in a GUI. Writing and running a C program only involves starting your favourite editor, writing the program and saving it to main.c, and typing:

$ cc main.c
$ ./a.out

C'est tout! Linux really is a developer's operating system. Command line tools suit most types of development really well. Even gdb can be more powerful than an integrated graphical debugger sometimes. I don't understand how people develop C and C++ on platforms other than Linux.

Unfortunately, driver issues are commonplace. Especially when I used to have a multi-monitor setup, GNOME would sometimes freeze up on me. Luckily, because it's open source and has a really active developer base, such driver issues are becoming less frequent, I feel.

Before I used Linux, I could hardly imagine that my entire machine would consist of gratis open-source software, as is now (mostly) the case. GNU/Linux is the best example of how well open-source software works.

Distributions I've used include Ubuntu, Arch, Fedora, Linux Mint, Antergos and Manjaro. I find KDE a bit too "bulky" and find GNOME, XFCE or Cinnamon nicer to work with.

Apple Mac OS X

I have never used OS X on any machine I own, so any experience I have with it has been on someone else's PC. When I have used it in such an event, I have found that it can do a lot of the things Linux can - but then again, the two are both UNIX-like.

However, OS X is largely proprietary and owned by Apple. These facts do not speak in OS X' favour. I prefer to have the security and freedom that come with open-source programs.

Microsoft Windows

I dislike Microsoft Windows. As a normal user the experience isn't too bad, many people may actually prefer Windows over Linux or OS X simply for its user-friendliness. However, it's interpreted user-friendliness in such a way that there's a fear of anything that is text or terminal based. This often leads to massive development suites whereas with GNU tools there's only a set of simple command line utilities, with some initial configuration.

Anyone who's watched an instance of Microsoft Visual Studio start up knows that the times of going for coffee breaks during compilation have shifted into the times of going for coffee breaks before you even get started. The configurability of the development environment on Linux is also far superior to any graphical development tool in any Windows toolchain. I fail to grasp how any native developer could use Windows comfortably.

I sometimes use Windows 7 to play games that I can't get working in Wine on Linux. I find the centralized idea of the Windows Store in Windows 8 appalling, and I have upgraded (I consider it an upgrade anyway) back from Windows 10 to Windows 7 after seeing the default privacy options. I decided using Windows 10 was not something I wanted to be a part of. Considering Windows 10 was a free downgrade from Windows 7, you're no longer paying for it. And if you're not paying for the product...