RSSAmplifier

Blog

Luna’s Blog

blog.xoria.orgRSS feed ↗36 posts

Latest posts

Cocoa Basics Part Two: Our First Window

Now that we actually have a proper Mac app up and running, let’s delve into making a user interface! Making a window First, we’ll need a window. We want this window to open on startup, so let’s implement the applicationDidFinishLaunching(_:) app delegate method: // main.swift import AppKit let _ = NSApplication.shared let appDelegate = AppDelegate() NSApp.delegate = appDelegate NSApp.run() class…

Cocoa Basics Part One: The Application Structure

In the last part I took a bit of a shortcut: I had you compile and run a Mac app as a single executable. This isn’t how Mac apps are supposed to be built. Although they appear as single “files” in the Finder, a Mac app is what’s known as a package – a directory that appears as a file in the user interface. (It’s worth pointing out that the term folder is used to refer to directories which…

Cocoa Basics Part Zero: Introduction

Learning to make native Mac apps was difficult for me. With a little searching you can find Cocoa tutorials online, but they invariably only teach the what – things like “this is how you make a button”, or “this is how you make a list” – rather than the why. Maybe this says more about me than anything, but it took me around a year of on-and-off experimentation to feel like I finally…

Naming Files

I used to name files like a “normal person” – with capitalization, spaces, and so on. Non-Fiction Book Report Partly because I thought the programmer aesthetic looked cool and partly because I’d begun using the command-line heavily, I started naming my files so they’d be easy to type into a shell instead. nonfictionbookreport.md Over the years I came to embody the programmer aesthetic I had…

Execution Units are Often Pipelined

In the context of out-of-order microarchitectures, I was under the impression that execution units remain occupied until the µop they’re processing is complete. This is often not the case. As an example, take the Firestorm microarchitecture in the A14 and M1. It has two integer execution units capable of executing multiplies, which take three cycles to complete one multiplication. Of course, a…

macOS Tips for Programmers: Threading

Most people writing code that ends up running on macOS machines aren’t super familiar with the operating system, its unique features or its rough edges. That’s okay! If you’re a programmer using macOS and your code will actually end up running on a Mac rather than a server somewhere or whatever – even if your software isn’t a user-facing graphical application – then this post is for…

macOS Tips

macOS is a rather unique operating system, one which I like a great deal. This post started as a a list of tips I wrote for a friend who’s switching to macOS, but evidently I got carried away enough to turn it into a blog post. In my opinion it’s a good idea to first understand how the system was designed to be used before decrying it as ill-conceived or making it something it isn’t using…

Vector Type ABI Shenanigans

In a previous post I mentioned Clang’s OpenCL vector extension. Since then I’ve continued playing around with AppKit and Metal programming, and my enthusiasm for Clang’s OpenCL vectors has only grown since. It’s often necessary to specify two-dimensional values when doing GUI programming. Apple’s frameworks for making GUIs (AppKit, Core Graphics, Core Text, etc) use CGPoint and CGSize (sometimes…

First-Class Types, Syntactically

Zig has popularized the idea of treating types as first-class values that can be passed around and manipulated like any other. Generic data structures are just functions that take a type and return a type. This approach requires compile-time code execution, or “comptime”. Personally I’m not a fan of comptime because it creates an entire separate “mode of execution” for code. You can’t use your…

Boolean Types

Up until recently I was of the opinion that the obvious choice for the in-memory representation of booleans is an 8-bit integer. As has become a running theme across the last couple posts, my preconceptions were challenged once I started looking more into the Handmade Network and related communities. For some reason everyone there seemed to use 32-bit integers for booleans, and I started wondering…

Invalid Values and String Types

I was writing a reply to a post on Ziggit and (as usual) got completely carried away, so I decided to flesh it out a little more and post it here instead. Over the last little while I’ve come to really appreciate Odin’s approach to strings. I wasn’t convinced initially, but I now think there’s a really solid argument to be made for having a string type even in a low-level systems programming…

Opinions on Vector Types & the Features They Require

Over the past few months I’ve started to (finally!) get into GPU programming using the wonderful Metal API after years of failed attempts at learning OpenGL and WebGPU . One thing I’ve really come to appreciate is good language support for vector types. Being able to write float4 ndc = float4(position.xy / resolution * 2 - 1, 0, 1); is such a joy, and I really came to miss it when writing C and…

The Dangers of Programming Language Complexity

I have this unhealthy habit where I can’t help but use every feature a programming language provides me. I’ve gotten a lot better at resisting the urge in recent years, but it’s still there. Usually these features have some kind of unique benefit you can’t get any other way by virtue of being built into the language. Maybe the compiler can detect if you call some functions in the wrong order, or…

Randomness on Apple Platforms

In this post I’d like to lead you through my journey trying to discover the “best” way to obtain randomness on Apple platforms. 1 The goal throughout will be to get as close to the underlying hardware random number generators as the system allows by stripping away layers of abstraction one by one. Once we have a comprehensive picture of the entire system, I’ll walk you through my opinions on which…

Const Pointers

I’ve noticed a pattern which keeps coming up over and over again throughout the field of software engineering: mutable state is hard. More specifically, shared mutable state is hard. Think about this for a bit and you’ll come to a foundational realization: it’s easy to maintain invariants locally, but hard to maintain them globally. For example, if several copies of some duplicated code need to be…

To Use a Keyword or an Identifier?

The latest C standard declares that true , false , int , float and all the other core types are keywords. As a result, a definition like union int_or_float { int int; float float; }; is illegal since you can’t use keywords as field names. This isn’t just a contrived edge case, in my opinion: a union like the above is genuinely useful if you’re doing a lot of bitcasts. I think this situation is a…

A Language Design Trick for Keywords

A recurring issue in the design of programming language syntax is the handling of keywords. What makes keywords tricky is that they’re made of letters, which user-defined identifiers are too – they conflict. As a result, adding new keywords to a language can break existing code which uses these keywords as identifiers. Most languages bite the bullet and accept the necessity of breaking…

Systems Languages Should Support Zero Is Initialization

In the last few years, a barrage of new systems programming languages have been released. A common feature is language-level support for non-null pointers, along with some kind of nullable pointer type. This may be a dedicated type ( as in Hare ), or it may be a general-purpose “optional” or “maybe” type which represents a non-present pointer as a null pointer ( as in Rust and Zig ). It is no…

Rounding Up to Multiples of Powers of Two Efficiently

Suppose we want to round a number, n , up to the next multiple of p , where p is a power of two. We might write some naive code like this: int64_t round_up(int64_t n, int64_t p) { int64_t rem = n % p; if (rem == 0) { return n; } return n + p - rem; } We calculate the remainder of n divided by p . If n is already a multiple of p , then we can just return n . Otherwise, we calculate how far we are…

Prefer Passing By Pointer

Before the standardization of C, not all C compilers let you pass or return structs by value. This led to code that looks like this: struct player { int x, y; int health; int score; int xp; int level; int damage_taken; int secs_played; }; void player_create(struct player *p, int screen_w, int screen_h) { p->x = screen_w / 2; p->y = screen_h / 2; p->health = 100; p->score = 0; p->xp = 0; p->level =…

Thoughts On Integers

In this post I’ll lay out my views on integer types, and how I’ve come to those views. Hopefully you’ll disagree initially and be convinced by the end! The status quo Let’s begin with what I’d characterize as the status quo in popular programming languages today. But first, some caveats: I won’t mention scripting languages throughout this article for obvious reasons. Moreover, I’m leaving Java out…

Classes Are Overloaded

I realize it’s unusual to do some good old-fashioned object-oriented programming only after having learnt other, less mainstream languages like Rust and Haskell, but here I am. Recently I had my first proper experience with C#, and I have some thoughts. Classes are used for, well, everything, and I’m not sure how I feel about that. Let’s see some examples. Class as data type This is how I think…

<em>n</em> times faster than C, Arm edition

The other day I read a two-parter blog post by Owen Shepherd, {n} times faster than C . In it, he takes a simple algorithm, and optimizes it as much as he can, dropping down to raw assembly along the way. I love this sort of thing, though I’m not very good at it. I decided I’d try my own hand at it anyway, but for the A64 instruction set . I’ve tried to make this post understandable if you haven’t…

Hidden Overheads

One day I was sitting around thinking about performance, when a thought popped into my head &ndash; how can it be that systems programmers shun higher-level languages due to their hidden performance costs when even C has plenty of areas where something expensive can happen without much ceremony or acknowledgement from the language? To answer that question we first need to take a look at some of…

Methods in Languages for Systems Programming

I’d been working on this article on and off for around a month or so when I realized it’d probably just end up sitting uncommitted on my laptop forever. I’m sure anyone who has a sporadically-updated blog can relate. Something about it feels wrong to me, and I can’t quite put my finger on why. Fast-forward and it’s now been two months since I last edited this accursed post. I go to write a blog…

Side-Effectful Expressions in C

This article began from a list of reasons I was making which purportedly justify my years-long (and so far fruitless!) pursuit of writing my own systems programming language compiler. More concretely, I was making a list of gripes I have with C. I sorted them into two groups: changes that would improve the safety of the language, and changes that would help maintain the sanity of users and…

Signing Your Commits in 2023 on macOS

Let me preface this with a disclaimer: I am not a security expert, and I in fact know very little about either digital security or cryptography. This is just a little note on what I’ve learned about this topic so you don’t need to go scrounging around the internet like I did. Edit: It has been one day since I posted this. I have now learned of the existence of Secretive and YubiKeys , and how…

Don’t Zero Out Memory By Default

A common practice in low-level languages such as C and C++ is to default to filling memory with zeroes. For example, this proposal suggests zeroing out stack variables by default. Anonymous memory mappings created using mmap(2) are filled with zeroes, and so are allocations created with calloc(3) . Missing fields in C’s designated initializers are &ndash; you guessed it &ndash; null-initialized.…

A Simple Yet Useful Version of Generics

Traditionally, containers are seen as an area where generics with monomorphization are essential; who wants every key and every value in their hash table to be boxed? However, I think pretty much every use-case for generics in the context of containers can be replaced with something far simpler. To start, let’s take a look at a simple implementation of a dynamic array in C. Everything in this post…

My Webfont Contradiction

I’ve seen lots of tech people complain online about how websites are becoming increasingly bloated. I understand this sentiment, completely. One of the culprits which is often mentioned (alongside invasive advertising and mountains of JavaScript) is (are?) webfonts. I’ve seen them be derided for being a pointless waste of hundreds of kilobytes or perhaps even megabytes of bandwidth per page load,…

Dynamic Arrays with Data-Oriented Design

I would say that dynamic arrays are the most common container type. When programming in a data-oriented style where all allocations are done ahead of time, dynamic arrays manifested as an explicit type like C++’s std::vector or Rust’s Vec<T> often aren’t even necessary. In many cases, data-oriented design advocates the use of numerous large flat arrays of scalar values. A lot of code ends up…

Escaping the Identifier Casing Orthodoxy

My initial programming experience was with Ruby and Python, for both of which there exists a strong convention regarding identifier casing: Python & Ruby variable snake_case constant UPPER_SNAKE_CASE function snake_case type PascalCase Later when I began to use Rust, things stayed pretty much the same: Python & Ruby Rust variable snake_case snake_case global variable UPPER_SNAKE_CASE constant…

How to Choose Colors for Your CLI Applications

Let’s say you’re creating a CLI tool which has to display syntax highlighted source code. You begin by choosing some colors which look nice with your chosen terminal theme: ~ — zsh — Sorcerer — 51×11 % highlight foo # just some docs func HelloWorld () [ 12 ] u8 { return "hello world \n " } Finished highlighting in 0.02 seconds. % █ Nice! However, who knows if it’ll still look good for people who…

I Love Email

I constantly hear about how much everybody hates email. Look, I receive just as many spam messages and useless email-based notifications and stuffy vapid “regarding my previous email” work messages as the next gal. I get it. But I’ve found there’s something magical about email as a medium of communication, and as a technology. As of late I’ve taken to emailing random people about things they’ve…

Classes and Globals

As of late I’ve been going through the commit history of Rui Ueyama’s excellent chibicc , a self-hosting as-simple-as-possible C compiler. One thing that stood out to me was the pervasive use of global variables. codegen.c is a good example. At the top of the file several statics are defined: static FILE *output_file; static int depth; static char *argreg8[] = {"%dil", "%sil", "%dl", "%cl",…

Meta Memory

Let’s take a tree structure struct Expr { Int(u32), Add { lhs: Box<Expr>, rhs: Box<Expr> }, } and flatten it into a Vec<T> , or contiguous region of memory. struct Arena(Vec<Expr>); struct Expr { Int(u32), Add { lhs: usize, rhs: usize }, } We can compare this representation to a traditional memory model: memory meta-memory address space arena pointer usize malloc() Vec::push free() Vec::clear…