Up to Main Index                         Up to Journal for September, 2025

                    JOURNAL FOR SUNDAY 7TH SEPTEMBER, 2025
______________________________________________________________________________

SUBJECT: Thoughts on the MacBook Pro M4
   DATE: Sun  7 Sep 15:33:36 BST 2025

To re-cap, I needed a MacBook in order to work for Apple. I ordered a silver
MacBook Pro M4 (4× P cores @ 4.5Ghz, 6× E cores @ 2.9Ghz), 32Gb RAM, 1Tb SSD,
14.2" (3024×1964) nano-texture display, US English keyboard, upgraded 96W
charger for fast charging.

I’ve now been using the MacBook 8 hours/day, 5 days a week for 3 weeks. Here
are my thoughts so far, and a few of my own benchmarks. Bear in mind I’ve been
a Linux user for decades which may bias my opinions somewhat.

The MacBook Pro is a powerful, commercial, well supported ARM 64-bit system.
The flavour of ARM used in the M4 CPU is ARMv9.2-A without scalable vector
extensions (SVE)[1]. The M4 seems very efficient. In a typical day I am
editing code, compiling, testing, running databases, browsing, video calls,
etc. I use 40-50% of the battery.

The MacBook is average at 3.4 pounds (1.55 kg) with an aluminium case. On the
front of the case by the trackpad is a sculpted cut-out which has very sharp
pointy edges. On the underside of the MacBook are some air vent slots which
also have a very sharp edge to them. I went for the silver model which does
not seem to be much of a fingerprint magnet.

The nano-texture display is matte bliss, I love it. It’s not a touchscreen,
but I can look at it all day long with no glare, reflections or fingerprints.
I tend to leave the automatic brightness adjustment on and have the keyboard
backlit.

While the screen is fantastic, the MacBook is let down by it’s keyboard. I
ordered the US English layout instead of the default British English layout
for the UK. I just don’t like ISO Enter keys. Usually the double quotes (")
and at symbol (@) are swapped on a British keyboard with Shift-2 being the
quotes — a real pain when programming. This isn’t so on the MacBook.

Bear in mind I’ve used a Happy Hacking keyboard (HHKB) for over three decades.
But, Apple seems to really hate programmers :( The keyboard itself has nearly
zero travel and little feedback — it feels dead. I touch type badly, unless
I’m not thinking about typing, I can’t even do that on the MacBook.

As a Vim user, I use the Escape key a lot, all day long. It’s in the usual
place — but seems miles away across the keyboard. Luckily Apple make it easy
to setup the Caps Lock key as another Escape key. There is a Delete key that
backspaces, but no Backspace key. I have to use the function key with
Fn+Delete to forward delete.

Other keys I use all the time are the cursor keys. The MacBook has a horrible
inverted T layout for them where the keys are only half the size of the rest
of the keys. Needless to say they are horrible to use. I now use `h’, `j’, `k’
and `l’ a lot more frequently to properly move around in Vim :P

There are no Home, End, Page Up or Page Down keys. Instead it’s Fn+←, Fn+→,
Fn+↑ and Fn+↓. I use Control+← and Control+→ to switch desktops a lot. The
number of times I hit Control+↓ for page down only to enter App Expose mode
instead is infuriating.

The keyboard has four normal modifier keys: Function, Control, Option and
Command. These can be a nightmare. Command is often used instead of Control,
except when using the terminal application. Then you get combinations like:
Function+Control+Shift+←. That particular combo moves the active window to the
left half of the screen and the second window to the right half.

The one good thing about the keyboard is the backlight. Subjective, but I
quite like it.

Then there is macos, currently Sequoia 15.6.1. In general I don’t like GUIs
and mice, trackpads or trackballs. I live on the command line, in a terminal,
and drive everything via the keyboard. The GUI is pretty enough I suppose.
Quite snappy if you turn off a tonne of effects and animations. The biggest
thing I miss from my Linux desktop is automatic window tiling :(

However macos is Unix, derived from OPENSTEP and FreeBSD. It is even Unix 03
certified. From the command line, coming from Linux, everything seems mostly
familiar, if somewhat quirky. For example the shell is zsh, unless you want an
ancient version of Bash. Vim is quite up to date — I only had to tweak my
standard setup a little. Most of the usual commands are there. Although they
may be outdated versions and/or missing flags, options or features.

Of course I put Go on the MacBook and ran a few tests :)

I installed Go 1.25.0 using the official installer. I then downloaded the Go
1.25.1 sources. I used Go 1.25.0 to compile Go 1.25.1 from source:


          MackBook Pro:  4m 54s
      Intel i9 Desktop:  1m 44s -  3m10s (64.6%) quicker
        Raspberry Pi 4: 41m 35s - 36m41s (748.6%) slower


When using Go on the MacBook I noticed that the linking phase is particularly
slow. One way to improve this is to build omitting the Dwarf debugging symbols
by passing -ldflags="-w" to go build. Doing this for one build in particular
reduced the time from 17 seconds to less than 5 seconds.

I included the Raspberry Pi 4, running 64-bit Raspberry Pi OS as it’s the
closest comparable ARM system I have access to. The desktop is an Intel
i9-12900T (8× P cores @ 4.9Ghz (16 threads), 8× E cores @ 3.6Ghz), 64Gb RAM,
2× 1Tb SSD in RAID 1).

Next I ran Mere, my own programming language, with some of my standard
benchmarks:


                        MacBook  Desktop            RPi4
                        ───────  ─────────────────  ────────────────────
     loop-counter       07.472s  09.780s ( +30.9%)  1m09.843s ( +834.7%)
     counter            07.690s  09.897s ( +28.7%)  1m10.827s ( +821.0%)
     indexed-counter    19.216s  41.408s (+115.5%)  3m40.519s (+1047.6%)
     eratosthenes-sieve 08.034s  10.538s ( +31.2%)  1m18.336s ( +875.1%)


Note that by design Mere is only single threaded. The loop-counter benchmark
counts from 1 to 100,000,000 using a for-next loop:


    println "123456789%"
    for x = 0; x < 100_000_000 ; x++
      is x % 10_000_000 == 0; print "."
    next
    println "✓"
    println elapsed()["stampMilli"]


The counter benchmark is similar but uses a simple variable and a goto:


    x = 0
    loop:
      x++
      is x % 10_000_000 == 0; print "."
      is x < 100_000_000; goto loop


The indexed-counter benchmark is similar, but uses an indexed array:


    x = []int 0
    loop:
      x[0]++
      is x[0] % 10_000_000 == 0; print "."
      is x[0] < 100_000_000; goto loop


The eratosthenes-sieve[2] benchmark finds all of the prime numbers below
10,000,000 — of which there are 664,579. This is a nice benchmark as it makes
use of constants, arrays, loops, loop control and plenty of math.

So what do I think of the MacBook? Overall I would say it’s a nice enough
machine. Battery life seems good. The screen and keyboard backlight are
excellent. I can do all of my development work. Performance is a little hit
and miss. For example, when benchmarking, the loop—counter would sometimes
take twice as long to run. For me, the main issue is the keyboard, but it’s
usable with some hacks and perseverance.

--
Diddymus

  [1] This makes it closer to an ARMv8.7-A CPU.
  [2] Mere version of Sieve of Eratosthenes:


        # Sieve of Eratosthenes
        #
        # See: https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

        const LIMIT = 10_000_000
        const NOT_PRIME = -1

        # Initialise sieve
        sieve = dim 0 LIMIT+1
        sieve[0] sieve[1] <- NOT_PRIME NOT_PRIME

        for x = 2; x <= LIMIT; x++
          sieve[x] = x
        next

        # Find prime numbers
        for n=2; n>0;
          for x = n+n; x <= LIMIT; x += n
            sieve[x] = NOT_PRIME
          next

          N = NOT_PRIME
          for x = n+1; x <= LIMIT; x++
            if sieve[x] > NOT_PRIME
              N = x
              break
            fi
          next
          n = N
        next

        # Count prime numbers
        count = 0
        range ; n; sieve
          is n == NOT_PRIME; continue
          count++
        next
        println "Primes: " count
        println elapsed()["stampMilli"]


  Up to Main Index                         Up to Journal for September, 2025