Skip to main content

Mike Kreuzer

Revisiting Rust

March 12, 2021

Almost five years ago now in April 2016 I had a look at serialising a struct into JSON in a couple of different languages, including Rust. It feels past time to go back over that & have a look at what's changed with my inexpert eye, because what's changed with Rust turns out to be quite a bit, and so far it's all for the better.

The post, including the Rust code is still there, but before you go clicking on that link, I'll give you the code here to compare. This is not a clickbait driven website. Have you read this website? This is the opposite of a clicks driven site. I actively drive readers away.

extern crate rustc_serialize;
use rustc_serialize::json;
use std::error::Error;
use std::io::prelude::*;
use std::fs::File;
use std::path::Path;

#[derive(RustcDecodable, RustcEncodable)]
pub struct LangStruct {
    name: String,
    url: String,
    countStr: String, //count_str is canonical
    count: u8,
}

fn main() {
    let obj_array: [LangStruct; 2] = [
        LangStruct{
            name: "Ada".to_string(),
            url: "https://www.reddit.com/r/ada/".to_string(),
            countStr: "0".to_string(),
            count: 0
        },
        LangStruct{
            name: "C".to_string(),
            url: "https://www.reddit.com/r/C_Programming".to_string(),
            countStr: "0".to_string(),
            count: 0
        },
    ];
    let encoded = json::encode(&obj_array).unwrap();

    let path = Path::new("small.json");
    let mut file = match File::create(&path) {
        Err(why) => panic!("{}", Error::description(&why)),
        Ok(file) => file,
    };

    match file.write_all(encoded.as_bytes()) {
        Err(why) => panic!("{}", Error::description(&why)),
        Ok(_) => println!("done"),
    };
}

Firstly it's worth noting, that Rust code from five years ago, that still compiles just fine. Things have changed in the language, there are deprecation warnings, but five year old code and it still works. There is no Swift code on the planet that lasts anywhere near five years untouched. None. That is quite the achievement for the Rust folks.

So what has changed?

The serde crate (serde, named after serialise/deserialise) has replaced rustc_serialize. And I don't know if I knew about it before or not, but enabling the features of a crate is a thing now in cargo, the magic words being:

[dependencies]
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

It took me a lot of googling to work that out, code examples, and examples covering changes especially are still lacking. Maybe it's too niche a thing, but blog posts like this one I could not find.

The use declarations then become:

extern crate serde;
extern crate serde_json;
use std::fs::File;
use std::io::prelude::Write;
use std::path::Path;
use serde::{Deserialize, Serialize};

Something I didn't comment on (or maybe think of) last time, but use std::io::prelude::* or Write, to include parts of other crates, that seems like a fail to me. Maybe wrongly, this is an outsiders view. It makes me think of macros too. To rely so heavily on them, I think because the compiler can't deal with variable numbers of function arguments? I don't know. I don't know enough about building compilers to really say if it could be done differently, but still be as safe and as fast. Clearly not so far.

Structs haven't changed, as far as I can tell, other than calling a different crate to use on them here:

#[derive(Serialize, Deserialize)]
pub struct LangStruct {
    name: String,
    url: String,
    count_str: String,
    count: u8,
}

Which brings us to the main function. In the past it seems it would have been much faster to call to_owned() rather than to_string(). My bad, I didn't know. Apparently now to string is every bit as fast though, and rather more meaningful:

fn main()
{
    let obj_array: [LangStruct; 2] = [
        LangStruct {
            name: "Ada".to_string(),
            url: "https://www.reddit.com/r/ada/".to_string(),
            count_str: "0".to_string(),
            count: 0,
        },
        LangStruct {
            name: "C".to_string(),
            url: "https://www.reddit.com/r/C_Programming".to_string(),
            count_str: "0".to_string(),
            count: 0,
        },
    ];

But the thing that's excited me is how much less verbose the language seems to have become, at least with this example, which is only about a third as long now:

    let encoded = serde_json::to_string_pretty(&obj_array).expect("JSON to string failed");

    let path = Path::new("small.json");
    let mut file = File::create(&path).expect("File create failed");
    file.write_all(encoded.as_bytes())
        .expect("File write failed");
}

.except() here is unwrapping an optional, but with a custom message if it fails. Rather nicer than a ton of nested if let statements in Swift, to my mind. Pattern matching against the error still works, though the format of writing the error string out has changed a bit if you use that approach.

Finally, there's a pretty print option now too, to_string_pretty, shown here. Call to_string for the minified output of old.

So, some rather nice changes, plenty to like, a lot still to explore. Rust has been called "fractally complex", which I love as a description of anything, and who knows, that may well be true. But I like what I see so far. My revisit may take a while.

The year of Linux on the desktop

March 6, 2021

This is my leaving the Mac for Linux blog post. I think I'm obliged to write one of these.

I've used various Linux distros on servers over the years, but up until now the desktop alternatives have always been a better fit for me. Far better usually. Until now.

For me it's not about the "free as in beer". I've paid endless amounts for Apple & Microsoft OSs in the past, and if that was the easy option now I'd still be doing that.

It's also not about "free as in speech". Not really. I'm not in this to change the world.

For me it's about free as in "feel free to get off my lawn". It's about the freedom to be left alone.

After all the failing hardware and slowly tightening restrictions of the Mac world, and all the Oh-my-God-what-even-is-that of trying to use Windows, it was a simple pop-up ad for Safari on my Mac that pushed me over the edge. The proverbial straw, it was one intrusion into my desktop life too many.

I've got one M.2 drive set up with Windows, but that's for games only. I tried WSL, and WSL2 for development and they were laughably slow. But I needed to install Call of Duty, to test out the graphics card you understand.

I've still got my Macbook Pro too (while it lasts), for Acorn mostly, my preferred image editor. That's just out of habit really, I haven't looked at a Linux replacement for that yet.

I'm slowly working my way through all the software alternatives, but most of what I do on a computer is use VS Code (actually VSCodium) and docker and various scripts, and that's all the same stuff but with a solidly better experience so far. Solidly. It's night and day. It's not even close with how much faster Docker runs. The other stuff I can work on replacing over time. I'll write up a list when I'm more done on that front in case it helps anyone else.

At the top level, my choice of distro, I went conservative. I'm typing this on Ubuntu, the dad-core of the Linux world. I tried (and even mildly preferred) a few others, but the ability to run the same distro on my machine & on various Raspberry Pis (including the super cute keyboard 400), as well as those AWS EC2s, that made the decision for me.

It hasn't all been sweetness & light. An update killed my wi-fi drivers. I may have interrupted it I think, but I'm not sure. The fix was to kick off a reinstall of linux-modules-extra, no connection required. The magic incantation being:

sudo apt install linux-modules-extra-5.8.0-44-generic

You can use uname -r to find the version to use if it happens to you.

Update: Turns out it wasn't Linux at all – the annoying part of Ubuntu? Windows being a bad neighbour. In Windows: go to device manager, select network adapters, the wi-fi adapter, & untick turn this device off to save power under power management. Stupid Windows.

So here I am. Finally. It's early days, and who knows, it mightn't work in the end, but so far it's that beautiful, almost mythical thing: it's the "year of Linux on the desktop". At least for me.

Tags:

Swift no longer

February 5, 2021

In the beginning (1972ish) there was C. C was a small programming language. So small in fact that people frequently hurt themselves on its sharp corners.

By the early 80s, so long ago that nobody even remembers exactly when in the 80s any more, Objective C fixed all of that. Well, some of it. Objective C was a superset of the C language that added a bunch of affordances to C to make it more useful. But it contained all of C's goodness (and badness) within it. It added stuff but took nothing away.

NeXT liked Objective C.

Apple liked NeXT. A lot.

Then Apple made a rather nice line of phones and suddenly Objective C was everywhere. But most people using Objective C were only using it because they wanted to make money out of the phones Apple made. This was the 2000s already and by then Objective C seemed pretty old, and a bit weird. It had lots of square brackets. Nobody liked the square bracket thing.

So in 2014 Apple announced Swift as Objective C's replacement in the making money out of their phones business. Swift started small. But it grew. And it grew, and it grew. A lot.

Swift became a big language. Hard to learn. Harder to use. Really hard to use well.

Swift's available on Linux and Windows now. But I don't know why you'd want to use it there. People using Swift are only really going to be using it because they want to make money out of the phones Apple make…

Previously

Earlier posts...