Bookmarks

100R - orca

Orca operates on a base of 36 increments. Operators using numeric values will typically also operate on letters and convert them into values as per the following table.

A Gentle Introduction to Lambda Calculus - Part 1: Syntax

Even though lots of people nowadays advocate for applying functional programming principles to JavaScript, not many of them know the principles of Lambda Cal...

Faking ADTs and GADTs in Languages That Shouldn't Have Them

Haskell is the world’s best programming language, but let’s face the harsh reality that a lot of times in life you’ll have to write in other programming languages. But alas you have been fully Haskell-brained and lost all ability to program unless it is type-directed, you don’t even know how to start writing a program without imagining its shape as a type first. Well, fear not. The foundational theory behind Algebraic Data Types and Generalized Algebraic Data Types (ADTs and GADTs) are so fundamental that they’ll fit (somewhat) seamlessly into whatever language you’re forced to write. After all, if they can fit profunctor optics in Microsoft’s Java code, the sky’s the limit! This is an “April Fools” joke in the tradition of my previous one in some of these ways that we are going to twist these other languages might seem unconventional or possibly ill-advised… but also the title is definitely a lie: these languages definitely should have them! :D

Accelerate

Accelerate is a language for array-based computations, designed to exploit massive parallelism.

Ok Rust, You Really Have a Readability Problem

Rust is safe. Rust is fast. Rust is powerful. And Rust is… sometimes completely unreadable.

Why async Rust?

I genuinely can’t understand how anybody could look at the mess that’s Rust’s async and think that it was a good design for a language that already had the reputation of being very complicated to write.

Template Haskell

Intuitively Template Haskell provides new language features that allow us to convert back and forth between concrete syntax, i. e.

Comments on Source

The section of the wiki allows anyone to document, explain, post questions, or make comments on the Lua source code. You may link to [1] or paste the code in question.

The Making of Python

Guido van Rossum is the author of Python, an interpreted, interactive object-oriented programming language.

Programming Really Is Simple Mathematics

A re-construction of the fundamentals of programming as a small mathematical theory (PRISM) based on elementary set theory. Highlights: $\bullet$ Zero axioms. No properties are assumed, all are proved (from standard set theory). $\bullet$ A single concept covers specifications and programs. $\bullet$ Its definition only involves one relation and one set. $\bullet$ Everything proceeds from three operations: choice, composition and restriction. $\bullet$ These techniques suffice to derive the axioms of classic papers on the "laws of programming" as consequences and prove them mechanically. $\bullet$ The ordinary subset operator suffices to define both the notion of program correctness and the concepts of specialization and refinement. $\bullet$ From this basis, the theory deduces dozens of theorems characterizing important properties of programs and programming. $\bullet$ All these theorems have been mechanically verified (using Isabelle/HOL); the proofs are available in a public repository. This paper is a considerable extension and rewrite of an earlier contribution [arXiv:1507.00723]

Stating the problem in Lean

Note: this post was written for Lean 3; the latest version, Lean 4, is a very different language. Turn back the clock to 2009: a confused physics major newly infatuated with math and computer science, I enrolled in MATH 273: Numbers and Proofs at the University of Calgary. This wasn’t my first encounter with mathematical proof; in first-year calculus I’d mastered rote regurgitation of delta-epsilon proofs. Despite writing out several dozen, their meaning never progressed beyond a sort of incantation I can summon to this day (for every \( \epsilon > 0 \) there exists a \( \delta > 0 \) such that…).

Why Futhark?

A high-performance and high-level purely functional data-parallel array programming language that can execute on the GPU and CPU.

On Ousterhout’s Dichotomy Oct 6, 2024

Why are there so many programming languages? One of the driving reasons for this is that some languages tend to produce fast code, but are a bit of a pain to use (C++), while others are a breeze to write, but run somewhat slow (Python). Depending on the ratio of CPUs to programmers, one or the other might be relatively more important.

The categorical abstract machine

The Cartesian closed categories have been shown by several authors to provide the right framework of the model theory of λ-calculus. The second author…

What is the "question" that programming language theory is trying to answer?

I've been interested in various topics like Combinatory Logic, Lambda Calculus, Functional Programming for a while and have been studying them. However, unlike the "Theory of Computation" which str...

Advanced programming languages

Students often ask for a recommendation on what language they should learn next.

TuringConf

Haskell as fast as C: working at a high altitude for low level performance

After the last post about high performance, high level programming, Slava Pestov, of Factor fame, wondered whether it was generally true that “if you want good performance you have to write C…

On Competing with C Using Haskell

Mark Karpov wrote in his article on Migrating text metrics to pure Haskell how he originally did foreign calls out to C for many of the functions in his text metric package, but now ported them to Haskell when he learned that Haskell can give you performance comparable to C.

Performance

Moreover, it's often not clear if two programs which supposedly have the same functionality really do the same thing.

Creating enums at comptime

Using zig's @Type to dynamically create enums at comptime

Zig's new declaration literals

A look at Zig's new declaration literals

Zig's (.{}){} syntax

A look at some unfriendly Zig syntax

How 99% of C Tutorials Get it Wrong

But this article did not arise only from my own opinion. The argument I'll present here, at least in its general form, is one which programmers who I know personally and I admire a lot (e.

For Beginners

Occasional writings about Haskell.

TCP Server in Zig - Part 5a - Poll

Using non-blocking sockets and poll to improve the scalability of our system.

Typing the technical interview

In the formless days, long before the rise of the Church, all spells were woven of pure causality, all actions were permitted, and death was common.

Async Rust can be a pleasure to work with (without `Send + Sync + 'static`)

Async Rust is powerful. And it can be a pain to work with (and learn). Async Rust can be a pleasure to work with, though, if we can do it without `Send + Sync + 'static`.

Zig's BoundedArray

A quick look at how and why to use Zig's BoundedArray.

Linus Torvalds talks AI, Rust adoption, and why the Linux kernel is 'the only thing that matters'

In a wide-ranging conversation with Verizon open-source officer Dirk Hohndel, 'plodding engineer' Linus Torvalds discussed where Linux is today and where it may go tomorrow.

Zig and Emulators

Some quick Zig feedback in the context of a new 8-bit emulator project I starteda little while ago:

Zig Build System

The fundamental commands zig build-exe, zig build-lib, zig build-obj, and zig test are often sufficient.

Introduction to the Odin Programming Language

Preface This article is an introduction the Odin Programming Language. It is aimed at people who know a bit of programming, but have never touched Odin. It is not a reference guide, rather I try to keep things informal and talk about what I think are important aspects of the language. There will be some notes on differences to C/C++, as Odin in many ways tries to be better C. If you enjoy this article and want to support me, then you can do so by becoming a patron.

How I built zig-sqlite

When you prepare a statement zig-sqlite creates a brand new type only for this prepared statement.

Microfeatures I'd like to see in more languages

There are roughly three classes of language features: Features that the language is effectively designed around, such that you can't add it after the fact....

Rust Atomics and Locks

This book by Mara Bos explores Rust programming language's concurrency features, including atomics, locks, and memory ordering. Readers will gain a practical understanding of low-level concurrency in Rust, covering topics like mutexes and condition variables. The book provides insights on implementing correct concurrency code and building custom locking and synchronization mechanisms.

Implementing interactive languages

Implementing an interactive language requires considering both compile-time and run-time performance. Traditional switch-based bytecode interpreters are easy to implement but have lower run-time performance compared to optimizing compilers. A sweet spot in performance can be found by aiming for combined compile-time and run-time performance within a certain range. Various options for implementing fast interpreters, existing compilers like LLVM and Cranelift, custom compilers, and using WebAssembly as a backend are discussed. The idea of having two backends for a language to support quick startup and aggressive optimization is also explored. There are still many unknowns and further research is needed to determine the feasibility and performance of different approaches.

Parse, don’t validate

The text discusses the importance of parsing over validating in Haskell to prevent errors and enhance code reliability by using strong argument types. Parsing upfront helps maintain consistency and avoids potential issues with partial input processing, demonstrating the benefits of type-driven design in Haskell programming. The text also touches on the subjective nature of programming languages, highlighting differing perceptions of Haskell and the challenges faced by learners in navigating diverse opinions.

Why null sucks, even if it's checked

The article discusses the problems with using null in programming languages like Kotlin and C#, highlighting that null can lead to confusion and errors. It argues that null is not an extensible solution for representing absence of value and suggests using sum types or optional types instead. The author believes that languages should focus on improving optional types rather than trying to make null safer.

Resources for Building Programming Languages

The article shares resources for learning how to create programming languages, focusing on Rust and C. It highlights the book "Crafting Interpreters," which provides practical insights into building interpreters using different programming approaches. The author also discusses their personal experience building a language and the tools they've found helpful, like LLVM and Cranelift.

Little 'Big Ideas' in Programming Language Design

Colin Davis discusses "little big ideas" in programming language design, focusing on the balance between innovative features and conventional choices. He highlights Mojo and Go as examples, noting how Mojo combines modern improvements with familiar concepts, while Go prioritizes simplicity and a strong ecosystem. Davis suggests that small design decisions, like memory management and parameter passing, can greatly enhance a language's usability and performance.

p75-hoare

The author recounts experiences in designing a computer programming language and issues a warning about language complexity. Despite challenges, a subset of the language was successfully implemented. The author emphasizes the importance of simplicity and reliability in programming languages for critical applications.

Why Pascal is Not My Favorite Programming Language

Pascal is not recommended for serious programming due to limitations in its standard form. The language's strict typing and lack of features like separate compilation make it challenging for complex projects. Pascal is better suited for educational purposes rather than practical programming tasks.

Crafting an Interpreter in Zig - part 1

The author is learning Zig by implementing an interpreter for the Lox programming language, inspired by the book "Crafting Interpreters." They are documenting their journey, focusing on interesting aspects of Zig and how it differs from C. So far, they have enjoyed the process, particularly the simplicity and power of Zig's generic programming.

The Development of the C Language*

The paper discusses the development and influences of the C programming language, highlighting its creation at Bell Labs and transition from the B language. C's simplicity, efficiency, and widespread adoption across various platforms and architectures are emphasized, showcasing its enduring stability and usefulness in software development. Despite its quirks and historical origin, C has proven to be a powerful and versatile language for programmers worldwide.

Zig Interfaces for the Uninitiated, an update

The post discusses a new idiom for runtime polymorphism in Zig, focusing on using fat pointers instead of @fieldParentPtr. It provides a step-by-step guide on creating a formal Iterator interface and implementing it with an example range iterator. The drawbacks of this pattern include potential performance issues and the requirement for the original implementor to remain alive for the interface to function correctly.

Zig Interfaces for the Uninitiated

The text discusses how to create and implement generic iterators in Zig using interfaces like `Iterator` and `Range`. It demonstrates how to use these iterators to iterate over ranges of values and provides examples of ascending, descending, and skipping ranges. Additionally, it introduces a function `fold` to apply a function to successive elements in an iterator, showcasing Zig's runtime polymorphism for data structures.

Exploring Compile-Time Interfaces in Zig

Zig is a programming language with active community support and a focus on efficient, reusable software development. Interfaces in Zig define a blueprint for classes to implement specific methods, promoting code abstraction and flexibility. Compile-time interfaces in Zig optimize code structure by resolving methods during compilation for efficient program execution.

Aro - a C compiler

Aro is a C compiler created as an alternative to Zig's compiler. It includes the aro module for the compiler and a language-agnostic aro_backend module for translating code into machine code. Aro uses self-hosted backends from the Zig compiler for optimization.

One year of C

The author reflects on their year of writing C code, finding it enjoyable and productive. They emphasize the importance of choosing the right language for each problem and share insights on the benefits of using C over C++ in certain scenarios. Additionally, they discuss the advantages of C99 improvements and the simplified nature of writing C code compared to C++.

Heap Memory and Allocators

The text discusses different types of memory allocators in Zig programming language. It explains how memory allocation and deallocation work using alloc and free functions. Various allocator types like GeneralPurposeAllocator and FixedBufferAllocator are highlighted for managing memory efficiently.

Pointers

Pointers in Zig allow variables to reference memory addresses. Understanding pointers helps manipulate memory effectively. Pointers are values that store memory addresses and can be nested within structures.

An opinionated beginner’s guide to Haskell in mid-2019

This guide is for beginners in Haskell or those transitioning from similar languages, offering advice on learning resources and tools. It emphasizes the importance of writing Haskell code, getting help online, choosing popular platforms, and sticking to the default Prelude. The guide also touches on application architecture, using records, debugging techniques, and the experimental nature of Haskell as both a research and industrial language.

Are tagged unions overrated?

The author discusses the limitations of tagged unions and pattern matching in language development, suggesting that they are overrated for implementing language ASTs and IRs. Despite the benefits of tagged unions, the complexity they add may not always justify their use, especially in cases where simpler alternatives like class hierarchies can offer similar functionality. The post also highlights the potential for enhancing pattern-matching capabilities in mainstream languages to improve code readability and maintainability.

How do we tell truths that might hurt?

The document discusses the challenges of telling unpleasant truths and the conflict that arises when sharing these truths in the field of Computing Science. The author argues that remaining silent about these truths compromises the intellectual integrity of the field. The document also lists a number of truths related to programming languages and the use of language in computing systems. The author questions whether the field should continue to ignore these truths and urges for a change in attitude.

Bare Metal Zig

The text discusses compiling a freestanding Zig binary to run on "bare metal" without relying on an operating system. It shows how to create a simple freestanding binary, make it multiboot compliant, and add custom console functionality for output. The process involves targeting specific architectures, handling linker warnings, and ultimately creating a bootable "kernel" to run on virtual machines like QEMU.

C Isn't A Programming Language Anymore

C is no longer just a programming language but a vital protocol for all languages. Parsing C headers is a complex task best left to C compilers. Maintaining ABI compatibility in C can be challenging and may require versioning schemes.

Pipelines Support Vectorized, Point-Free, and Imperative Style

The text discusses how pipelines in the shell language support vectorized operations on collections and point-free style, where no data is explicitly mentioned. It also demonstrates how imperative code can be incorporated within pipelines for tasks like generating HTML tables. The unique features of pipelines include their ability to handle vectorized code, point-free composition, and integration of imperative instructions.

Zig Bare Metal Programming on STM32F103 — Booting up

The text explains how to program the STM32F103 microcontroller using the Zig programming language. It covers topics such as memory layout, linker scripts, and compiling code for embedded systems. By following the provided instructions, readers can successfully compile and run their first embedded program on the microcontroller.

Undefined Behavior deserves a better reputation

Undefined Behavior is often viewed negatively, but it can be a valuable tool for language designers. It allows programmers to convey insights to the compiler for optimizations. Responsible use of Undefined Behavior can enhance language design and code performance.

KHM+15

The text discusses a formal C memory model that supports integer-pointer casts, essential for low-level C programming. It proposes a quasi-concrete memory model that allows standard compiler optimizations while fully supporting integer-pointer casts. This model helps verify programs and optimizations that are challenging to validate with integer-pointer casts.

Some Were Meant for C

The document "Some Were Meant for C" explores the enduring significance of the C programming language, highlighting its dual role as both an application and systems programming language. It challenges common assumptions about C, emphasizing its unique communicative design that differs from managed languages. The document argues that C's explicit representations and memory access foster effective system-building and communication, making it a preferred choice for certain technical challenges. Additionally, it critiques the prevailing discourse that demonizes C, advocating for a nuanced understanding of its role in the programming landscape.

C Is Not a Low-level Language

C is often considered a low-level language, but this article argues that it is not. The author explains that vulnerabilities like Spectre and Meltdown occurred because processor architects were trying to build fast processors that exposed the same abstract machine as a PDP-11, which C programmers believe is close to the underlying hardware. However, the reality is that C code runs on a complex compiler that performs intricate transformations to achieve the desired performance. The article also discusses how C's memory model and optimizations make it difficult to understand and can lead to undefined behavior. The author suggests that instead of trying to make C code fast, it may be time to explore programming models on processors designed for speed.

Should you learn C to "learn how the computer works"?

The author discusses whether learning C is necessary to understand how computers work, ultimately concluding that C is not a direct representation of computer operations. Learning C can still be beneficial for understanding computing concepts and history, but it operates within a virtual machine and abstracts certain hardware details. By learning C, you can gain insight into the relationship between programming languages, hardware, and the historical development of computing.

A Guide to Undefined Behavior in C and C++, Part 1

The text explains that undefined behavior in C and C++ can lead to unpredictable program outcomes. Compilers may optimize code by exploiting undefined behavior, potentially causing programs to misbehave. It is important for programmers to understand how undefined behavior can impact program execution.

John Carmack on Functional Programming in C++

Functional programming in C++ can help in writing better software by making code easier to reason about and eliminating thread race conditions. Pure functions, which only rely on input parameters and produce consistent outputs, offer benefits such as thread safety and easier testing. Refactoring towards purity can improve code quality, even if full purity is not achieved, by disentangling computation from the environment it operates in.

Zig-style generics are not well-suited for most languages

Zig-style generics, like those in C++, may not work well for all languages due to limitations in compiler support and type inference. Armchair suggestions about adopting Zig-style generics in other languages may overlook these challenges. The flexibility and metaprogramming capabilities in Zig may not easily translate to other statically-typed languages.

Rust Compiler Development Guide

The Rust compiler processes and transforms your code for compilation. It uses different stages like lexing, parsing, and abstract syntax tree lowering. The compiler aims for correctness, performance, and supporting incremental compilation.

Zig Bits 0x4: Building an HTTP client/server from scratch

The text explains how to create an HTTP client and server from scratch using Zig >=0.11. For the client, you need to set up requests, headers, and wait for responses. The server part involves defining functions to handle requests and running the server to accept connections.

Problems of C, and how Zig addresses them

This blog post discusses issues with C and how Zig addresses them through features like comptime evaluations and improved memory management. Zig offers solutions like error handling improvements and treating everything as an expression, making it a modern alternative to C with enhanced functionalities. The comparison highlights Zig's advantages in areas such as memory management, error handling, and expressive coding practices.

How to use hash map contexts to save memory when doing a string table

The text explains how to save memory when building a string table using hash map contexts. By adapting context APIs, only indexes are stored in the table, reducing memory usage. This method can save 117 KB of memory for a string table with 10 thousand entries.

Notes on partial borrows

The text discusses limitations of the Rust borrow checker and proposes solutions for creating references that borrow from specific subsets of a type. Two approaches, "View types" and "Reference views," are explored to address these limitations and provide more flexibility in borrowing subsets of fields with different lifetimes and mutability. The discussion includes examples, subtyping implications, monomorphization considerations, and the need to update Rust's aliasing model to accommodate view references accessing discontiguous memory regions.

Dioxus Labs + “High-level Rust”

An article criticized Rust's gamedev hype, but its popularity stems from meeting modern programming needs like speed and safety. Efforts are underway to enhance Rust's capabilities for various industries and improve compile times significantly. Proposed enhancements include incremental linking, parallel frontend, and macro expansion caching to make Rust more efficient for developers.

Compile-Time Configuration For Zig Libraries

To expose compile-time configuration options in Zig libraries, developers can use global declarations in the root source file or through Zig's build system. By setting configuration flags, developers can customize behavior such as enabling or disabling assertions in library code. Compile-time configuration can improve performance by allowing certain checks to be done at compile-time rather than runtime.

Generics

Generics in Zig allow for creating data structures and algorithms that can work with different types. By using generics, code can be written once and reused with various data types. Zig's approach to generics involves leveraging compile-time metaprogramming capabilities.

Zig's HashMap - Part 1

Zig's std.HashMap implementation relies on two key functions: hash and eql. The documentation outlines various hash map types and their functionalities, including std.HashMapUnmanaged. AutoHashMap can automatically generate hash functions, but there are limitations, and custom contexts can be provided for more complex keys.

Assorted thoughts on zig (and rust)

Zig is simpler than Rust and offers similar features through compile-time execution. Rust provides strong type safety guarantees for generic functions, while Zig lacks automatic type constraint documentation and may face challenges with IDE support. Zig excels in custom allocators and handling out-of-memory errors, while Rust excels in preventing memory leaks and resource management.

The shape of data

The text discusses the importance of having a clear and consistent data notation in programming languages like Clojure. It emphasizes the advantages of a notation that closely aligns with the in-memory representation of data, making it easier for developers to work with and understand data structures. Additionally, it suggests that a well-designed data model and notation are crucial for efficient data manipulation and code analysis.

The Missing Zig Polymorphism / Runtime Dispatch Reference

The text discusses how Zig lacks built-in polymorphism features like interfaces or virtual methods. It explores creating polymorphism using existing language features in Zig. The author provides a detailed guide on implementing polymorphism in Zig, focusing on dynamic dispatch using function pointers.

Design duality and the expression problem

The text discusses the concept of design duality in programming, focusing on the trade-offs between objects and data representations. It highlights the importance of making conscious design choices when introducing new types, whether as data, objects with extensible implementations, or abstract data types with restricted extensibility. The author emphasizes the need for programming languages to better support and encourage these design considerations.

Random Thoughts On Rust: crates.io And IDEs

The author shares experiences with Rust, praising cargo and crates.io for easy code distribution. They highlight the need for improved library discovery on crates.io and discuss the potential for better IDE support in Rust projects. Despite challenges like type inference, Rust's design enables advanced IDE features that can enhance coding efficiency.

UB Might Be a Wrong Term for Newer Languages Apr 2, 2023

The author suggests that using the term "undefined behavior" in newer languages like Zig and Rust may not be the best choice due to differences in semantics. In C, implementations can define some behaviors left undefined by the standard, but in Rust and Zig, any program showing undefined behavior is considered invalid. The author proposes using terms like "non-trapping programming error" or "invalid behavior" to better convey the intended semantics in these languages.

What Every C Programmer Should Know About Undefined Behavior #1/3

This blog post explains that many seemingly reasonable things in C actually have undefined behavior, leading to common bugs in programs. Undefined behavior in C allows for optimizations that improve performance but can result in unexpected outcomes like formatting your hard drive. Understanding undefined behavior is crucial for C programmers to prevent potential issues and improve code efficiency.

The Rustonomicon

The Rustonomicon is a book for understanding Unsafe Rust programming details. It complements The Rust Programming Language by delving into combining language pieces and potential issues. The book covers topics like (un)safety, creating safe abstractions with unsafe primitives, and working with memory, but does not provide exhaustive API details.

So Many New Systems Programming Languages II

The text discusses new systems programming languages like Rust, Zig, and Odin, highlighting their safety features and syntax. These languages offer improved memory management and safety compared to older languages like C and C++. Rust, in particular, stands out for its memory safety, threading support, and borrow checker.

Arithmetic functions

BQN's arithmetic functions mirror mathematical notation and apply element-wise to arrays. BQN supports basic arithmetic operations like addition, subtraction, multiplication, division, exponentiation, and root functions. Character arithmetic is a distinctive feature allowing manipulation of characters with symbols like + and -.

Problems with BQN

BQN has issues with incoherent monad-dyad pairs and train structures, making code readability and implementation challenging. Modifications like the Constant modifier ˙ attempt to address these challenges. However, there are still limitations in tacit code construction and array reductions that impact the language's usability.

The borrow checker within

The text discusses improvements to Rust's borrow checker to align better with its core design ethos of mutation xor sharing. These changes aim to make Rust code patterns feel more intuitive and work seamlessly with the borrow checker's rules. The proposed enhancements include features like conditional return references, view types, and addressing phased initialization issues.

A decade of developing a programming language

The author spent a decade developing the programming language Inko, transitioning from gradual to static typing and using Rust for the compiler. Recommendations include avoiding gradual typing, self-hosting compilers, and focusing on functionality over performance when building a new language. Building a language for long-term use is a time-consuming process that requires prioritizing user needs over technical complexities.

The Rust I Wanted Had No Future

The author preferred certain design choices in early Rust over the current state, such as the treatment of certain language features and performance considerations. They express a desire for a simpler, less performance-focused language with different priorities than those commonly held in the Rust community. The author reflects on their preferences for language design and the trade-offs they would have made for a more straightforward and expressive programming experience.

Structure and Interpretation of Computer Programs, 2nd ed.

The text discusses key concepts in programming, such as primitive expressions, means of combination, and means of abstraction. It highlights the role of the environment in determining the meaning of symbols in expressions. The evaluation process involves reducing expressions to procedures applied to arguments, leading to a deeper understanding of programming concepts.

Writing an OS in Rust

This blog series provides tutorials on creating a small operating system in the Rust programming language. Each post includes all the necessary code and is accompanied by a corresponding GitHub repository. The series covers topics such as creating a Rust executable without linking the standard library, building a bootable disk image, implementing VGA text mode, performing unit and integration testing, handling CPU exceptions, setting up the interrupt descriptor table, implementing paging and heap allocation, and exploring cooperative multitasking and the async/await feature of Rust. The posts also include status updates and information on supporting the author.

Subcategories