musicmatzes blog


This is a reply to the article published by Drew DeVault called “Rust is not a good C replacement”.

First of all, let me say that Drew is one of the people out there on the internet whose opinions I highly value. Indeed he is one of the people I try to read and listen to regardless of topic, because I think he is one of the people that deserve unconditional attention.

Needless to say that I've also read his latest piece “Rust is not a good C replacement”. I have to admit I was shocked at first, but after a bit of cooling down (and doing the dishes), I can see where this comes from.

And I have to disagree.

But let me start with my background – because that might be important for you, dear reader, to classify this article.

My background is mostly hobbyist programming. I did a few years of C, probably a few 100kloc, not more. I also do rust since about Rust 1.5.0 (2015-12). I started a job where I expect to write C and C++ professionally about 1 month ago.

So, I do not have a background like Drew with probably millions of lines of C, but I guess that I have a bit more experience with Rust – I wouldn't say that I'm a Rust professional, but I would consider myself a “Advanced Rust Hobbyist”.

I'm also not as skilled in writing blog articles or even with the english language, so keep that in mind when reading this.

I am not a big fan of statement-by-statement replying to an article, but I guess for this type of article it is good enough.

First of all, Drews initial statement that Rust was designed by C++ programmers: Yes, I absolutely see that this is true. Nevertheless I have to say that these C++ programmers started developing Rust because C++ was too complex and too error-prone in what it did and how it did it. Rust is far away from the complexity C++ gives us in terms of language features! From the top of my head, we have

  • A full-blown OOP programming paradigm, including
    • Overloading
    • “friends”
    • (multi-)inheritance
    • abstract classes
    • partly and fully virtual functions
    • pointers and references
    • implicit conversions
    • Copy/Move constructors
    • Dynamic and static polymorphism
  • Manual memory management
  • Template Metaprogramming / Generic programming
  • operator overloading
  • Lambda expressions
  • Exceptions

in C++, whereas in Rust we only get

  • Dynamic and static polymorphism
  • operator overloading
  • Lambda expressions
  • Generic programming[^1]


You might consider this list cheated as Rust is not an object oriented language like C++, but an imperative one like C. That is very true. Nevertheless it is one reason why the cognitive load a C++-Program requires one to handle is much higher than an equivalent (as in features of the program) Rust program!

Drew claims that the values of C and C++ programmers are incompatible and I would agree with that. But that does not (have to) mean that a C-programmer and a Rust programmer do not have the same values. It is true, though, that Rust can excel at a lot of topics that C++ covers, but it also empower programmers that do not feel comfortable writing good C code to write their software. And that in a safe and at the same time performant language while not being overly blown up.

Further Drew compares C, C++, Go and Rust by their complexity, measured with features introduced in the language over the years. I am really sorry to say this here, Drew, but we are used to much better from you! You say that this approach (bullet points/features listed on wikipedia vs. bullet points in articles and release notes) is not very scientific, yes. But not even to mention the years these languages were released! For the record:

I am not saying that this disproves your statement – it even supports it! But I do say that comparing based on features per year/release/whatever must include a statement about how old these languages are, even if it is just for showing the reader about what timeframe we are talking.

So, Rust is a relatively young language and yes, it has added a lot of features and therefore can be compared to C++ much better than it can be to C. But saying that a 10-year-old C programm might even compile today and everything might be okay but not so much with Rust is just ignorant of the fact that Rust is not even that old. Having a Rust program that is one year old still compiles fine today (assuming it didn't use a compiler bug) and does not “look old” at all! Rust has a big infrastructure for doing regression tests and for being compatible with older programs.

As you say, out of the way with the philosophical stuff and lets get down to the facts.

C is more portable. But as mentioned before, C is almost six times as old as Rust. We'll get there!

C has a spec. Yes, and I completely hear you on this one. Rust does not (yet?) have a spec and it really is a pain-point. I want one, too! Maybe we'll get there at some point. By the way: Does Go have a spec? It seems like it, but that rather looks like a language definition and I doubt that this is what Drew meant when talking about “a spec”, is it?

C has many implementations. Yes and how much trouble has it been because different compilers do different things on undefined behaviour? Too many. This is where Rust tries to solve a problem: Get a language where undefined behaviour is not allowed or at least as minimal as possible, then we can have a spec for that language and then we can have different implementations. Time will tell whether we can get there.

C has a consistent & stable ABI. Point taken. I do not argue about that.

Cargo is mandatory. Yes, another point taken. I again do not argue.

Concurrency is generally a bad thing. This statement gives me the impression that you did not yet try Rust, actually. Like in a big (and possibly multithreaded/concurrent/parallel/whateveryoucallit) environment. You say that most software does not have to be parallel and I fully agree on that – but if you need to be parallel, I'd rather chose Rust over Go, C or C++. Having the safety guarantees Rust gives me allows normal people (and not Rockstar-programmers) to write software that can be massively parallel without having to fear about deadlocks and other ugly things you get with other languages.

It is still true that bad design decisions are possible and might result in bad software – but that is true for every language, isn't it? And I'd rather like to have a bad program that gets the job done because it can be statically verified that it does than a program that crashes because I ran into a bug that was introduced by bad design decisions.

The next paragraph Drew writes makes me really, really sad. Fullquote:

Safety. Yes, Rust is more safe. I don’t really care. In light of all of these problems, I’ll take my segfaults and buffer overflows. I especially refuse to “rewrite it in Rust” – because no matter what, rewriting an entire program from scratch is always going to introduce more bugs than maintaining the C program ever would. I don’t care what language you rewrite it in.

This gives me the impression that Drew was hit with “Just rewrite it” too many times. And I completely agree with you, Drew, that you should indeed not rewrite it in Rust just for the sake. Nobody should ever rewrite anything in any other language than what “it” currently is written in. I hate these people that actually say things like that (if it isn't for trolling, but I have the uneasy feeling that Drew was hit with real “Just rewrite it”ers and not just trolling).

I do not say that the points Drew shows are false.

What I do say is that the initial assumption that Rust is there to replace C or C++ is, in my opinion, false. It is certainly meant to get things right that C++ got wrong – and it is certainly there to replace the C++-Monster that we call Gecko, because Mozilla is exactly trying to do that! But it is not there to replace all C or C++ code ever written because of some stupid “Hey we can do X better than your language” bullshit!

Also, the statement that Rust might end up as Kitchen-Sink like C++ and die with feature-bloat is one that concerns me because I do not want Rust to end up like C++. It certainly is not as complex as C++ and we (as in “the Rust community”) have a lot of work to do to not end up with feature-creep – but we are also certainly not there yet. But I definitively see where this statement is coming from.

The title of this article is “Rust is one of the best C replacements we currently have” – and I stand by this. But I also think that it is false to say that anyone has to replace C or that Rust is necessarily there to do so.

There are domains where you might want to rewrite C code, if you have the time and resources. But I'd rather advice against it[^3]. Improving existing code is always easier than a rewrite of a program and rewriting software does not improve the value of the software or even make customers more happy. Rewriting software is IMHO only legit in two cases:

  • It makes you happy because you're doing it for fun
  • It makes your boss happy because he ordered you to do so (for whatever reasons, may it be speed, resource usage, customer request or whatever)

But just for the sake of it? Nah.

I see where Drews article comes from and I see why he thinks like he does. I greatly value his opinion and thoughts, and that's why I took the time to write this article.

I see that we (as in “the Rust community”) have a lot to do to make more people happy. Not as in making them Rust programmers, because that's not our goal, but as in showing them that we do not want everything to be written in Rust and that it is just trolls that request a “rewrite in Rust”.

We do value friendlyness and kindness – let me state explicitely that this does also include other programming-language-communities (and all other communities as well)!

Trolling does not help with that.

[^1]: Yes we have generic programming in Rust. I'm not a professional regarding C++, so I cannot say whether they are comparable in this regard. [^2]: Some might say that we have manual memory management in Rust as well. That might be true by definition, but not the way I meant it: In C++ we can allocate something on the heap and then forget it. We have to try really hard to do that in Rust, though! [^3]: In fact I might get into the situation where I have to rewrite an application in my job, but I'd rather rewrite it in the same language than switching languages just for the sake of it!

tags: #open-source #programming #rust #c #c++ #cpp

Why can't we do

fn foo(i: i32, j: i32) -> i32 {
    i + j

fn main() {
    println!("{}", foo((1, 2)));

in Rust?

The idea

First of all: I don't know much about what is going on in rust-compiler-land, hence I don't know whether this is technically possible or even in progress already. I'm simply writing down some thoughts here.

The idea, or rather the question, is: Why can't we map tuples on arguments in Rust? The code from above shows exactly what I mean by that: Why is the compiler not able to unpack the tuple and pass it as list of arguments to the function?

It would be really cool if it could do that. The usecase is something like this:

some_possibly_failing_fn() // -> Result<_, _>
  .and_then(|res| (res, some_other_failing_fn()?)) // Result<(_, _), _>
  .map(PartialEq::Eq) // Result<bool, _>

for example. If mapping of tuples on arguments would be possible, one could write code like this, where failing functions are chained and operators and functions can then be called on the results of the failing functions.

Currently, one has to write it like this:

some_possibly_failing_fn() // -> Result<_, _>
  .and_then(|res| (res, some_other_failing_fn()?)) // Result<(_, _), _>
  .map(|(a, b)| a == b) // Result<bool, _>

or, because it is solvable with one line less:

some_possibly_failing_fn() // -> Result<_, _>
  .and_then(|res| Ok(res == some_other_failing_fn()?)) // Result<bool, _>

You might think that the overhead for that convenience is rather low and thus it is not really beneficial to have such a functionality in the rust compiler.

That is true. But there are great possibilities of API design if this is mapping of tuples on arguments are possible. For example, one could write an extension to the Result type which extends tuples. Think of something like that:

// assuming:
// some_possibly_failing_fn() -> Result<T, _>;
// some_other_failing_fn()) -> Result<U, _>;
// even_other_failing_fn()) -> Result<W, _>;
// yet_another_failing_f()) -> Result<V, _>;
// check_results(T, U, W, V) -> Result<bool, Error>;

some_possibly_failing_fn() // -> Result<T, _>
  .and_then_chain(|| some_other_failing_fn()) // Result<(T, U), _>
  .and_then_chain(|| even_other_failing_fn()) // Result<(T, U, W), _>
  .and_then_chain(|| yet_another_failing_f()) // Result<(T, U, W, V), _>

From an API-design standpoint, this is plain awesome.

Lets compare that to what we have to write today to do this:

some_possibly_failing_fn() // -> Result<T, _>
  .and_then(|a| Ok((a, some_other_failing_fn()?)))
  .and_then_chain(|(a, b)| Ok((a, b, even_other_failing_fn()?)))
  .and_then_chain(|(a, b, c)| Ok((a, b, c, yet_another_failing_f()?)))
  .and_then(|(a, b, c, d)| check_results(a, b, c, d))

and that's really not that readable.

From a technical point of view, the compiler is able to verify the length of the tuples and thus is able to check whether the tuple actually matches the number of parameters of a function.

As said, I'm not that much into the development of the language, thus I don't know whether there are other things that prevent this, though.


After posting this as a question on and getting some nice replies with explanations why this cannot be, I conclude:

It is not possible to do it in a way that does not yield weird edge cases, ugly implicit conversions and other weirdness we really do not want in the language.

But I learned something, and that was worth it!

tags: #tools #software #c++

Today I learned that the new C++ standard (C++17) has std::variant – but no pattern matching.

Variants and how they work

Variants or “tagged unions” are a special form of data type. They describe an abstract thing which could be one concrete thing or another concrete thing. Variants are available in a lot of languages, including and not limited to ML, Haskell, Algol 68, Pascal, Ada, Rust and even C.

With C++17, the C++ standard was extended to have the std::variant generic type, which is basically a “C union on steroids”.

(To the C++ greybeard programmers reading this: I know this is technically not right, how it is implemented and how this works is very different from an actual C union, but what it is used for is basically the same, so please don't yell at me for this statement.)

A std::variant can be used to express, for example, a return value of a function which might have failed. Maybe you think “Hey, that's what exceptions are for” – no, that's not what exceptions are for, though a lot of programmer use them like this. Exceptions are for unexpected behaviour of your program. If you're writing a terminal calculator, an invalid input is an expected failure. An unexpected failure would be that you cannot read from stdin!

In cases where expected failures happen, a std::variant can be used to return a “I failed doing my job”-value.

Why you need pattern matching

Pattern matching can be used to destructure variants efficiently (as in code, readability, extendability and thus maintainability) to access their inner values.

For example, in Haskell, one can destructure a variant like this:

data Result = Ok | Err

explainresult :: Result -> [Char]
explainresult Ok  = "All right"
explainresult Err = "Ouch"

Here, we define the variant Result and a function explainresult which destructures the variant and returns a string based on the passed variant. Of course, variants can hold data and this data can be accessed then.

As a matter of fact, variants are incredible useful in everyday programming and so is pattern matching for destructuring them.

What C++17 offers instead of pattern matching

C++17 does not offer pattern matching. Why? I don't know. But it really should have, because the way this issue is solved in C++17 is painful: std::visit is used for imitate pattern matching.

On the first glance, the following code looks rather okayish (well, it is still C++, right?):

std::vector<std::variant<char, long, float, int, double, long long>>
           vec = {5, '2', 5.4, 100ll, 2011l, 3.5f, 2017};

// display each value
for (auto& v: vec){
  std::visit([](auto&& e){std::cout << e << " ";}, v);

But this is simple. What if we want to actually do something with the element based on which type it has?

Well, not so nice: We have to design our own visitor and equip it with the functionality:

struct Visitor {
    void operator()(const string& s) const {
      // ...

    void operator()(const int n) const {
      // ...

While having a dedicated visitor which can be passed around is rather nice, having it as the only option for pattern matching is hell.

Also, the standard library does not provide a helper for building a visitor object from a list of lambdas!

All in all: Is the whole thing a step into the right direction? No. It is rather a stumble into the rightish direction. Nothing more.

A friendly advice from a non-Cpp programmer

Take a grain of salt. I'm not a (C++) professional, hence this might not reflect the opinions of the broader community. Also, the following might get some people really angry. But I don't care.

Don't use C++ for new projects!

I know C++ is a heavy target and the standard is backwards compatible and a lot of people count on the standards committee to get this right and yaddayaddayadda. From my point of view, C++ tries to catch up. This is, of course, nice. But at that speed, other languages will innovate much faster and better and C++ will slowly die. That's one reason I would never ever use C++ for a new project.

tags: #tools #software #c++

I could not think of a better title, I'm sorry.

These are notes how to create a kernel which can be booted in qemu and pass a drive to it which has loadable kernel modules.

The idea

I wanted to play around with the linux kernel and write a minimal filesystem inside the kernel tree. I wanted to boot the kernel in a QEMU, as I do not want to mess with my running kernel.

Here are the steps I did (on a debian VM I run on my universitys infrastructure).


sudo apt-get install build-essential bc git gcc
git clone git://
cd linux
make x86_64_defconfig
make kvmconfig
make menuconfig

The last step brings up the kernel configuration interface, which I used to enable SATA (Device Drivers -> Serial ATA and Parallel ATA drivers (libata) -> Generic ATA support) support which is needed to be able to mount a device into the qemu instance, where we can put things to play around with in the VM.

I then did a make -j 16 (if you have not 8 cores, use a lower number).

While the kernel compiled, I created a busybox initramfs. I used this blog article for how to do it. I'll dump in the commands from the blog article, for detailed information, go and read it, it's a really good article. I didn't do the speed-optimizing things, as the QEMU boots fast enough for me (~3 seconds).

(I used the latest busybox, but I don't see why it should work with the one from the article, which is about two versions old)

curl | tar xjf -
cd busybox-1.23.2
mkdir -pv /tmp/obj/busybox-x86
make O=/tmp/obj/busybox-x86 defconfig
make O=/tmp/obj/busybox-x86 menuconfig # See below why
cd /tmp/obj/busybox-x86
make -j 16

# it does not install in your system, so you can execute this without fear
make install

mkdir -p /tmp/initramfs/x86-busybox
cd /tmp/initramfs/x86-busybox
mkdir -pv {bin,sbin,etc,proc,sys,usr/{bin,sbin}}
cp -av /tmp/obj/busybox-x86/_install/* .

# now edit the init script
vim init

You have to enable busybox build as static binary (with the menuconfig part).

The init script I use:



mount -t proc none /proc
mount -t sysfs none /sys
mount -t debugfs none /sys/kernel/debug

mkdir /tmp
mount -t tmpfs none /tmp

mdev -s # We need this to find /dev/sda later

echo -e "\nBoot took $(cut -d' ' -f1 /proc/uptime) seconds\n"

exec /bin/sh

The init script boots into a /bin/sh. We can now build the initramfs with it:

chmod +x init
find . -print0 \
    | cpio --null -ov --format=newc \
    | gzip -9 > /tmp/initramfs-busybox-x86.cpio.gz

Try it out (1)

Now we can try it out, whether the kernel boots and we get out shell:

# In the kernel tree:
qemu-system-x86_64 \
    -kernel arch/x86_64/boot/bzImage \
    -initrd /tmp/initramfs-busybox-x86.cpio.gz \
    -nographic -append "console=ttyS0"

We should see some output like this:

[    7.170702] Freeing unused kernel memory: 1200K (ffffffff81f55000 - ffffffff82081000)
[    7.171539] Write protecting the kernel read-only data: 14336k
[    7.177328] Freeing unused kernel memory: 816K (ffff880001934000 - ffff880001a00000)
[    7.219360] Freeing unused kernel memory: 1116K (ffff880001ce9000 - ffff880001e00000)
mount: mounting none on /sys/kernel/config failed: No such file or directory
mount: mounting none on /tmp failed: No such file or directory

Boot took 7.33 seconds

/bin/sh: can't access tty; job control turned off
/ # [    7.630681] input: ImExPS/2 BYD TouchPad as /devices/platform/i8042/serio1/input/input3

/ #

(Yes, the output is slightly messed up... but hey! We just booted a linux kernel in a QEMU!

Load the kernel module

We can now create a kernel module in the linux kernel tree:

# In the kernel tree
git checkout -b my-module
mkdir fs/iamcoolfs/ # because I like filesystems
cat <<EOS > ./fs/iamcoolfs/Kconfig
config COOL_FS
        tristate "COOLFS support"
          Private FS for playing and learning FS programming

          This will definitively eat everything you put into it.

cat <<EOS > ./fs/iamcoolfs/Makefile
# Makefile for the linux mb-filesystem routines.

obj-$(CONFIG_MB_FS) += coolfs.o
cat <<EOS > ./fs/iamcoolfs/coolfs.c
#include <linux/init.h>
#include <linux/module.h>

static int __init coolfs_init(void)
        pr_debug("cool module loaded\n");
        return 0;

static void __exit coolfs_fini(void)
        pr_debug("cool module unloaded\n");




This creates all the files we need for a minimal module. Because I like filesystems and I really want to implement a minimal filesystem, I chose to create the files in ./fs, but I guess it shouldn't matter.

Make sure you adapt the fs/Kconfig file to find your new module! Put

source "fs/coolfs/Kconfig"

into it.

Now you can execute make menuconfig and find the configuration option for your new module. We can also simply make M=fs/coolfs to build the module. Now we create a (ext2) disk where we can cp the module to, so we can mount that disk into our QEMU and use the module there:

dd if=/dev/zero of=/tmp/disk bs=4M count=100
sudo mkfs.ext2 /tmp/disk # you could also try ext4, for example
mkdir /tmp/disk-mount
sudo mount /tmp/disk /tmp/disk-mount
cp fs/coolfs/coolfs.ko /tmp/disk-mount/
sudo umount /tmp/disk-mount

Try it out (2)

And when we boot our QEMU now with -hda /tmp/disk, we can find /dev/sda in the booted instance and mount that:

# In the booted VM
mkdir sda
mount /dev/sda ./sda
ls sda

Happy FS dev!

tags: #c #linux #open source #programming #software #testing #kernel

This article is about the annoyance of programming language tutorials. First, I will argue why learning new programming languages always feels a bit like a pain to me. And then I will tell you why learning Rust was different.

I know a few programming languages. I've done things in C, Ruby, Java, Python, PHP, C++, Bash, Lisp (Racket, actually), Haskell, LaTeX, Nix, Make, Lua* and JavaScript*.

*: Only a bit, but still enough to say “I've done things in this language”

When I started learning programming, I learned Java and shortly after that Ruby. Both languages have their oddities, but besides their overall concept (imperative programming and object orientated programming) they are both rather easy to learn. After that I learned C. Learning C was a new world for me back then, as I only knew object orientation. I cannot remember which resources I've been using learning C, though I remember it was a pain. I had a good friend helping me, which was awesome, though I struggled a lot with the new concept.

After learning C, I did a fair amount of PHP. Learning PHP was simple (I actually did it in one weekend and a few thousand lines), though it again was a pain. It was a pain because of the tutorials and resources. And that's the point I want to discuss here.

All other programming languages I've been learning so far were painful to learn. Not because of their concepts (see Haskell, functional programming at all), but because of the resources. Haskell is a really good example here. There is exactly one resource I enjoyed while learning Haskell, and that's “Learn you a Haskell for great good”. And why? Because it takes your hand and shows you the new world. It is good because the concept of functional programming is new for most people reading this resource. Learning JavaScript, Bash, Lua or Python sucks because you already know what an object is. You know what a function or method is and you know that the basic syntax for arithmetic is the very same as in the languages you've been using by now. But all tutorials expect you start from zero – which is fine if you're actually starting from zero, but most of the time you're not. After learning Java and Ruby I understood what OOP is (actually not after learning Java, but after learning Ruby, because Java isn't a fully object oriented language in my opinion).

So, learning Haskell was kinda amazing. Learn you a Haskell is a really great book and if you want to learn Haskell, you really should read it. But what was even a better experience was learning Rust.

So why is that? It is because Rust is a new concept and the old concept (imperative programming). Learning Rust is not like learning Python after learning Ruby. It is like Learning Haskell after learning Racket. The concept behind the language is kinda the same, though it is different in most details.

Plus, the Rust tutorials and resources are freakin' awesome. Let me repeat that. The tutorials and documentation of the tools, libraries and everything, the resources on how to do things, are awesome!

Every documentation for each library looks exactly the same, which is a huge advantage over other languages library documentations. cargo, the Rust build-tool builds the documentation locally for you, if you want that. So working offline after you fetched the dependencies or your project (also via cargo) is no hassle. Building a new project with cargo is absolutely painless, its literally just executing a command, editing a textfile and executing another command (setting up the project, writing down dependencies and meta information about the project and building the project, which fetches the dependencies).

So really, if you want to learn a new programming language, check out Rust. I haven't even talked about its language features, and I will not, as this is not the goal of this article. This article is about resources and tutorials. And my conclusion is:

All programming language tutorials suck. Except the Rust language tutorial. tags: #programming #open source #bash #c #c++ #haskell #nix #racket #rust #shell

So I'm in my praxis semester at the moment, and I have to work with fastcgi++, a C++ library for fastcgi. And it is a nightmare! Here comes why...

So first, the codebase of fastcgi++ is a mess. Code snippets like

bool foo = someFunction();
if (foo) return true;
else return false;

are everywhere. You really don't want to read that kind of code. And yes, you have to actually read this code because there is no documentation on how to use the library! There is a wonderful doxygen-generated API documentation, but that does not help you because, yeah, you know the types and the interfaces now – lucky you! How to build a fastcgi module with them – figure it out by reading through the codebase!

Secondly, you are not allowed to define your custom accept() handler. You have to inherit from a Request class template and you have to implement the virtual bool response(void) = 0; method. Okay, no problem, I can do this! But then, you want to start accepting requests. You do this by creating an instance of a class called Manager:

Fastcgipp::Manager<MyRequestInheritedClass> man();

or something like this (this is no real code, I just want to demonstrate how it looks like). The manager accepts one connection (through many layers of abstraction, actually), creates an instance of your request class and calls response() on it.

Well, that's not a problem, is it? Well, it gets to a big problem if you want to be able to handle multiple requests at once, speaking of multithreading/concurrency here. It is a huge mess! My codebase exists of three classes, actually. A ThreadedRequest class, a BlockingQueue where requests get stored thread-safe and a RequestDispatcher which is a singleton which runs several worker threads. These worker threads take the requests out of the queue and process them if they can.

The ThreadedRequest class puts itself into the queue, which is a member of the RequestDispatcher singleton instance. The problem is not that it is unnecessarily complicated to build these 1-N multiplexing thing, but that the library provides an interface which enforces you to couple your classes realy tightly. And this is freaking bullshit.

So, finally: I'm building a wrapper lib around fastcgi++ to be able to handle requests in a concurrent way. And it sucks. But it works.

So, my conclusion is: Stay away from this bullshit library. And even from fastcgi if you can. Apache for example offers a way to write modules, so you can simply write your own module for apache if you need to – which is faster anyways!

If you have to use fastcgi, consider writing your own library!

tags: #c++ #linux #server #open source #programming #software

Some of you might know my little project rate. It is a bash script to collect a database of things you want to rate.

What this means and why I started to reimplement in C++ – read it here!

So I started to write this application because I wanted to keep track of animes I already watched, Bands I like but do not listen to that often and so on and so forth. What the application does is really simple: You can enter notes about a certain thing (in your favourite text editor, which is vim for me) and attach tags to it and put it into a category. Then you can give it a rating. The rating can be everything, from simply numbers to text to whatever you like. But it is supposed to be a number between 1 and 10, of course. That's also the way I use it.

So how does it work? Well, that's really simple: The “rate” script creates a directory structure in ~/.rate/collections/, whereas a folder is a “collection” of things and a file is a rating. So, I have something like “movies/animes/” as collections (they are nested, of course) and then a file for each anime I watched. The filename is generated from the title I passed “rate” when creating the entry. The file also contains a “header”, which includes a unique ID (which you really should not change), a list of tags, the title (the filename is the title, too, but as on linux you shouldn't include whitespace in file names, it is not the title as you typed it) and a rating of course. Custom fields could be added to the header, but this feature is not implemented yet. After the header, you can put your description.

That's basically it. “rate” provides some features to search this database, for example you can grep for text in your entries, you can view your entries, you can list your entries and you can attach more text to your entries or edit them. As everything is git controlled in the ~/.rate directory, you can reset if you (or the script,...) messed up somehow.

There's no release by now, as it lacks of some features by now. For example I want to be able to search for entries with a certain rating or within a certain range of ratings. I also want to be able to search for entries with aspecial set of tags or within a certain collection (I can do this, though) special set of tags or within a certain collection (I can do this, already)! After these things are implemented, I will release my first version, which would be 1.0 then. And, of course, I will package it for NixOS!

So why C++

Well, I have to learn C++ for my praxis semester. That's basically it. I wanted to learn a new programming language for a relatively long time, and that's my approach on learning C++. I was able to implement some things, but not yet to run an application. My first step would be to parse my already existing entries. Hope that works. As I stated in the github repos file, I do not want to use any frameworks for this. No Boost, no Qt, no other libraries. I just want to use plain C++11 (or maybe 14 in future, not sure about this, though).

Also, C++ gives me way more posibilities when it comes to features. I can refactor things really easy and maybe the C++ implementation will continue to live whereas the bash implementation will die at some point. Who knows? The point is, the bash implementation implements a file format which is

  1. really simple
  2. forward compatible

The file actually looks like this:

key = value
other = value
another = another


and that's basically it. The three dashes mark the end of the header and everything before the header is a <key> = <value> list, whereas each line is only allowed to contain one key-value-pair. The value can be a list of values, for example a list of Tags whereas tags are seperated by a whitespace character (space) or a string, such as the title is. The bash implementation “knows” which key has to be which value and the C++ implementation has to know this, too, of course. But that's it.

The commandline interface of the application needs some work, though. Maybe it will get some REPL-like interface later on, or maybe something more interactive. By now, it is simply an interface where you can do one thing per call. I have no problem with that and I'm planning to keep backward compatibility with the bash implementation even if this one is not even released! It is fun to write such a tool and I really like doing it.

Also, it is not a that complex thing to implement and that's a huge point to me. I don't want to spend months and months in implementing a thing which only one or two people on this planet actually use. For bigger projects, I contribute to open source projects. That's a better way to produce large-scale software, IMHO.

tags: #bash #programming #c++ #linux #shell #vim

I have a problem. I want to write a small application. It should be a commandline application, but maybe I want to extend it later with a GUI or even a web interface. But I don't know what language to write it in.

This article could also be named “Which is the right tool for the job?”

The idea is simple: I want to write a journal-application, where one can take notes, tag them, query the journal for entries, optionally provide filters before printing them to print only some of them and so on.

I want to be able to encrypt them with gpg and I want to write posts to the journal with vim. I want to be able to configure these steps, of course, so I can use a certain key for encrypting the journal or maybe another editor (for these emacs lovers out there).

It should be designed to be extensible, so I can add a GUI or web interface later on. Or maybe a tex output, so I can compile a PDF out of it or something. Posts should be written in standard markdown, so this wouldn't be a big deal.

But I don't know what language to write it in. The languages which I can or would choose from are:

  • C
  • C++
  • Haskell
  • Rust
  • Java (not really...)
  • Scala (not really either, it's still JVM)
  • Ruby
  • Python (by extending jrnl)
  • Racket
  • Lua
  • Bash (I really don't want to write it in bash, but it's still a possibility)

As you can see, the first four languages are compiled languages, then Java and Scala are (lets call it) Semi-Compiled languages and the others are scripting languages. All of these languages have certain advantages over others.

The compiled languages

... have the advantages that they are fast. Haskell and Rust also have the advantages that if the compiler does not fail compiling the sources, the program just works ™.

Also, learning C++, Haskell or Rust would be a really great experience and may be beneficial later in a job or something.

The semi-compiled languages are also (kind of) fast, but they are JVM-languages, so I won't look into them here...

The scripting languages

Writing the application in a scripting language would have some other advantages: They would be much more flexible and I'd be faster writing the application (compared to Rust or Haskell, which I would need to learn with the application). I don't need to learn Ruby, I know a fair bit of Racket and I guess I can get productive with Python or Lua really fast.

Bash is another option and I'm actually an bash script for an almost similar job right now. I could simply extend this script, that would be an option, of course.

So which is the right tool for the job?

Can you tell me? I don't know which tool is the right tool for the job. After all, I don't think I should write such an application from scratch. So, for me, there are two options left: Extending jrnl, which is an Python script, or extending diary (I do not even find a link for this anymore), which is a bash script. Extending the bash script would be an easy job, I guess. But it wouldn't be as flexible as the Python tool is already. tags: #bash #c #c++ #haskell #programming #racket #rust #shell #tools

I already wrote about the project me and some friends at my university are currently doing. One of my team mates came up with the idea of porting the codebase from C to C++, yesterday the appropriate issue was opened Yesterday, to discuss it. I'm not sure what to think.

The idea is to port the codebase as soon as possible to C++. I do not like this idea entirely, as I think the port should be done after the project phase, but not within. I consider myself at a newbie-like level when it comes to C++ and I think other project members feel almost the same, maybe better, but not on an expert level or whatsoever. Given the fact that we're already running out of time, I think a port of the (30K LOC) codebase would quite take some time and would cause the project to be delayed even more.

So I'm trying to push back on that part. A port after the project phase would be another question, which I want to talk about here.

First of all: I don't think a port to another language is required, as I consider the codebase as very clean and carefully designed. The architecture is good, the code is well documented, the abstractions are clearly defined. A port to another programming language would have a certain level of impact on this, but I think we are able to handle that. I see the improvements which could be made by a port to a OOP(-like) language, though.

Having inheritance build into the language, having a template-like system in the language and having methods, virtual functions and the like would cause some redesign but also some improvements.

My project mate suggested C++ as language. Now, the careful reader knows that I don't like C++ that much. Some of my points are maybe valid, some not. But well, this is a very opinion-based topic, and I won't go into further detail or discussion about that topic here. What I think, though, is that it would be nice to port to a language which gives us more power (simplifying to the terminus “power” here to refer to possibilities to do abstractions, building complexity and the like) and security. I think C++ gives us more power about the code, which is very good. I don't think C++ gives us more security, meaning secure code. I think one can very simply do the same mistakes in C++ as in C, speaking of semantics of the code. For example you can create data races, thread related problems or memory corruption in C++ as well as in C.

That given, I consider C++ as an improvement to the code, but not the best possibility. My opinion is currently that a port to Rust would be a much better option, as Rust gives us memory safety, prevents us from doing nasty things with memory, including all the thread stuff. Given the fact that none of us is able to write Rust on an expert level by now, the question of doing the port within the project phase or after is answered automatically. Also, Rust is not stable yet. I would at least wait for version 1.0 of the Rust language before doing the port, possibly saving some time of Rust-to-Rust porting.

I still don't think a port is necessary and I really like the code we produce. I can see the advantages over staying in C, but for me personally, the disadvantages overweight by now. This may change in future, but for now and for the rest of the project phase, this is my opinion on the topic.

The discussion on github is not done yet, of course. I will carefully propose my opinion there, as this has become a very explosive topic by now. This article was just written to be a short overview over the topic and also to be a summary of my thoughts.

tags: #programming #c #rust #c++ #software

This is the third part of my series about C++.

After some serious discussions with several people, I came to a conclusion. Well, not really a conclusion, as it was clear from the beginning of the series or even before, when I started to learn C++ at my university, but a point where I can say that C++ is not as shitty as I thought before.

Well, even the word “bullshit” isn't the right terminus.

C++ does some things which seem to be really really weird when you first start learning it. After all, I wouldn't suggest it as first programming language to a newbie!

I still consider the syntax of C++ as bloated and not really helpful in certain ways, as (for my taste) one can hide too much of the relevant stuff. One cannot directly see what's happening in a piece of code without knowing the stuff around the code, the infrastructure or at least the types of the variables. Other languages solve this “problem” much better.

I had a discussion with a friend of mine who is really into C++ and he explained the benefits, which I fully understand. I also had a discussion with a friend who is at most a C++-Critic. Both of them made valid points.

After all, it is a matter of taste whether you like C++ or you don't. I do not like it. I can see its benefits over C, but I consider other languages as better. C++ has a historical background, of course. I don't want to ciritcize this, but I think there are other languages which adress the problems C++ addresses much better today.

I'm speaking of D, Rust, Go and the like, of course. I also consider languages like Haskell, Erlang, the whole Lisp Family and the JVM stuff as better solutions to most problems. Not only that I consider them as easier to learn, but also much easier to maintain and less cluttered with language elements one has to understand to work on an existing codebase. tags: #programming #c++