A Strong Typing Example

I’m a Rust programmer and in general a fan of strong typing over dynamic or duck typing. But a lot of advocacy for strong typing doesn’t actually give examples of the bugs it can prevent, or it gives overly simplistic examples that don’t really ring true to actual experience. Today, I have a longer-form example of where static typing can help prevent bugs before they happen. The Problem Imagine you have a process that receives messages and must respond to them.

Blocking Sockets and Async

Using async in Rust can lead to bad surprises. I recently came across a particularly gnarly one, and I thought it was interesting enough to share a little discussion. I think that we are too used to the burden of separating async from blocking being on the programmer, and Rust can and should do better, and so can operating system APIs, especially in subtle situations like the one I describe here.

Why Rust should only have provided expect for turning errors into panics, and not also provided unwrap

UPDATE 2: I have made the title longer because people seem to be insisting on misunderstanding me, giving examples where the only reasonable thing to do is to escalate an Err into a panic. Indeed, such situations exist. I am not advocating for panic-free code. I am advocating that expect should be used for those functions, and if a function is particularly prone to being called like that (e.g. Mutex::lock or regex compilation), there should be a panicking version.

Another Confusing Haskell Error Message

The Error Message I’ve written before about just how befuddling Haskell error messages can be, especially for beginners. And now, even though I have some professional Haskell development under my belt, I ran across a Haskell error message that confused me for a bit, where I had to get help. It’s clear to me now when I look at the error message what it’s trying to say, but I legitimately was stumped by it, and so, even though it’s embarrassing for me now, I feel the need to write about how this error message could have been easier to understand:

Command Line Interface UXes Need Love, Too

It took me a long time to admit to myself that the venerable Unix command line interface is stuck in the past and in need of a refresh, but it was a formative moment in my development as a programmer when I finally did. Coming from that perspective, I am very glad that there is a new wave of enthusiasm (coming especially from the Rust community) to build new tools that are fixing some of the problems with this very old and established user-interface.

Trivia About Rust Types: An (Authorized) Transcription of Jon Gjengset’s Twitter Thread

Preface (by Jimmy Hartzell) I am a huge fan of Jon Gjengset’s Rust for Rustaceans, an excellent book to bridge the gap between beginner Rust programming skills and becoming a fully-functional member of the Rust community. He’s famous for his YouTube channel as well; I’ve heard good things about it (watching video instruction isn’t really my thing personally). I have also greatly enjoyed his Twitter feed, and especially have enjoyed the thread surrounding this tweet:

Function Overloading in Rust

I just made a pull request to reqwest. I thought this particular one was interesting enough to be worth blogging about, so I am. We know that many C++ family languages have a feature known as function overloading, where two functions or methods can exist with the same name but different argument types. It looks something like this: void use_connector(ConnectorA conn) { // IMPL } void use_connector(ConnectorB conn) { // IMPL } The compiler then chooses which method to call, at compile-time, based on the static type of the argument.

Can you have too many programming language features?

There’s more than one way to do it. Perl motto There should be one– and preferably only one –obvious way to do it. The Zen of Python (inconsistent formatting is part of the quote) When it comes to statically-typed systems programming languages, C++ is the Perl, and Rust is the Python. In this post, the next installment of my Rust vs C++ series, I will attempt to explain why C++’s feature-set is problematic, and explain how Rust does better.

A Checklist of Dev-Ops Disciplines

I have worked on a lot of programming projects in my time, and while I was a programming consultant I have worked in a lot of different corporate environments. At some of them, it was easy to be concretely productive: I was able to contribute immediately, and at a rapid rate. At others, actual useful contributions would be impossible until I had a month or more of experience with a codebase, and even then every change would be a long slog.

Choosing the Right Integers

Paying attention to beginner questions is important. While many are just re-hashes of things that books have explained 1000 times, some are quite interesting, like this one that I saw recently in a Reddit post: How do I determine when to use i8-64 (same for u8-64)? Now, here is a surprisingly hard question. It’s really easy to find out what i16 and u8 and friends mean, and what they do: the appropriate section comes really early in The Book.

Can you reproduce it?

NOTE: This post has the #programming tag, but is intended to be comprehensible by everyone, programmer or not. In fact, I hope some non-programmers read it, as my goal with this post is to explain some of what it means to be a programmer to non-programmers. What is the most important skill for a software engineer? It’s definitely not any particular programming language; they come and go, and a good programmer can pick them up as they work.

A Rust Gem: The Rust Map API

For my next entry in my series comparing Rust to C++, I will be discussing a specific data structure API: the Rust map API. Maps are often one of the more awkward parts of a collections library, and the Rust map API is top-notch, especially its entry API – I literally squealed when I first learned about entries. And as we shall discuss, this isn’t just because Rust made better choices than other standard libraries when designing the maps API.

The Good Ol' Days of QBasic Nibbles

Let’s talk about an ancient programming language! I think we can all learn things from history, and it gives us grounding to realize that our time is just one time among many, to see what people in the past did differently, what they got wrong that we would never do now, and also to see what they got right. Do you remember MS-DOS? Do you remember that it came with an interpreted programming language?

Warnings and Linter Errors: The Awkward Middle Children

What is “bad” Rust? When we say that a snippet of code is “bad” Rust, it’s ambiguous. We might on the one hand mean that it is “invalid” Rust, like the following function (standing on its own in a module): fn foo(bar: u32) -> u32 { bar + baz // but baz is never declared... } In this situation, a rule of the programming language has been violated. The compiler stops compiling and does not output a binary.

Haskell Error Messages: Come on!

I am a big fan of strongly typed languages, and my favorite GC’d language is Haskell. And I want you, the reader, to keep that in mind today. What I am writing is some commentary about a language I deeply love, some loving criticism. So here’s what happened: A few days ago, I was showing off some Haskell for a friend who primarily programs in Python. The stakes were high – could I demonstrate that this strange language was worth some investigation?

Being Fair about Memory Safety and Performance

For this next iteration in my series comparing Rust to C++, I want to talk about something I’ve been avoiding so far: memory safety. I’ve been avoiding this topic so far because I think it is the most discussed difference between C++ and Rust, and therefore I felt I’d have relatively little to add to the conversation. I’ve also been avoiding it because I wanted to draw attention to all the other little ways in which Rust is a better-designed programming language, to say that even if you concede to the C++ people that Rust isn’t “truly memory safe” or “memory safe enough,” Rust still wins.

In Defense of Async: Function Colors Are Rusty

Finally in 2019, Rust stabilized the async feature, which supports asynchronous operations in a way that doesn’t require multiple operating system threads. This feature was so anticipated and hyped and in demand that there was a website whose sole purpose was to announce its stabilization. async was controversial from its inception; it’s still controversial today; and in this post I am throwing my own 2 cents into this controversy, in defense of the feature.

Endianness, API Design, and Polymorphism in Rust

I have been working on a serialization project recently that involves endianness (also known as byte order), and it caused me to explore parts of the Rust standard library that deals with endianness, and share my thoughts about how endianness should be represented in a programming language and its standard library, as I think this is also something that Rust does better than C++, and also makes for a good case study to talk about API design and polymorphism in Rust.

C++ Move Semantics Considered Harmful (Rust is better)

This post is part of my series comparing C++ to Rust, which I introduced with a discussion of C++ and Rust syntax. In this post, I discuss move semantics. This post is framed around the way moves are implemented in C++, and the fundamental problem with that implementation, With that context, I shall then explain how Rust implements the same feature. I know that move semantics in Rust are often confusing to new Rustaceans – though not as confusing as move semantics in C++ – and I think an exploration of how move semantics work in C++ can be helpful in understanding why Rust is designed the way it is, and why Rust is a better alternative to C++.

Sayonara, C++, and hello to Rust!

This past May, I started a new job working in Rust. I was somewhat skeptical of Rust for a while, but it turns out, it really is all it’s cracked up to be. As a long-time C++ programmer, and C++ instructor, I am convinced that Rust is better than C++ in all of C++’s application space, that for any new programming project where C++ would make sense as the programming language, Rust would make more sense.

Apple Silicon

This year, Apple released, to much fanfare, a somewhat obscure technical change to how its computers work: Macs will transition away from Intel’s CPUs to in-house processors known as “Apple Silicon,” more similar to the technology Apple already uses in its phones and tablets. It is a tremendous amount of hype for something rather technical, and to people used to more user-visible feature announcements, this can be somewhat disappointing, or at least confusing.

Open Internet, Closed Web

The Internet promised — and still promises — a revolution in democratic, decentralized, and open communications. And yet, we see today a tech world controlled by a few central players, as Elizabeth Warren promises to break them up and Congress summons Mark Zuckerberg to explain his company’s role in privacy-violating election-manipulating foreign conspiracies. But Presidential use of anti-trust laws and new Congressional regulations of social media won’t address the more fundamental issues: The Internet is now structured, on a technical and social level, so as to naturally encourage centralized monopolies.

The Haskeller’s Hungarian Notation

When I was first learning to program, a long time ago, it was in BASIC, and you had to annotate your variable names to indicate what type something is. foo would be a number, whereas foo$ would be a string. This meant that there could only be as many types of information as there were symbols to put after your variable, but that was okay for the sort of programming BASIC was used for.

Components of a Modern Operating System

In previous posts, we discussed historic operating systems and where various OS features come from, but we only gave a brief overview of how they worked. Now that we have a modern operating system’s full complement of features, we can look at what components need to exist in a modern operating system to get those features. As discussed with MS-DOS, an operating system, even today, is partially code, and partially conventions, like file formats or rules of good behavior – the difference being, that modern operating systems have more ability to enforce some of these conventions.

Operating Systems Part II: Modern Operating Systems

We use operating systems all the time in our life, whether designed for a computer, a phone, or for a server we’re more indirectly interacting with, but a lot of people don’t know very much about what connects the different systems we use, and what makes them distinct. We discussed fundamental concepts of operating systems in the last post, so in this post we will discuss how some of the same concepts apply to modern operating systems, going over them one at a time.

What is an operating system?

A user of modern technology hears the term “operating system” thrown around a lot. Most people can name a few examples: Windows and macOS on workstations and laptops, iOS and Android on phones. Some people might even throw in Linux or Unix or ChromeOS. Most people also understand that a program or a game or even a sufficiently advanced website might work on some operating systems but not others, and might require different versions for different operating systems.

Function Pointers in C and C++

Programmers of functional programming languages will often point out that, in functional programming languages, the order of the arguments is often significant, because of currying. If you have a function that takes two arguments (e.g. map which takes a function to apply and a list to apply it to) it actually takes the first argument, and returns a function that takes the second argument and returns the final result. This makes it more convenient to write a lambda where the second argument is the unknown parameter: \x -> map someFunc x can be written as map f, whereas \f -> map f someValue has no such convenient shorthand (flip map someValue is actually clunkier).