Saturday, November 09, 2024

Current Tools

I'm posting this mostly because it's interesting to look back and see how things change.

Hardware

Desktop - 27" 2017 iMac Pro. Considering it's 8 years old, performance is still quite reasonable. It's a 3.2 GHz 8 core Intel Xeon with 64 GB of DDR4 memory.

Laptop - 16" 2019 MacBook Pro with a 2.3 GHz 8 core Intel Core i9, also with 64 GB of DDR4 memory.

Apple could almost certainly have sold me a new machine, if they still made 27" iMacs, and if they didn't charge a fortune to get 64 GB of memory. Also, moving to an Apple cpu would make it harder to run a Windows VM.

Keyboard - For the last 5 years I've been using Varmilo mechanical keyboard with Cherry MX Silver switches.

NAS - Synology DS920+ NAS with four 10 TB drives for 26 TB of redundant capacity.

Wifi - Netgear Orbi RBR50 + Satellite

Software

IDE/editor - VSCodium - the open source version of VSCode, without tracking. Prior to VSCode I used Microsoft Visual Studio for C++ and Eclipse for Java.

Programming Language - Go - I made a bet on Go over 10 years when it was still new. Back then it was barely production ready. Luckily, it has improved hugely and has become relatively mainstream. Like any language, it has its quirks, but for the most part I'm happy with it. Rust is interesting, but Suneido needs garbage collection. I don't miss C++ or Java.

Version Control - Git & Github

Parallels VM's for Windows and Linux

Browser - Firefox - I'm not particularly a fan of Firefox and I'd rather Mozilla would focus on making a good browser instead of going off on tangents like the AI bandwagon. But I hate the thought of Google having a 100% monopoly on browsers. I could use Safari but I'm not crazy about the megacorp that Apple has become either.

Notes - Obsidian - I used Evernote for a long time, then moved to Joplin, and finally to Obsidian for the last few years. I like that it doesn't have a proprietary database, just markdown files in directories. And I'm happy with its wysywyg markdown editor. Unfortunately, it's not open source.

Dropbox - I used to rely on Dropbox to keep my office and home computers in sync. Now that I work from home full time it's more to keep my desktop and laptop in sync. It's also nice to be able to access files from my tablet or phone occasionally.

Antivirus - Bitdefender

Cloud Backups - Backblaze

Sync - Chronosync - to mirror my 5 TB of photos to the Synology NAS

Local Backups - Restic - More for developers than consumers but seems to work well. I've tried various other backup programs and haven't liked any of them.

Apple's Time Machine is a great concept but it's never been reliable for me. It'll stop backup up without any kind of notification. Or the backups will become corrupted and you have to start over. I suspect the combination of using a NAS and having a huge number of files is too much for it.

Sunday, November 03, 2024

Go range over integer gotcha

Go version 1.22 introduced the ability to do a for loop ranging over an integer. For example:

for i := range 5

This is normally explained as equivalent to:

for i := 0; i < 5; i++

Recently I decided to go through my code and update to the new style. It was mostly fairly mechanical search and replace. But when I finished and ran the tests, there were multiple failures. I figured I'd just made a typo somewhere in my editing. But that wasn't the case. The places that were failing were modifying the loop variable. For example:

for i := 0; i < 5; i++ {
    fmt.Println(i)
    i++
}
=> 0, 2, 4

for i := range 5 {
    fmt.Println(i)
    i++
}
=> 0, 1, 2, 3, 4

I don't see anything in the language spec about this.

The accepted proposal says:

If n is an integer type, then for x := range n { ... } would be completely equivalent to for x := T(0); x < n; x++ { ... }, where T is the type of n (assuming x is not modified in the loop body).

There might be some discussion of this but I didn't find it. It may relate to how closures capture the loop variable. In Go 1.22 this was changed so each iteration has its own iteration variable(s). So if each loop gets its own variable that kind of explains why modifying it doesn't have any effect on subsequent iterations.

But even if you declare the variable outside the for statement, it still behaves the same:

var i int
for i = range 5 {
    fmt.Println(i)
    i++
}
=> 0, 1, 2, 3, 4

It's not really a major issue, it just means if you want to modify the loop variable you need to use the old style of for loop. The unfortunate part is that you can't mechanically replace one with the other. You have to check whether the body of the loop modifies the variable. I don't typically do this but occasionally it can be useful.