Timeline

I want to make an MMORPG…

A demo session of the eleven chat client

I hear that’s the thing beginning programmers say to game developers. One of those naïve things people want to do who don’t know any better. But while I agree it’s an illusion to think we, as beginners, and a single person, could just write out the next World of Warcraft, I can totally understand why one would want to do it.

The reason why MMORPGs are near-impossible to pull off is the same reason that makes them so interesting: They’re a big honkin’ fun challenge. They combine all the fun tech and its problems. And they’re fun to use and well regarded as well. Think about the challenges:

  • Graphics and animation – often even on low-end machines, often in 3D, with bone meshes, inverse kinematics, several detail levels of models and customizable weapons, avatars etc.
     
  • User interfaces – often completely custom written on top of low-level 3D engines.
     
  • Maths – figuring out how leveling needs to work, how different weapons interact, but also pathfinding, and graph theory for the NPCs’ limited “AI”.
     
  • Social and economic science Managing interaction between players to encourage fun, discourage trolls and griefers, and balance gameplay between beginners and hardcore gamers or at least keep them from interfering with each other’s enjoyment. Often also involving trading systems.
     
  • Networking – Including load-balancing of lots of users, accounting for input lag, streaming level data and video.
     
  • Security – In addition to traditional hackers, you’ve got lots of players and script kiddies who are fans and are just trying to game the system a little for personal benefit.
     
  • Storytelling and content-creation – Non-sequential stories depending on user decisions, and lots of other content overlapping with graphics and animation to keep players coming back, and to bridge the gaps between story missions.
     
  • Databases – Includes storing all user information with good performance under heavy load and with transactional integrity even on sudden disconnects (e.g. so you don’t “pay” for an item and then don’t receive it).

I think the only thing from computing you don’t need to know how to do for an MMORPG is how to build hardware dongles and write their drivers.

And you want to build one?

Well, yes and no. I wouldn’t really want to run an MMORPG. I also already have a job. And I suck at 3D modeling. But a bunch of these problems are intriguing and fun to think about, so I’m tinkering with ideas, writing little test projects that implement this or that part that one would need for such a game. I’ve also been reading a lot of stuff on Stack Exchange’s GameDev sub-section, for example a question on how one calculates the leveling of characters.

So you might just see me blog a little more about game design in the future. Or this may be the first and only post I’ll do about this topic before I lose interest, who knows.

So what have you made so far?

Having played a couple hundred hours of Star Trek Online, I realized that a lot of the program felt like a graphical client talking to an IRC server that had a bot that ran the actual game logic. So the networking layer is what I wanted to start with. I’m not sticking to any IRC specification, but simply started implementing a modular chat server that is kinda similar to IRC, and has chatrooms (which are useful for separating maps and their communications overhead), and of course user accounts with blocking mechanisms.

The advantage of this approach is that, even if I don’t ever make a game that uses this, it may be useful to other people who are looking for some sort of networking layer, be it for chat, or for some other social program. And at the very least it let me practice sockets and is allowing me to learn how to use TLS to encrypt a connection.

Where will it go from there?

Well, the basic idea is to then build the “bot” that actually implements the game. It will live in chat rooms, one for each map (i.e. a city, planet or whatever) and let you connect to one. Once in a chatroom, it will send you all the data you need to get started.

In the case of a graphical game that would be models, level maps etc. as well as pending messages you may have (e.g. “crafting operation completed” or “spell prepared” etc., but also remind you of mission rewards you need to accept or present a mission introduction you haven’t confirmed as read yet). It will also send status about the player, like inventory, cooldowns of abilities you’ve recently used etc. and update you about changes in any of these, and inform you of nearby enemies and allies and what they’re doing (to you?).

You can now send commands to this bot, which include character movements, casting a spell, firing a weapon or whatever.

So, oddly, all of this feels a lot like it can be implemented fairly elegantly and simply as sort of an IRC/e-mail hybrid with read receipts. And this can all be done without needing to have a client, nor any graphics. Heck, you could test this by writing an ASCII client that looks like NetHack.

The game map

The game is streamed, so it might not be the best idea to download the entire map at once. Especially if you want to be able to maybe have large or endless maps, or maps that can be re-used for different purposes. You’d want to be able to only load those parts of maps that the user visits for this mission.

So the obvious approach so far seems to be to just split the map up into tiles that have relative locations to each other and then load the tiles surrounding your player’s location, and when the player moves load additional ones so you never run out. This can be a 2D tiled map to start with, but can easily be expanded into cubes that can also be stacked vertically.

To simplify, I’ll probably have only a 2D coordinate inside each tile. The vertical coordinate for a player or NPC inside its particular tile-cube will then simply be decided by the ground level underneath it. Since we can connect the tiles arbitrarily, stairs would still be possible to make. Just create a tile with the stair model at its end:

StairsOnTileMapExample

The player will seem to walk up the stairs because the ground level rises. If we now connect the left edge of the tile to the tile one level up, the user will easily walk up one level. The only downside of this approach is that a character won’t be able to hide under the stairs.

Another advantage of using such tiles is that they can be used for collision testing. You can just block an entire tile from being stood on.

That wasn’t too hard … ?

Well, this is still missing any item management, interaction, mission objective enforcement, combat or pathfinding mechanisms, so it’s far from a game, but yeah, it’s probably what I will try to implement after the chat server is finished. Or maybe I’ll just — oh look a butterfly.

How Drawing on iOS Works

Someone on Stack Overflow recently asked about the various drawing APIs on iOS, and what the difference between using CALayers directly or using them indirectly through UIViews is, and how CoreGraphics (aka Quartz) fits into the equation. Here is the answer I gave:

The difference is that UIView and CALayer essentially deal in fixed images. These images are uploaded to the graphics card (if you know OpenGL, think of an image as a texture, and a UIView/CALayer as a polygon showing such a texture). Once an image is on the GPU, it can be drawn very quickly, and even several times, and (with a slight performance penalty) even with varying levels of alpha transparency on top of other images.

CoreGraphics (or Quartz) is an API for generating images. It takes a pixel buffer (again, think OpenGL texture) and changes individual pixels inside it. This all happens in RAM and on the CPU, and only once Quartz is done, does the image get “flushed” back to the GPU. This round-trip of getting an image from the GPU, changing it, then uploading the whole image (or at least a comparatively large chunk of it) back to the GPU is rather slow. Also, the actual drawing that Quartz does, while really fast for what you are doing, is way slower than what the GPU does.

That’s obvious, considering the GPU is mostly moving around unchanged pixels in big chunks. Quartz does random-access of pixels and shares the CPU with networking, audio etc. Also, if you have several elements that you draw using Quartz at the same time, you have to re-draw all of them when one changes, then upload the whole chunk, while if you change one image and then let UIViews or CALayers paste it onto your other images, you can get away with uploading much smaller amounts of data to the GPU.

When you don’t implement -drawRect:, most views can just be optimized away. They don’t contain any pixels, so can’t draw anything. Other views, like UIImageView, only draw a UIImage (which, again, is essentially a reference to a texture, which has probably already been loaded onto the GPU). So if you draw the same UIImage 5 times using a UIImageView, it is only uploaded to the GPU once, and then drawn to the display in 5 different locations, saving us time and CPU.

When you implement -drawRect:, this causes a new image to be created. You then draw into that on the CPU using Quartz. If you draw a UIImage in your drawRect, it likely downloads the image from the GPU, copies it into the image you’re drawing to, and once you’re done, uploads this second copy of the image back to the graphics card. So you’re using twice the GPU memory on the device.

So the fastest way to draw is usually to keep static content separated from changing content (in separate UIViews/UIView subclasses/CALayers). Load static content as a UIImage and draw it using a UIImageView and put content generated dynamically at runtime in a drawRect. If you have content that gets drawn repeatedly, but by itself doesn’t change (I.e. 3 icons that get shown in the same slot to indicate some status) use UIImageView as well.

One caveat: There is such a thing as having too many UIViews. Particularly transparent areas take a bigger toll on the GPU to draw, because they need to be mixed with other pixels behind them when displayed. This is why you can mark a UIView as “opaque”, to indicate to the GPU that it can just obliterate everything behind that image.

If you have content that is generated dynamically at runtime but stays the same for the duration of the application’s lifetime (e.g. a label containing the user name) it may actually make sense to just draw the whole thing once using Quartz, with the text, the button border etc., as part of the background. But that’s usually an optimization that’s not needed unless the Instruments app tells you differently.

What it means to be a gamer

I’m reading this GG stuff and how they send threats and … I just hope it ends well and those @$$es get prosecuted for their horrible deeds.

When women simply voice their opinion on games, or make a game and get threatened with rape and death and have to leave their homes, and people support the initiative in whose name those threats have been made instead of founding their own, more sensible initiative, it is a sign of a mob.

I play games. And I’m embarrassed by these childish, hate-mongering people. Games are about challenge, fun, escapism, expression, inclusion. GG is pure newspeak. They start at good things, then reverse them. Supporting something is manipulation, while benefiting from something is OK? Really?

Intel made a huge mistake by giving in to the GG terrorist demands and taking down their ads. But they can fix it. They can take a stance. Intel can show them that you don’t blackmail a company that is in the right with hate speech.

I try not to be political on this blog, but that’s where these monsters have driven me. I don’t want this world they have given me. I want great developers and great journalists to be safe from these monsters. I don’t know what to do. But I can’t be quiet about this.

To good people supporting GG: Get away from this toxic group. Come up with your own that expresses what you believe, because GG surely doesn’t. Don’t risk being complicit in the proliferation of hate.

Getting started with Star Trek Online

My character selection screen on STO.

I’ve never considered myself a gamer, I never owned a dedicated gaming device, and generally only played games like the LucasArts adventures (including successors like Telltale and Double Fine’s Broken Age), or Myst, but recently I came across Star Trek Online and caught the bug. Since STO is a rather large game, it took me a while to get into the jargon and understand it. So I thought I’d present my findings here for others who would like to try out this game.

For the TL;DR crowd, the short blurb is that STO is a massively multiplayer online RPG, but with enough story and single-player missions (some very moody and scary) that even story-puzzle-adventure nerds like me can enjoy it without feeling that the grinding is too much of an err… grind. It is set in the classic Star Trek universe of the TV series, so is a nice Sci-fi spaceship setting. The major downside is that STO’s system requirements are rather narrow, and not easy to find, and the game will just randomly crash if you don’t meet them instead of alerting you to the mismatch beforehand.

How do I get it?

STO is a free download at The STO product page at ARC games, or from Steam. Note that, while the game is not even a 60MB download, that’s not all. Once you’ve started that app and created a new STO account, it will download about 8GB of “patches” containing the actual game data. These “patches” are a common occurrence, but subsequent ones aren’t generally as huge as the initial one.

I’ve got it, how do I play?

Create new Character button

In STO you have a main character, who is the only playable character, plus in the process of the game, you get Bridge Officers, which are the NPCs that make up your crew that accompany you on ground and space missions and that support you. Your main character belongs to one of 3 factions: Federation, Klingon, or Romulan.

Character selection screen

You have to pick a gender and race for your character. Available races are:

Federation Humans, Vulcans, Andorians etc.
Klingon Klingons, Orions, Gorn, Nausicaan etc.
Romulan Romulans.

All races also have a general “Alien” race that gives you a lot of freedom in designing your character. You start from a general human build, but can add brow ridges, hair, crazy skin colors, patterns, and take the proportions of the character to slightly more non-human levels (think more Dr. Phlox, you can’t really build an overweight or flat-chested person in this game).

You also pick a career (“class”) for your character: engineering, science or tactical., The career affects the extra abilities your character will have beyond being able to run/fly around and shoot. Scientist is a “healer” character supporting other characters, while Engineering means that you build little drones and force field shields and other more defensive or indirect attack mechanisms to support yourself, while tactical means that you’re the front-line person to throw grenades and lunge and kick at the enemies.

Among the factions you can pick, Romulans are a special one, because after the destruction of their homeworld (the only reference to an event from the new movies), each Romulan can choose for themselves whether they want to side with the Federation or the Klingons. The advantage of this is that you get cool Vulcan-looking aliens (or alien-looking ones), plus cool Romulan spaceships, but you also get missions, uniforms and items of one of the other factions. Sadly, you don’t get all of them. While Klingon-allied Romulans get cool Klingon uniforms, the Federation-allied ones get a horrible Federation/Romulan mashup costume.

If you’re following along, you may have noticed that I left out a few races. You see, STO is a free-to-play game. The way they make their money, is by selling you certain things beyond the core game. Among these things are additional races for your player character, and other extra items like clothes or cooler ships. You can tell those by a little coin icon with a “Z” in it, as in “ZEN”.

ZENs are roughly equivalent to Euro-cents in value, and can be bought on their web site. Once you have ZENs, you can go to the “C-Store” (the little coin-icon-and-“store” in the lower left of your onscreen mini-map) and buy stuff there, but note that especially costumes seem to be mostly available for Federation characters. There are a few more for Klingon characters, and for Romulans of either faction it seems you’re way more limited. Also, each faction has its own ships, and usually there are more paid ships for Federation characters than for Klingons, and again more Klingon ships than Romulan ones.

Advanced customization of character outfit

Note that picking a character’s race, class and gender (and later faction, if applicable) are the only permanent things about your character. You can, at almost any point in the game, fly back to base and go to a “taylor” to change your outfit, picking from the free items that you see when you create your character (plus a few more you get as you choose a faction or get promoted, and of course any you decide to buy). This outfit, oddly, includes your skin color, head shape, height etc. For the “alien” race, that means you can pretty much completely change the way your character looks, and later you can have a “uniform” and a “costume” outfit slot which offers different possibilities, and some new costume parts appear as your character’s rank increases.

There’s also a “save outfit” button with which you can save and load outfits into these slots, giving you a near-infinite number of saved outfits, but it seems those are cleared after a while and are saved locally on your Mac.

One warning: The switcher at the bottom of the initial character creation page looks like you could switch from Appearance back to Species and Career. Don’t. You will lose any customizations you’ve done to the character’s appearance if you do so. The same happens when you toggle a character’s gender when customizing head/body/uniform of your character.

On the last screen, you name your character and your first(!) ship. Then it’s off to the tutorial.

A ground mission in Federation space dock

The tutorials and gameplay at this point are pretty self-explanatory (that’s the point, after all). Just like later in the game, you’ll get windows popping up that offer you missions, and you can choose to accept or decline them. Sometimes you’ll get additional missions while you’re on another. It’s fine to click those away, you can always go back to the Missions window later and pick a mission you’ve been offered under “episodes”. One thing to know: There are two kinds of gameplay. Space, and Ground. Space means you’re controlling a ship (tip for users of Mac keyboards without a num pad: You can set a secondary key combination for navigating in space battles. Set that to the arrow keys, that way you can use both hands. The default has the number keys as triggers, which places your hands on top of each other when using WASD for steering. You can now control your ship the same way you steer your character during ground battles).

The tray with weapons arranged by what way weapons face.

Also, you can right-click-and-drag items in the little tray at the bottom to change their order (and thus which num key they’re triggered by). That way you can e.g. move the melee attack (pushing away an enemy when you’re in tight quarters with a punch or the end of your weapon) on 1, where your left pinky finger is, and your weapon and its secondary fire mode on 2 and 3, and then your favorite other special action on 4.

Similarly, I arrange my weapons so that the ones that mainly face front (see the thick part of the circle in the icon) are at the left, the one that have a big radius in the middle, and the one that face backwards on the right, so I can fluidly transfer firepower as the ship turns. (You can even add rows to the tray using the button in its lower right — The C1 row triggers on Ctrl-1 etc., the A1 row on Alt-1 etc.)

Now you can get playing, have fun!

Space Travel

The Galaxy Map

To travel through space, you can bring up a larger main map. This map has 3 sections. A pretty graphical map that shows you (in a slightly compacted form) which sectors of space lie near which, so you can plan long-distance trips. The idea here is that each sector is a separate location containing several star systems and space stations. Once you’re at the edge of a star system, you are offered to warp to the next sector. Note that a few “blocks” (groups of sectors) are actually farther apart, but have been moved near each other and connected with lines. So e.g. going west from Eta Eridani block will not take you to Gamma Orionis Block. Rather, it will take you to Drellis Block. Also note that the blocks’ different colors indicate what faction they belong to. Some blocks can be traveled to by whoever you are, but e.g. a Klingon-affiliated Romulan can not just go into Sirius Block where Earth is.

Then there’s the Area Map, which is the classic game map that shows you where your character/ship is right now. This is the nice interactive map of your current location, where you can click stuff to fly there. You can also click little triangles at the edges here to plot a course to the edge of a particular adjacent block so you can warp there. This may seem a bit silly if you’re just playing missions (“PvE”, player vs. enemy), like I do so far, but in multiplayer games (“PvP or player vs. player), that means that the enemy can’t just warp in additional troops arbitrarily, they have to have been prepared and waiting nearby.

Third, there’s the system list. When you’re in sector space (i.e. not in a solar system where space fights happen, or on a planet/inside a station/inside a ship where ground combat occurs), you can see a list of all the systems/stations and adjoining sectors here, to more easily find them. Note also, that the little summary of mission objectives at the right of your screen usually only mentions the name of the system. So pay attention to what sector they mention in the dialog. You can also call up the mission objectives window (behind the “Hail Starfleet” button) and that will actually mention the sector and block.

Shiiips iiiin Spaaaaaaace!

One final tip about space travel: Auto-navigation using the map is not perfect. Often you have to manually fly towards an object in space to get close enough to actually be offered to beam down onto the planet. E.g. near Earth, you can immediately beam to the academy, but have to fly close to the space station to be offered to beam over to the Dock. Also, sometimes auto-navigation will leave you right below a star system in space, and you’ll have to fly up to be offered to enter the system. Also, sometimes when the ship turns during auto-navigation, it will cross the edge of the sector, and will offer to warp into that sector instead of finishing its turn and flying to where you actually told it to go. So check what sector it wants to warp to, and if it’s the wrong one just close the window asking you to warp to continue on the mapped course.

Skills and Ranks

As you execute missions, you will earn skill points. At certain amounts of skill points, you automatically advance to the next level. The rank and level for your character are displayed in the upper left. You can click that box to see what ranks you can still achieve, and what benefits go along with it:

The Rewards Window

One of the benefits, for example, is that you occasionally get a new (additional!) ship. So don’t spend money on ships right away. Wait until you hit final rank and have all the free ships, then decide if you want another ship.

Skill points are also the “currency” you use to buy abilities for your character, your ship and the bridge crew. You can simply use the little arrows to “spend” skill points to make yourself better at a certain ability. There are mouse-over popups that tell you all the details.

The Skills window

Note that different skills cost different skill points for different increments. So if one character’s skills window doesn’t let you increase a particular skill anymore (the arrows are disabled), check another character. Chances are, they can still gain a few more points. That’s especially true for your character vs. your bridge officers, which seem to come from different pools, so look around where you can spend more points once you’ve clicked “Accept” once.

Bridge officers have a narrower skill selection (about one new skill for each rank), but they are another class than you, and can thus use special abilities your player character can’t. E.g. if you’re an engineer, you can build a support drone that fights alongside your tactical bridge officers while they throw grenades at the enemy. Or if your tactical, your science officer will come up to you and heal you, and set up little generators, or your engineering officer will set up a force field dome around you. While bridge officers have a limited number of skills, you can re-train them in exchange for energy credits to get one with your ideal combination of abilities. Again, this is something you will want to do once you have reached rank 50 and tried out a few bridge officers and their abilities. Some work better to balance out your character’s flaws than others.

Managing Inventory

Finally, during the game you’ll pick up lots of items, which will end up in your inventory, From there, you can drag them into the Status section of the same window that shows your skills. Depending on whether you’re on a character page or the ship’s, different items in your inventory will be greyed out, so you don’t put an engine into a bridge officer’s weapons slot.

The Inventory window

If your inventory is full, you have to empty it somehow, or you won’t be able to pick up new items. Apart from spending ZEN on buying more slots, I’ve found 3 options:

  1. You can click the “replicator” button in the lower right of the inventory and then pick items to recycle (you will get “energy points” with which to buy items again from the Replicator, but the selection is limited to standard, non-fancy items, while some of the stuff you pick up during the game is much nicer).
  2. You can go to the bank on the base (the flotilla/New Romulus, the space dock, or Q’o’nos), which is a little computer in which you can dump a limited number of items.
  3. You can go to the “exchange” terminal on one of the bases (and many space stations), and offer them for sale to other players. Not all items can be sold (who would want a common Mark I phaser when they’re already at Level 10 and get Mark X stuff during missions). The prices o the exchange are sometimes higher than what you see printed on the items. I sometimes put up items I don’t really want to sell, but can’t have in the inventory right now. Then I later withdraw them from sale. Of course, someone might still buy it, but at least then I get some energy credits from it.

Comparing inventory

Also, when you get new inventory items, you may want to immediately use them. But what if you get a “Personal Shield Mk II [Pha] [Pla]” and a “Personal Shield Mk II [Dis]”? What’s the difference? Well, one will probably be in your character’s/ship’s corresponding slot. Make sure you can see your character’s status page, then mouse over the new item in your inventory. It will now show you a popup describing this item, plus one for each equivalent item your character/ship has. And now you can compare their stats. I don’t claim I understand their stats fully, but I guess if the Shield Capacity is bigger, the shield is better.

BTW — items are classified into different classes: Common, Uncommon, and Rare. So if they’re all Mk II shields, but one is Rare, it’s often the better one. I’ve even had cases where a Mk IV Rare was better than a Mk V Common one. Also, some items are “bound” to your character, or to your account. That means you can’t sell them on the exchange or e-mail them off in-game to another person (or even can’t e-mail them to another character you created on your account). Some are only “bound on equip”, which means if you just pick them up but don’t actually use give them to one of your characters or ships, you can still sell them. So if you get something you don’t need, it’s sometimes handy to not try out that item right away, so you can maybe later sell it.

Devices and Kits

A lot of stuff you’ll find will be called “Devices”, and will look like food, or hypo-sprays (I.e. health bonuses) etc. You can put this in a character’s device slot on the Status page, and your bridge officers will use them up when they’re being attacked. If your player character has a device, you can drag it to the little tray at the bottom and trigger it. There’s even a bunch of Tribble devices. I guess they relax you and thus make you more resilient to certain kinds of attacks (like, “ice tribble” makes you less susceptible to Breen ice attacks, etc.).

The main difference in your character’s status page and that of the bridge officers is that you have a “kit” slot. At some points in the game, you come across a kit. Most will not match your character’s chosen profession, but those that do will give you bonuses and skills if you drag them to that slot, where they’ll kick the previous kit back into your inventory. There’s also a little bracket or three to the left of the kit slot that can hold one or more “kit modules” with additional abilities, like additional combat skills. Note that when you remove a kit and put it in your inventory, it will take along your kit modules, so if you want to use those in a new kit, take them out first.

Dilithium and Duty Officers

The Duty Officers Window
At some point, you will get a bunch of Duty Officers. Duty Officers are not Bridge Officers, they are more like bonus cards that you can draw. There are duty officers that can make your shields restore faster, duty officers that you can call for help on a ground mission to get an extra rifle against the enemy, and similar stuff.

There’s a whole separate window for duty officers that is basically covered in the tutorials. But there are 2 things you can do with duty officers: You can put them on Active Space/Ground Duty
(which means you will benefit from their abilities), or you can send them off on assignments.

Refining Dilithium

The latter is essentially a gamble where you are not able to use a Duty Officer’s abilities for a specified time (I’ve seen durations from 45 minutes to 72 hours, real time, but you don’t have to be logged in). In exchange, if the random number generator isn’t against you, you get small items, skill points (meaning you can increase your rank this way), additional duty officers (“refugees” or “prisoners”), or other kinds of currency. In particular, you can get Dilithium and Lobi Crystals, both of which you can use to buy stuff at certain in-game stores. You can also get some of these items as occasional drops from missions, but getting them and not really having to do anything sounds kinda preferable.

That said, most missions give you about 5 Dilithium or so, and items in the Dilithium store cost somewhere in the 5-figures range. Also, once you have Dilithium, you have to refine it on the “Assets” tab of the window that has your inventory, and you can at most refine 8000 Dilithium per day. So even if you find more than 8000, it’ll take 3 days to get enough “refined” for one of the smaller items. And you can’t get it all from the few Duty Officers (assignments are limited, as are DOffs), so you’d have to also take on some of the repeatable missions where you mine or earn Dilithium.

Special Events

Star Trek Online often runs special seasonal or promotional events where stuff you would have to pay for is free for a little while. You can then buy those items in the store for 0 ZEN. Some events also include a temporary ceasefire, where e.g. even Klingon characters can fly to Risa in federation space and play some of the missions there. So keep an eye out for news on special events, particularly if you don’t plan to spend money. There is also a live stream on Twitch every week where they give away stuff, but currently you can’t redeem those temporary rebate codes in the Mac version of STO.

Fleets and other Players

Whenever you’re in one of the bigger areas with other players, it can happen that you get a little pop-up window requesting you join a fleet. Fleets are groups of players. I.e. actual humans banding together and playing as a team on-line. There’s an NPC in the game that can give you more info, but you don’t have to join any fleets right away. Wait a little, get to know the game, then investigate what fleets are good for and which one you want to join later.

The Foundry

Vacation in your own engine room
The Foundry is the name of the user-generated missions on STO. Once you’ve completed the tutorial, you can play additional missions there (they have their own tab in the Missions window). I’ve found some quite well-written and fun episodes there, and before you start them you can even see a rating whether they’re ground or space missions (or a bit of both) or have story etc. I quite enjoyed The Mayns of Balnar Moon.

PS – Sometimes, there are balloons in the game. And why don’t you try visiting your own ship’s bridge and walk around the corridors and check out the engine room? Hint: You get there somehow using the mini-map window.

Update: Now that I’m past Level 40, I’ve corrected some of my conclusions. In particular, Romulan turns out to not quite be as cool as it originally sounded, and I added mention of the Exchange and arranging your tray.

Update: Now that I’m at Level 50, and have also created a few additional characters and leveled them up a bit, I’ve added more info on character classes and things outside the game, bridge officer skills, bound items, and accidental warping during auto-travel in space.

Enough with the NSStatusItems! Teach your app its place!

I see more and more applications implemented as NSStatusItems in the upper right side of the menu bar. In this posting, I’ll lay out why this is a worrying development, and why you should rarely implement NSStatusItems.

Screen real estate

The menu bar is very precious screen real estate, and the most expensive part of your computer. It takes up a permanent 22 points at the top of your screen (if you have several screens, it may even show up on every screen). The menu bar is fixed in position and size, different from other windows, and no other window can inhabit these sacred pixels. You can’t switch it behind another window. It is always visible, always immediately clickable.

It is also used for an important part of the user interface of the current application. All of an application’s menus have to fit into this area. There is no scrolling, no wrapping to a second line.

Perspective of importance

One of the fundamental rules of UI design is to arrange UI elements by their importance. Things that provide information the user constantly needs to be aware of, or that are constantly used should always be in view/at a single-click range, while things the user uses less can be relegated to less easily reachable spots that might require several clicks to get to.

The document window (or main window in the case of a shoebox application like iPhoto) is the top of this hierarchy. That’s what the user works with most of the time and where her attention is focused. Floating palettes are also near the top.

Things you can’t put directly in front of the user like that go in a menu, where the user needs to click to discover them or trigger them. If something is even less important or needs to display information more complex than is desirable to put in a menu item, it can go in an auxiliary window shown by a menu item.

Popovers, while relatively new to the scene, are kind of halfway between these two. On one hand you need to click to open them, like a menu, on the other hand you can’t have as many of them as you can have menus. They also occupy a half-way position between a menu and a modal window. They can contain more complex controls.

NSStatusItem

So, now that we know how limited room in the menu bar is, and how it is the second go-to location after you’ve run out of main window space, where does NSStatusItem fit in here?

Well, NSStatusItems can show information in their icon, and otherwise work like a menu. They can immediately react to a click (like the “Notifications” icon in the upper right of the screen) or show a menu, or a popover.

They are also visible across all applications. As such, they are a permanent, most reliable fixture in the user interface. Always visible, always clickable. It is prime real estate if there ever was one.

From this follows that it should only hold functions that inhabit exactly this place for the user: Something that is needed no matter what application is frontmost. Something that is constantly needed, not just occasionally when the user is working on one particular project. Or something that indicates some important piece of information, like how long the computer’s battery will last.

The reality of status items

Compare that to the reality we’re living with today: Every Twitter client I’ve used so far had a status item by default. A status item and a dock icon. At the time of this writing I’ve written well over 57’000 tweets, but even I don’t think that Twitter is that important. One dock icon is fine for seeing new tweets and posting a new one. It’s one click away.

I’m sure some users disagree, but really, is that the majority? Does it have to add that status item and take up dock space by default? Can’t it just leave this as a feature that the user can activate if they think it is needed?

Similarly, there are applications that perform periodic clean-up tasks in the background. Maintenance. Do I really need to see those applications’ icons in my menu bar permanently? Couldn’t they just show their icon when they are doing work, then remove it again? Couldn’t they be a GUI front-end with a background helper application that magically does its work? How often do I manually need to trigger a re-scan of my movies folder to see if it contains new files if the application watches the folder for changes anyway? If this really is just a workaround for rare bugs, why not make me launch the GUI front-end to achieve that and stay out of my menu bar?

There are applications that let me run a server, for testing, locally, on my computer. Why can’t they just be a regular GUI front-end with the server as an invisible background process? Why can’t they just add a bookmark file somewhere that I can launch using Spotlight instead of making me use a different item in the precious status item area of the screen to open the URL for that server?

Why does everyone have such an inflated sense of the importance of their app that they need to have an icon in the menu bar?

Cocoa and the Builder Pattern

There’s been a nice discussion about the Builder pattern on Twitter today. The Builder pattern is a nice tool to have, particularly because it addresses a few common problems.

What Builder Pattern?

In short, the Builder pattern is a pattern where you have one object that you configure that then creates another object based on that configuration. The nice thing here is that you can first build your object step by step, like you’d e.g. do with NSMutableString, but then the actual construction of the object happens in one go. Very handy for immutable objects.

Usually, a setter for a Builder object returns self, like retain or autorelease do. That way, you can create something in Java or C++ that almost looks like Objective C:

Image theImage = (new Image.Builder)->SetWidth(100)->SetHeight(80)->SetDepth(8)->Build();

Where the Build() method releases the builder and returns the actual, immutable Image object.

Extending init methods

When you add a parameter to an initializer in Objective-C, it is annoying. You usually add the parameter to the initializer, then create a compatibility version with the old method’s name that calls the newer version with a default value for the extra parameter.

Java and C++ have solved that problem by allowing you to specify default values for parameters, but they don’t maintain binary stability that way. If you add a parameter, you still have to recompile, but at least you don’t need to change your code.

I guess one fix would be if ObjC supported default arguments to a parameter that would simply result in the creation of a second version of this initializer with the label and parameter removed:

-(id) initWithBanana: (NSBanana*)theBanana curvature: (CGFloat)curvature = 5
{
    // magic happens here
}

Would be the same as writing:

-(id) initWithBanana: (NSBanana*)theBanana curvature: (CGFloat)curvature
{
    // magic happens here
}


-(id) initWithBanana: (NSBanana*)theBanana
{
    return [self initWithBanana: theBanana curvature: 5];
}

Of course, you’d still need at least one parameter, because ObjC has no way of knowing what part of the message is the name, and what is the label for the second (for init there could be special code, I guess, but what for a -exfoliateCow:withSpeed: method?). And defaulting to -initWithBanana if the first parameter has a default is obviously not always desirable either. It would solve the annoyance of telescoping constructors, at the least.

The Builder pattern doesn’t have this problem. Each parameter has a setter that you use to set it. A new builder could have defaults for all parameters when it is created. Then you change the ones you want to customize, and call -build on it to get the new object. If a new setter is added, that’s fine. You don’t call it, you get the default. The maintainers only add the one setter, no compatibility method needed.

Thread safety and immutable objects

The easiest way to get thread safety is to prohibit data from changing. If data is immutable, there is nothing to be synchronized between threads,and no need for one thread to wait for the other. However, immutable objects are also annoying, as they need to be fully specified in their init method.

A case where this is a problem in Cocoa is NSImage. NSImage is an immutable object by convention, but not actually. It is an object that has its own builder built in. You are expected to know that, for an NSImage to be thread safe, you are expected to create it, set its attributes, draw something in it, and then stop messing with it, treating it as an immutable, read-only object from then on.

The problem is, nobody enforces it. NSImage is a perfectly mutable object, with setters and getters. There is no exception thrown when you violate this verbal contract. Of course Apple could have added a “makeImmutable” method to NSImage that causes those exceptions to happen when you try to edit an instance. But then they’d have to add code to each setter that errors (Or at the least use some aspect-oriented-programming mechanism to inject code before every setter that performs this check automatically).

The Builder pattern would solve that: They can have a huge, private constructor on NSImage that changes with every release to add new parameters and initialize that immutable object, while the Builder would present a stable and convenient API to all clients. There would not be any setters on NSImage.

But it is ugly…

Admittedly, it feels a bit inelegant to build an object that builds an object. The way NSImage works is so much nicer. But Mike Lee actually offers a neat approach that works almost as well:

Just pass in a list of properties. This could be a dictionary of properties, or even just a variadic argument list like -dictionaryWithObjectsAndKeys: takes it. You’d define a constant for each possible property (that way if you mis-type the parameter name the compiler tells you, which you don’t get from a raw string). Internally, this constant could even hold the actual name of the property, even if it is never exposed as a method in the public header. So, all your constructor would do is call [self setValue: properties[key] forKey: key] in a loop, once for every element.

You get the same effect as labeled parameters (if you put the keys first, even more so). You also get the same effect as optional parameters. The binary ABI never changes, so that’s good, too. The only downside is you need to pass every parameter as an object, and you lose compile-time type checks. OTOH you gain compile-time errors when you try to change the object after creating it (because it declares no setters).

Is it worth all that work?

Admittedly, I haven’t had to add parameters to the init method of a public class that often. Nonetheless, I think Mike’s approach and the Builder pattern both are useful things to keep in mind if you ever come up with a class that can be created in numerous configurations (and is likely to gain new properties in the future) but should then be immutable. Class clusters and plug-in classes seem like a typical place where you might need this.

Are your rectangles blurry, pale and have rounded corners?

One common problem with drawing code in Cocoa (iOS and Mac OS X) is that people have trouble getting crisp, sharp lines. Often this problem ends up as a question like “How do I get a 1-pixel line from NSBezierPath” or “Why are my UIBezierPath lines fuzzy and transparent” or “Why are there little black dots at the corners of my NSRect”.

The problem here is that coordinates in Quartz are not pixels. They are actually “virtual” coordinates that form a grid. At 1x resolution (i.e. non-Retina), these coordinates, using a unit commonly referred to as “points” to distinguish them from act pixels on a screen (or on a printer!), lie at the intersections between pixels. This is fine when filling a rectangle, because every pixel that lies inside the coordinates gets filled:

filled_rectangle_between_pixels

But lines are technically (mathematically!) invisible. To draw them, Quartz has to actually draw a rectangle with the given line width. This rectangle is centered over the coordinates:

coordinates_between_pixels

So when you ask Quartz to stroke a rectangle with integral coordinates, it has the problem that it can only draw whole pixels. But here you see that we have half pixels. So what it does is it averages the color. For a 50% black (the line color) and 50% white (the background) line, it simply draws each pixel in 50% grey. For the corner pixels, which are 1/4th black and 3/4ths black, you get lighter/darker shades accordingly:

line_drawing_between_pixels

This is where your washed-out drawings, half-transparent and too-wide lines come from. The fix is now obvious: Don’t draw between pixels, and you achieve that by moving your points by half a pixel, so your coordinate is centered over the desired pixel:

coordinates_on_pixels

Now of course just offsetting may not be what you wanted. Because if you compare the filled variant to the stroked one, the stroke is one pixel larger towards the lower right. If you’re e.g. clipping to the rectangle, this will cut off the lower right:

coordinates_on_pixels_cut_off

Since people usually expect the rectangle to stroke inside the specified rectangle, what you usually do is that you offset by 0.5 towards the center, so the lower right effectively moves up one pixel. Alternately, many drawing apps offset by 0.5 away from the center, to avoid overlap between the border and the fill (which can look odd when you’re drawing with transparency).

Note that this only holds true for 1x screens. 2x Retina screens exhibit this problem differently, because each of the pixels below is actually drawn by 4 Retina pixels, which means they can actually draw the half-pixels needed for a 1 point wide line:

coordinates_between_pixels_retina

However, you still have this problem if you want to draw a line that is even thinner (e.g. 0.5 points or 1 device pixel). Also, since Apple may in the future introduce other Retina screens where e.g. every pixel could be made up of 9 Retina pixels (3x), you should really not rely on fixed numbers. Instead, there are now API calls to convert rectangles to “backing aligned”, which do this for you, no matter whether you’re running 1x, 2x, or a fictitious 3x. Otherwise, you may be moving things off pixels that would have displayed just fine:

coordinates_on_and_between_pixels_future_retina

And that’s pretty much all there is to sharp drawing with Quartz.

The fast road to unit tests with Xcode

Supposedly Xcode has unit test support. I’ve never seen that work for more than two Xcode revisions. So I’ve come up with a minimal unit test scheme that works reliably.

1) Add a “command line tool” target (Foundation application, C++ application, whatever makes sense). Put your test code in its main.m or whatever. After each test, print out a line starting with “error: ” if the test failed. If you want to be able to see the successes as well, start them with “note: “. Keep a counter of failed tests (e.g. in a global). Use the number as the app’s return value of your main().

2) Add a “Run Shell Script” build phase to this target, at the very end. Set it to run ${TARGET_BUILD_DIR}/${PRODUCT_NAME}. Yes, that’s right, we make it build the unit test app, then immediately run it. Xcode will see the “error: ” and “note: ” lines and format them correctly, including making the build fail.

3) Optionally, if you want these tests to run with every build, make that command line tool target a dependency of your main app, so it runs before every build. Otherwise, just make sure your build tester regularly builds this test target.

4) Add a preprocessor switch to the tests that lets you change all “error:” lines into “warning:” instead. Otherwise, when a test fails, you won’t be able to run it in the debugger to see what’s actually going wrong.

How to write a compiler

A bytecode interpreter feeding instructions through it.Since there isn’t that much beginner info out there about this topic, here’s a very rough run down of what I know about the basics of writing your own compiler, in particular about how the CPU works and how to generate code for it.

CPU/bytecode interpreter

A bytecode interpreter works just like a CPU, the difference being that it is in software, while the CPU is actual hardware. So all a fake or real CPU does is take a list of instructions and fetch them one by one.

To properly do that, there is one variable (in a real CPU, this is a register) that contains the position of the current instruction. This is called the program counter or PC for short, and is basically just the memory address of whatever command it is to execute.

Once an instruction finishes, the CPU adds to the PC to make the pointer point at the next instruction (or in the case of a conditional or loop, it rewinds the PC back to the start of the loop, or jumps over the ‘else’ section, or whatever.

So it’s fairly easy to create a bytecode interpreter. It’s just a loop:

#define NO_OP        0
#define PRINT        1
#define END          2
struct Instruction { int instructionType; int param1; int param2; };
Instruction *currentInstruction = LoadCodeFromDisk();

while( currentInstruction )
{
    if( instructionType == NO_OP )
        currentInstruction++;
    else if( instructionType == PRINT )
    {
        DoPrint( currentInstruction->param1, currentInstruction->param2 );
        currentInstruction++;
    }
    else if( instructionType == END )
        currentInstruction = NULL;
    else
        exit(1); // UNKNOWN INSTRUCTION! BLOW UP!
}

So all that generating machine code or byte code is, is really adding items to an array of structs. Of course, if you want to generate Intel machine code it’s a little more complicated, because instructions can be different size, so you can’t use a classic array, but you can write the raw data to a file or memory block just the same.

Generating code that jumps

If you’ve ever programmed BASIC, you’ve probably seen the following program:

Text with arrows indicating the progression from Print to Goto back to Print1 PRINT "Hello World"
2 GOTO 1

This is an endless loop. Line 1 prints some text to the screen, and line 2 jumps back to line 1. Once line 1 is done, we continue to line 2 again, which jumps back to line 1, forever and ever until someone turns off the computer. So all GOTO does is change the currentInstruction from our above example, the program counter.

currentInstruction = 1;

You can implement GOTO the same way in your bytecode interpreter. However, since you usually don’t know what address your code will be loaded at (and it definitely won’t be address 1), you will generally write your code so it jumps relative to the current instruction’s location. So our version of GOTO, the JUMPBY instruction, would be

currentInstruction += currentInstruction->param1;

For our pseudo-machine-code:

PRINT "Hello World"
JUMPBY -1

With this instruction under your belt, you can quickly implement conditional statements like if. An if-instruction is simply an instruction that looks at a location in memory (whose address could be provided as param2) and if that location is 1 (true), jumps by param1. Otherwise it does the usual currentInstruction++.

The conditional GOTO is the basic building block of all flow control. If/else:

Flow from 1,2,5,6 for true case,  2,3,4,6 for false case.1 FOO=1
2 GOTO 5 IF FOO
3 PRINT "Foo is false."
4 GOTO 6
5 PRINT "Foo is true."
6 END

loops:

1 FOO=0
2 GOTO 6 IF FOO
3 PRINT "Repeating."
4 DO_SOMETHING_THAT_COULD_CHANGE_FOO
5 GOTO 2
6 PRINT "End of loop"
7 END
While loop execution order: 1,2,3,4,5,2 and then if FOO is 1, from there to 6 and 7, otherwise on to 3 again etc.

Note that bytecode has no operators, no expressions, no precedence. You provide operations in the order it is supposed to execute them. If you want to compare two strings, you do so in the instruction at the top of the loop, save its result to FOO, then loop over FOO:

1 FOO=COMPARE("a","b")
2 GOTO 6 IF FOO
3 PRINT "Repeating."
4 DO_SOMETHING_THAT_COULD_CHANGE_FOO
5 GOTO 1
6 PRINT "End of loop"
7 END

(Note how line 5 jumps to line *1* here, i.e. every time through the loop, the condition is evaluated, then the conditional GOTO tests it)

Retroactive code generation

Now how do you generate code for this? How do I know, before I have read and generated the individual instructions, what line the GOTO in line 2 will have to jump to?

Well, you don’t. Instead, what you do is write out the GOTO as

2 GOTO 0 IF FOO

and then later, when you reach the end of the loop in line 5, where you write out the GOTO that jumps back to the condition, you simply change the destination of line 2 after the fact. This is usually fairly easy if you write a function for parsing every syntax element. Take the following C-like program:

strcpy( txt, "a" );
while( compare(txt,"b") )
{
    print("repeating");
    do_something_that_could_change_txt();
}
print( "End of loop" );

You’d have a function CompileOneLine() that reads one line and looks at the first word. If it is “if” it calls CompileIfLine(), if it is “while” it calls CompileWhileLine(), “print” – CompilePrintLine() etc.

CompileWhileLine would look something like:

void CompileWhileLine()
{
    int conditionOffset = ReadAndCompileExpression( "FOO" );
    int conditionalGotoOffset = WriteInstruction( "GOTO IF", 0, "FOO" );
    if( NextChar() == '{' )
    {
        SkipChar('{');
        while( NextChar() != '}' )
            CompileOneLine();
    }
    else
        CompileOneLine();
    int gotoOffset = WriteInstruction( "GOTO", conditionOffset );
    SetDestinationOfGoto( conditionalGotoOffset, gotoOffset );
}

And since we call CompileOneLine() again to read the lines inside this while statement, we can nest while statements.

Variables

As demonstrated, this byte-code has one big downside: How do we do variables? We can’t put the variables in with the code, because that would mean that when a function calls itself, it would use the same variables as its previous iteration. So we need some sort of stack to keep track of the most recent function’s variables.

And this is what the stack in programming languages like C is: The code for a function has a prolog and an epilog. That is, a few instructions at the start, before any actual commands that the function contains, where it makes the stack larger to reserve space for the variables we need, and a few more after the end to get rid of them again. In our BASIC-like pseudocode, this could look like:

PUSH 0 // Reserve space for 3 int variables:
PUSH 0
PUSH 0
// ... actual code goes here
POP // Get rid of no longer needed 3 int variables
POP
POP

Now since we sometimes need a variable just for a short while (e.g. FOO for holding the loop condition’s result to hand off to the conditional GOTO instruction), it would be kind of awkward to find our variables by counting from the back of the stack. So for that we have a base pointer. A base pointer is another variable/register, like our program counter before. Before we push our variables on the stack, we write the size of the stack into the base pointer.

SavedBasePointerPUSH basePointer // Save the old basePointer (for whoever called us)
SET_BASEPOINTER // Write current stack size to basePointer
PUSH 0
PUSH 0
PUSH 0
// ... actual code goes here
POP
POP
POP
POP_BASEPOINTER // Restore the saved base pointer into the basePointer

Now, to use a variable, we can simply access it relative to the basePointer, i.e. basePointer[0]=1. No matter how many variables we add, these numbers stay the same for the lifetime of our function.

ParametersOnStackAnd once we have this, we can also implement parameters. Parameters are simply variables at a negative offset. Since whoever calls us pushes parameters on the stack right before calling us, they all can be found right before our saved basePointer. So basePointer[-2] is parameter 1, basePointer[-3] parameter 2 etc. This means the parameters need to be pushed in reverse order, but that’s all there is to it.

Returning

Given the above, it comes as no surprise that you can’t just return from your function. You need to make sure that, before you return, your clean-up code runs. So what we usually do is, we make a note of the position at which the clean-up code starts, put a RETURN statement right at its end, and then whenever the code wants to return, we just write the return value somewhere on the stack, GOTO the clean-up code and let it return.

Of course, you’ll have to remember all spots that GOTO that code, because when you write them, the clean-up code won’t have been written yet, and fill it out in retrospect. But if you got this far, that’s all old hat to you.

Strings and other (bigger) data

Illustration of a few instructions followed by a block of data with arrows from the instructions to their particular stringsAs you may have noticed, our instructions only have two ints as parameters. What if you need to e.g. provide a format string to printf? Well, you’ll need an instruction that loads a string constant. Pushes its address on the stack, which the print command can then grab and display.

Commonly, what one does is simply write the strings in the same file (or memory block) as the bytecode, e.g. right after the actual instructions, and then load the whole thing into RAM. Since you know how big your block of code is after you’ve written it, you can retroactively fill out the offset from the instruction to the string it is supposed to push on the stack, and at runtime, the instruction can use currentInstruction +n to get a pointer to it and push that on the stack.

And that’s pretty much how you create a bytecode interpreter and generate bytecode (and in a simplified form, this is how you generate machine code).

Cocoa: String comparisons and the optimizer

Woman in front of a mirrorA while ago, a friend came to me with this bit of code:

NSString *a = @"X";
NSString *b = @"X";
if( a == b )
{
    NSLog(@"Same!");
}

“How come it works with the == operator? Didn’t you have to call isEqualToString: in the old days?”

Before we answer his question, let’s go into what he implicitly already knew:

Why wouldn’t == work on objects?

By default, C compares two pointers by simply comparing the addresses. That is logical, fast, and useful. However, it is also a little annoying with strings, arrays and other collections, because you may have two collections that still contain identical objects.

If you have the phone books from 2013 and 2014, do you just want to compare the numbers 2013 and 2014 and be told: “No that’s not the same phone book”, or are you actually interested in whether their contents are different? If nobody’s phone book entry changed in a particular city, wouldn’t you want to know that and save yourself the trip to the phone company to pick up a new phone book?

Since all Objective-C objects are pointers, the only way to do more than compare the addresses needs some special syntax. So NSString offers the isEqualToString: method, which, if the pointers do not match, goes on to check their contents. It compares each character to the same position in the second string to find out whether even though they’re not the same slip of paper, they at least have the same writing on it.

So why does the code above think they’re the same?

After all that, why does the code above think they are the same object after all? Doesn’t a point to the @"X" in the first line, b to the @"X" in the second line?

That is what is conceptually true, what a naïve compiler would do. However, most compilers these days are smart. Compilers know that a string constant can never change. And they see that the contents of both string objects pointed to by a and b are the same. So they just create one constant object to save memory, and make both point to the same object.

There is no difference for your program’s functionality. You get an immutable string containing “X”.

However, note that there is no guarantee that this will happen. Some compilers perform this optimization for identical strings in one file, but not across files. Others are smarter, and give you the same object even across source files in the same project. On some platforms, the string class keeps track of all strings it has created so far, and if you ask for one it already did, gives you that, to save RAM. In most, if you load a dynamic library (like a framework) it gets its own copy of each string, because the compiler can not know whether the surrounding application actually already has that string (it might be loaded into any arbitrary app.

Mutability is important

This is a neat trick compilers use that works only with immutable objects, like NSString or NSDictionary. It does not work with NSMutableString. Why? Because if it put the same mutable string into a and b, and you call appendString: on a, b would change as well. And of course we wouldn’t want to change our program’s behaviour that way.

For the same reason, NSString may be optimized so that copy is implemented like this:

-(id) copy
{
    return [self retain];
}

That’s right. It gives you the same object, just with the reference count bumped, because you can’t change this string once it has been created. From the outside it looks the same. Copy gives you the object with its retain count bumped, so you can release it safely once you’re done with it. It behaves just like a copy. The only hint you may have that this happened is that instead of an NSString with reference count owned solely by you, you get one with a reference count of 2 whose ownership you share with another object. But that’s what shared ownership is about after all.

Of course, this optimization doesn’t work with NSMutableString.

What I take away from this

So if someone walks up to you and shows you code that uses the == operator where it should really be checking for content equality, and argues that “it works, so it is correct”, now you’ll know why it just happens to work:

It’s a fluke, and if Apple decides to switch compilers or finds a better way to optimize performance or memory usage that requires them to no longer perform this optimization, they might just remove it, and this code will break, because it relied on a side effect. And we don’t want our code to break.