Making Illegal States Unrepresentable
> It’s a concept I find very helpful. But if you look for examples online almost everything either “let’s prevent dividing-by-zero” or “let’s enumerate the cases in a data type”. We can more creative than that! Some examples of “illegal states unrepresentable” that I found useful but have not seen anyone else talk about online:
Porting to TypeScript Solved Our API Woes
> With the Ruby backend, we sometimes forgot that a particular API property held an array of strings, not a single string. Sometimes we changed a piece of the API that was referenced in multiple places but forgot to update one of those places. These are normal dynamic language problems in any system whose tests don’t have 100% test coverage. (And it will still happen even with 100% coverage; it’s just less likely.)
Dynamically scoped variables in Go
> What we want is to be able to access a variable whose declaration is neither global, or local to the function, but somewhere higher in the call stack. This is called dynamic scoping. Go doesn’t support dynamic scoping, but it turns out, for restricted cases, we can fake it.
How can I have a C++ function that returns different types depending on what the caller wants?
Fighting the Async fragmentation
> This is about some dead ends when trying to fix the problem of Rust’s async networking fragmentation. I haven’t been successful, but I can at least share what I tried and discovered, maybe someone else is having the same bugging feeling so they don’t have to repeat them. Or just maybe some of the approaches would work for some other problems. And because we have a bunch of success stories out there, having some failure stories to balance it doesn’t hurt.
The story of a V8 performance cliff in React
Models of Generics and Metaprogramming: Go, Rust, Swift, D and More
> In some domains of programming it’s common to want to write a data structure or algorithm that can work with elements of many different types, such as a generic list or a sorting algorithm that only needs a comparison function. Different programming languages have come up with all sorts of solutions to this problem: From just pointing people to existing general features that can be useful for the purpose (e.g C, Go) to generics systems so powerful they become Turing-complete (e.g. Rust, C++). In this post I’m going to take you on a tour of the generics systems in many different languages and how they are implemented. I’ll start from how languages without a special generics system like C solve the problem and then I’ll show how gradually adding extensions in different directions leads to the systems found in other languages.
Detecting in C++ whether a type is defined
How 2 TypeScript: Get the last item type from a tuple of types
> Kinda like a normal array lookup!
> But what if you don’t know the length of the tuple? Hmm... how do we get TypeScript to tell us the length and then let us use that length to pick out the last item, all at compile time?
What should you do if somebody passes a null pointer for a parameter that should never be null? What if it’s a Windows Runtime class?
> If you put the cases of in-process and out-of-process callers together, you see that the conclusion is “Go ahead and dereference those pointers.” If the caller is in-process, then it’s okay to crash because you are crashing the caller’s process (which happens to be the same process that you are in). If the caller is out-of-process, then the RPC layer will prevent invalid null pointers from getting through.
> There’s an additional wrinkle to this general principle, however, for the case where you are implementing a Windows Runtime class.
Go has no type for types in the language
> Part of what this means is that in Go, you cannot write an expression like ‘x := y.(type)’ not just because the language syntax forbids it, but because there is no standard type that the variable x can be. If you wanted to allow this, you would have to create a new Go type and define what its behavior was.
A new runtime for Nim
> In this blog post I explore how the full Nim language can be used without a tracing garbage collector. Since strings and sequences in Nim can also be implemented with destructors the puzzle to solve is what to do with Nim’s ref pointers and new keyword.
> Type-specific allocation turns every “use after free” bug into a logical bug but no memory corruption can happen. So ... we have already accomplished “memory safety without a GC”. It didn’t require a borrow checker nor an advanced type system. It is interesting to compare this to an example that uses array indexing instead of pointers:
.NET Internals Cookbook
> In this series I answer various .NET questions. Some of them are asked during interviews, some of them I see on the internet, some of them are completely made up. The goal is to provide short answer with links to references if needed. This is by no means a .NET tutorial or experts reference, this is just a bunch of useful answers to refresh your knowledge.
Some of this gets pretty deep actually.
Typed nils in Go 2
> This is an experience report about a gotcha in Go that catches every Go programmer at least once. The following program is extracted from a larger version that caused my co-workers to lose several hours today.
> You’ve probably realised the cause of this problem is the dreaded typed nil, a gotcha that has its own entry in the Go FAQ. The typed nil emerges as a result of the definition of a interface type; a structure which contains the concrete type of the value stored in the interface, and the value itself.
> Typed nils are an entirely logical result of the way dynamic types, aka interfaces, are implemented, but are almost never what the programmer wanted.
The linked post is a good read as well: https://research.swtch.com/interfaces
to increment some counter on the page
> node.innerText += 1 doesn’t work (0 → 01 → 011 → ⋯), but node.innerText -= -1 works fine (0 → 1 → 2 → ⋯)
> However, newValue is returned, not the value that was actually stored in the array!
C++ Standard Ranges
> As you may have heard by now, Ranges got merged and will be part of C++20. This is huge news and represents probably the biggest shift the Standard Library has seen since it was first standardized way back in 1998.
> Future blog posts will discuss how we got here and the gritty details of how the old stuff and the new stuff play together (we’re C++ programmers, we love gritty details), but this post is strictly about the what.
Type erasure and reification
> In this post I’d like to discuss the concepts of type erasure and reification in programming languages. I don’t intend to dive very deeply into the specific rules of any particular language; rather, the post is going to present several simple examples in multiple languages, hoping to provide enough intuition and background for a more serious study, if necessary. As you’ll see, the actual concepts are very simple and familiar. Deeper details of specific languages pertain more to the idiosyncrasies of those languages’ semantics and implementations.
Building C# 8.0
> Here’s an overview of the most significant features slated for C# 8.0. There are a number of smaller improvements in the works as well, which will trickle out over the coming months.
You can’t “turn off the borrow checker” in Rust
> Every once in a while, someone will talk about unsafe in Rust, and how it “turns off the borrow checker.” I think this framing leads to misconceptions about unsafe and how it interacts with safe code.
> So what does unsafe actually do? Unsafe Rust is a superset of Safe Rust. Unsafe never changes the semantics of Rust code. It instead adds new features that you can only use inside an unsafe block.