Home Page

Cody Casterline

Twitter

So recently Elon has:

  • Removed twitter identify verification (blue checkmarks are now meaningless?)
  • Shut down 2FA
  • Removed the information about what app someone tweeted from.

It sure is starting to seem like he paid a lot of money to delegitimize it as a communication platform.

Guess you can't get "cancelled" if people and bots are indistinguishable.

Cody Casterline

The weather finally got decently cold and we turned on the heat in the new house. Woke up at 3:15am broiling in my own bed. It turns out the previous owner had programmed the thermostat to go up to 75°F at some point in the night.

75!? I barely let the house get that warm during the summer! So I’m currently in the living room with the sliding door to the back patio cracked so I can cool off. 🥵

Cody Casterline

IDE Inlay Hints

Am I weird in disliking inlay hints?

They're those little notes that your IDE can add to your code to show you what types things are, but they're not actually part of your source code. For an example, see TypeScript v4.4's documentation for inlay hints.

My opinion is that:

  • for well-written code, they fill my screen with redundant noise that makes it more difficult to see the simple code in front of me.
  • for poorly-written code, they're a crutch that you can rely on instead of refactoring the code to be more readable and less fragile.

As an example, take this code:

function main() {
    console.log(foo("Hello", "world"))
}

// Imagine this function is in some other file, so it's not on the same screen.
function foo(target: string, greeting: string) {
    return `${greeting}, ${target}!`
}

If you're looking at just the call site, there's a non-obvious bug here because the foo() function takes two arguments of the same type, and the author of main() passed them to foo() in the wrong order.

Inlay hints propose to help with the issue by showing you function parameter names inline at your call site, like this:

function main() {
    console.log(foo(target: "Hello", greeting: "world"))
}

(target: and greeting: are added, and somehow highlighted to indicate that they're not code.)

Now it's more clear that you've got the arguments in the wrong order. But only if you're looking at the code in an IDE that's providing those inlay hints. If you're looking at just the raw source code (say, while doing code review, or spelunking through Git history), you don't see those hints. The developer is relying on extra features to make only their own workflow easier.

Without inlay hints, it's a bit more obvious that, hey, the ordering here can be ambiguous, I should make that more clear. Maybe we should make foo() more user-friendly?

Lots of languages support named parameters for this reason. TypeScript/JavaScript don't have named parameters directly, but often end up approximating them with object passing:

function foo({target, greeting}: FooArgs) {
    return `${greeting}, ${target}!`
}

interface FooArgs {
    target: string
    greeting: string
}

Now the call site is unambiguous without inlay hints:

foo({greeting: "Hello", target: "world"})

And, even better, our arguments can be in whatever order we want. (This syntax is even nicer in languages like Python or Kotlin that have built-in support for named parameters.)


The prime use of these kinds of hints is when you're forced to use some library that you didn't write that has a poor API. But IMO you're probably still better off writing your own shim that uses better types and/or named parameters to operate with that library, to save yourself the continued headache of dealing with it. Inline hints just let you pretend it's not a problem for just long enough to pass the buck to the next developers that have to read/modify the code.

Cody Casterline

Is Windows 11 Just This Slow?

I have a desktop gaming machine that runs Windows 11. It's not bad at games but it's so slow at things like, opening apps, opening settings, etc.

Is Windows 11 just this slow, or is something wrong?

It's so bad that I ran winsat formal to see if my nvme "hard drive" was somehow misconfigured:

image.png

Results:

> Run Time 00:00:00.00
> Run Time 00:00:00.00
> CPU LZW Compression                          1139.80 MB/s
> CPU AES256 Encryption                        15057.26 MB/s
> CPU Vista Compression                        2834.34 MB/s
> CPU SHA1 Hash                                10656.56 MB/s
> Uniproc CPU LZW Compression                  100.19 MB/s
> Uniproc CPU AES256 Encryption                986.78 MB/s
> Uniproc CPU Vista Compression                250.19 MB/s
> Uniproc CPU SHA1 Hash                        774.01 MB/s
> Memory Performance                           29614.11 MB/s
> Direct3D Batch Performance                   42.00 F/s
> Direct3D Alpha Blend Performance             42.00 F/s
> Direct3D ALU Performance                     42.00 F/s
> Direct3D Texture Load Performance            42.00 F/s
> Direct3D Batch Performance                   42.00 F/s
> Direct3D Alpha Blend Performance             42.00 F/s
> Direct3D ALU Performance                     42.00 F/s
> Direct3D Texture Load Performance            42.00 F/s
> Direct3D Geometry Performance                42.00 F/s
> Direct3D Geometry Performance                42.00 F/s
> Direct3D Constant Buffer Performance         42.00 F/s
> Video Memory Throughput                      279385.00 MB/s
> Dshow Video Encode Time                      0.00000 s
> Dshow Video Decode Time                      0.00000 s
> Media Foundation Decode Time                 0.00000 s
> Disk  Sequential 64.0 Read                   4159.90 MB/s          9.5
> Disk  Random 16.0 Read                       1007.15 MB/s          8.8
> Total Run Time 00:00:11.67

When it can read a Gagabyte per second when doing random access, I don't think the disk is the problem. The CPU is an "AMD Ryzen 7 3700X 8-Core Processor" at 3.59 GHz, which also shouldn't be a problem.

Anybody have tips beyond "LOL don't run Windows"?

Cody Casterline

FeoBlog Upgrades

Well, I started this morning fixing a minor bug in FeoBlog. But then the GitHub Action build failed which sent me down a day-long rabbit hole that ended up with me upgrading from ActixWeb v3 to v4.

It's a bit disappointing because Rust is in theory not supposed to break backward compatibility. But I guess some bits of their API leaked and then got used by libraries I was using.

Not really what I had planned for my Sunday but glad to be on newer versions of things, I guess? 😅

Cody Casterline

Me: You should remain professional and avoid burning bridges.

Facebook recruiter: Hi! Want to use ML to moderate virtual social spaces?

Me: On second thought, …

Cody Casterline

Fresh Looks Cool!

When Node became popular, I never understood the hype around server-side JavaScript, other than that it took what had before then been mostly client-side and making it usable on the server.

But the pitfalls of writing large systems on the server without type checking seemed too great. And I wasn't that fond of JavaScript at the time.

By the time I got around to playing with Node more seriously, TypeScript was a thing. In FeoBlog I wanted to write a browser-based client that would both be a nice UI and a great demo of the client/server capabilities of the system. I chose Svelte as my UI toolkit, and I very much enjoy the features it offers. However, bundling JavaScript for the browser is still a pain to get working. And if you ship everything as a Single-Page Application, you lose out on indexing, and old/underpowered browsers.

FeoBlog actually has remnants of an early server-side template system which it falls back on for that purpose, but you lose out on a lot of features, and it's lost parity with the new Svelte UI. It would be nice if I could write code once and have it render on the server OR the client.

So now I'm starting to see the appeal of server-side JS. But... I don't really want to run Node. Thankfully there's Deno, which I've already enjoyed writing some scripts for.

AND, there's a cool new web framework called Fresh. It's got the same super-fast dev cycle that I've enjoyed with Deno, and the result is code that can render things on the server OR client.

If you want to see a(n incidental) demo of Fresh, take a look at Deno Deploy: Crazy Fast Cloud Functions - Architecture Speedun, which is where I first discovered it.

Looking forward to see where this goes!

Cody Casterline

I do not have a kind view of anyone who brags about not voting. And anyone trying to convince you not to vote has motives you should definitely question.

… But watching the Democrats just roll over on every damned thing is really making it feel like a pointless ritual. Democracy Theater.

  • Continued and renewed efforts at voter suppression
  • Packing the supreme court
  • The timid handling of Jan. 6th insurrectionists. (Including a supreme court justice and former president!)
  • Now, their reaction to Roe v. Wade is
    • "Still not time to end the filibuster"
    • "Need more police protection for these poor SCOTUS judges!"
    • "Let's talk about something else."

They're guaranteed the vote of anyone like me who is against what Republicans are doing, so won't throw away their vote on a further-left party. But as a result they keep moving right to try to pick up more "middle" voters.

Feeling a bit frustrated and hopeless about the future for the U.S.

Just to be clear, though: I'll still be voting.

Cody Casterline

Uhh, WaPo… is this an ad for Trump? "Inaction" as democracy "came under attack"? He was and is continuing to attack democracy by continuing to lie about the legitimacy of the election. He spoke at the rally that ended up invading the capitol while the election was being finalized! And told them to do it! WTF kind of reframing is this?

This is as bad as the bootlicking "shots were fired and someone died at an altercation involving police" trope.

Screen Shot 2022-05-09 at 1.57.32 PM.jpg

Cody Casterline

I've been writing Java since before Generics and still ran into this landmine:

Coworker (reviewing my code): container.contains(null) can throw a NullPointerException.

Me: I don't think so, the docs say:

Returns true if this collection contains the specified element. More formally, returns true if and only if this collection contains at least one element e such that (o==null ? e==null : o.equals(e)).

And this code works as I expect:

import java.util.*;

public class Contains {
    public static void main(String[] args) {

        // Interestingly, List.of requires all its elements be non-null. Weird.
        // var list1 = List.of("foo", "bar", "baz");
        // var list2 = List.of("foo", "bar", null);

        var list1 = makeCollection("foo", "bar", "baz");
        var list2 = makeCollection("foo", "bar", null);
        
        check(list1);
        check(list2);
    }

    private static Collection<String> makeCollection(String... args) {
        // return Arrays.asList(args);
        return new HashSet<String>(Arrays.asList(args));
    }

    private static void check (Collection<String> list) {
        System.out.println(list.contains(null));
    }
}

Coworker: read a bit further. Docs also say:

Throws […] NullPointerException - if the specified element is null and this collection does not permit null elements (optional)

… sure enough. In my case I'm actually using a Set.of(predefined, elements), and that particular implementation will throw if passed a null.

UGHHh. NULLS.

FWIW, Kotlin handles this much more nicely:

fun main() {
    val c1 = setOf("foo", "bar")
    val c2 = setOf("foo", null)

    
    val value: String? = null
    println(c1.contains(value))
    println(c2.contains(value))
}

… though you can only depend on that sane behavior when using its setOf() constructor. If you might ever be passed a non-null-safe Java Collection you're back to needing to protect yourself against NPEs.