Swift: When Is a Protocol Not a Protocol?

Riddle me this, Batman: when is a Swift protocol not a protocol?

Answer: when it’s an Error.

I think the main thing about Swift types bugs me the most is that it’s type system seems to be a raft of special cases when there are perfectly good alternatives. Swift exceptions are a perfect example of this.

Let’s start with a quote from the Swift documentation from Apple:

In Swift, errors are represented by values of types that conform to the Error protocol. This empty protocol indicates that a type can be used for error handling.

Spoiler: this is an outright lie. Let’s prove it.
To start, let’s start with how swift represents protocols (in particular, this is the protocol list type)

---value---
---value---
---value---
-Metadata--
-PWitness0-
(PWitness1)

It’s a block with 3 machine pointers set aside for the value represented by the Protocol (if the value does not fit in 3 machine pointers, there will be a pointer to allocated memory for the value), then there’s a pointer to the class Metadata for the value, and finally there is a list of pointers to protocol witness tables for each protocol that is represented. If Swift uses a protocol for the Error type, we should be able to test this side by side with another empty protocol and see what the compiler does with this.

public protocol EmptyProtocol {
}
public enum MyError : Error, EmptyProtocol {
                case itsAnError
                case itsAHorribleError
                case itsTheTotalCollapseOfCivilization
}
 
public func doNothing(_ a: Error) { }
 
public func alsoDoNothing(_ a: EmptyProtocol) { }
 
let x = MyError.itsAHorribleError
alsoDoNothing(x)
doNothing(x)

I compiled this and dumped out the resulting assembly and this is what I got:

_main:
; these 3 instructions set up the stack frame
0000000100000e40 push       rbp
0000000100000e41 mov        rbp, rsp
0000000100000e44 sub        rsp, 0x40
; rax is a pointer to stack memory for a protocol
0000000100000e48 lea        rax, qword [rbp+var_28]
; this is the protocol witness table - it goes into rcx
0000000100000e4c lea        rcx, qword [__TWPO5None17MyErrorS_13EmptyProtocolS_]
0000000100000e53 lea        rdx, qword [__TMfO5None17MyError]
; after this instruction rdx will point to the class metadata MyError
0000000100000e5a add        rdx, 0x8
; this is the value of itsAHorribleError, storing into x
0000000100000e5e mov        byte [__Tv5None11xOS_7MyError], 0x1
0000000100000e65 mov        qword [rbp+var_10], rdx
0000000100000e69 mov        qword [rbp+var_8], rcx
; this stores x into the stack memory
0000000100000e6d mov        r8b, byte [__Tv5None11xOS_7MyError]
0000000100000e74 mov        byte [rbp+var_28], r8b
0000000100000e78 mov        dword [rbp+var_2C], edi
0000000100000e7b mov        rdi, rax
; rax points to stack memory which contains this:
0x0000000000000001 -> value word 0 (itsAHorribleError)
0x0000000000000000 -> value word 1
0x0000000000000000 -> value word 2
0x00000001000043f8 -> Metadata for MyError
0x0000000100003710 -> Protocol witness table for MyError.EmptyError
; which is a protocol list type with 1 protocol

0000000100000e7e mov        qword [rbp+var_38], rsi
0000000100000e82 call       __TF5None113alsoDoNothingFPS_13EmptyProtocol_T_ ; None1.alsoDoNothing (None1.EmptyProtocol) -> ()
; now here's the set up for calling doNothing
0000000100000e87 lea        rax, qword [__TMfO5None17MyError]
; after this rax will have the Metadata for MyError in rax
0000000100000e8e add        rax, 0x8
; rsi will have the protocol witness table for MyError.Error
0000000100000e92 lea        rsi, qword [__TWPO5None17MyErrors5ErrorS_]
0000000100000e99 xor        r9d, r9d
0000000100000e9c mov        edx, r9d
0000000100000e9f xor        ecx, ecx
0000000100000ea1 mov        rdi, rax
; now this is different...
0000000100000ea4 call       imp___stubs__swift_allocError
0000000100000ea9 mov        r8b, byte [__Tv5None11xOS_7MyError]
0000000100000eb0 mov        byte [rdx], r8b
0000000100000eb3 mov        rdi, rax
// rax/rdi point to heap memory which contains:
0x001d800100655179
0x0000000000000000
0x0000000000000000
0x0000000000000000
0x0000000000000000
0x00000001000043f8 -> Metadata for MyError
0x00000001000042a8 -> Protocol witness table for MyError.Error
0x0000000000000000
0x0000000000000000
0x0000000000000001 -> value of itsAHorribleError
0000000100000eb6         call       __TF5None19doNothingFPs5Error_T_            ; None1.doNothing (Swift.Error) -> ()

So here’s the dirty little secret about Swift.Error: it acts like a protocol, but in use it is not a protocol whatsoever. It’s a heap-allocated container that has information about the encapsulated type. In digging around, Apple appears to be claiming that this representation is so that an Objective C NSError and a Swift Error can co-exist in the same type. So if I call Objective C code which reports an NSError, the Swift code can treat it like a throw (and vice-versa).
I consider this to be a mistake on Apple’s part on a number of fronts. To explain why, we need to understand Swift exceptions a little better.
If I have a function in Swift that throws an exception, in theory there is a transformation available of the function to match Swift’s functional approach.

public func someFunc() throws -> SomeType { }
public enum ExceptionHolder<T> {
    case normalReturn(T)
    case exception(Error)
}
public func someFunc() -> ExceptionHolder<SomeType> { }

In this example, the second incarnation of someFunc is equivalent to the first incarnation except that instead of throwing, we’ve transformed it into a discriminated union of the either a return value or a thrown exception. For Swift, this makes complete sense because exceptions are not exceptions in the sense of typical OOP languages like C++/Java/C#. This is because Swift is a reference counted language and returning from a function abnormally wreaks absolute havoc on your reference counting. The solution to this is that an exception thrown is actually a normal return and that allows Swift to clean up references counts. The transformation above is more or less what Swift 2 used to do (at least I think so – I looked at it very briefly and put it aside and haven’t looked back). This is no longer the case. In Swift 3, Apple has deviated from the standard ABI yet again and has also broken from the functional approach of one argument, one return (see this previous blog). When a function can throw, it will return 2 values. One in standard registers (rax etc), and an exception in r12. If there is no exception, r12 is 0 and the standard registers have the return. If r12 is non-zero, it contains a pointer to a heap-allocated error object.
So why is Swift doing the wrong thing, in my oh-so-humble opinion? Well, first the calling conventions break the ABI. Second, Apple has decided to use one format for Swift.Error forcing all Swift code to suffer just to get interoperability with Objective C. Finally, it’s inefficient: transformations should instead happen at the point of interface, not for everyone. The reason being that in Swift error handling code, the typical pattern matching code ends up calling a library routine, swift_dynamicCast (bet you didn’t know that swift even had dynamic casting like this) for every single case and the way that swift_dynamicCast it written, this particular type gets forced through several cases that are guaranteed to fail and ends up eventually running through a recursive call. So much wasted time.
Now, the Swift ABI is not finalized yet and this may yet change, but jeez.
This doesn’t even touch on the problem that Swift exceptions are (still) fundamentally broken from a language point of view, but that’s a topic for another day.
So we see that Swift exceptions at first look appear to be a protocol that acts similarly to exceptions in other languages, but in implementation are a misfeature that breaks the language model and the ABI and hurts efficiency.

Swift Argument Passing, Part Deux: Tuples

In the last post I did about Swift argument passing, I neglected a couple types. One in particular is the tuple. If you’re not familiar with tuples, you should be. They’re nice a nice bit a sugar in a programming language – kind of like swearing in a spoken language: good once in a while but if you overdo it, the people around you will probably wonder about your upbringing. Tuples are are syntactic sugar for an anonymous struct (or class) with public properties. As a type, many languages represent them as (T0, T1, … Tn) where each Ti is a type. As a variable declaration they are either represented as the whole type as a single aggregate or as a set deconstructed into names. For example, in F#:

let (x, y) = (1, "frobozz")

(x, y) is a decomposition of a tuple of type (int, string). You can see that this is equivalent to this C#:

struct Anon {
   public int x;
   public string y;
}
Anon xy = new Anon() { x = 1, y = "frobozz" };

In Swift, tuples are represented exactly like structs in memory. The trick is to figure out how to pack them. I know this was supposed to be about argument passing, but trust me, we’ll get there.
Suppose we want to write some code to figure out the offset in memory of each item in a tuple. You could do this like this (this is C#, by the way – I’m working C# because Swift’s reflection capabilities can’t do this yet). In this example, assume that we have code elsewhere that given a Type can return its memory alignment and its size.

public struct TupleMap {
    public Type[] Types;
    public int[] Offsets;
    public int Size;
    public int Stride;
    public int Alignment;
    public int Stride;
}
 
public static int RoundUpToAlignment(int value, int align)
{
    return (value + align - 1) / align * align;
}
 
public static TupleMap FromTypes(Type[] types) {
    TupleMap map = new TupleMap();
    map.Typles = types;
    map.Offsets = new int[types.Length];
    int size = 0, overallAlignment = 1;
 
    for (int i=0; i < map.Types.Length; i++) {
        Type t = types[i];
        int fieldAlignment = Alignmentof(t);
        size = RoundUpToAlignment(size, fieldAlignment);
        map.Offsets[i] = size;
        size += Sizeof(t);
        overallAlignment = Math.Max(fieldAlignment, overallAlignment);
    }
    Map.Size = size;
    map.Alignment = overallAlignment;
    map.Stride = RoundUpToAlignment(size, map.Alignment);
    return map;
}

This is a fantastic gem – given the types of the elements in a Swift tuple, we can locate any particular item in memory. In fact, this code works on Swift structs as well because like I said earlier, Swift tuples really are syntactic sugar onto structs. Almost. The divergence has everything to do with Swift’s argument passing and while I don’t agree with the choice of the language designers, I have respect for it.
In Swift, every function takes precisely 1 argument and returns precisely 1 value. This is one of the places in Swift where you can look at it and say “yup – this is a functional programming language” (other places, not so much – oh and the thing about returning precisely one value? That’s a lie, but it’s a lie of convenience). “But wait,” you cry, “didn’t you do a whole article about how arguments are passed and you’re now telling me there’s only one?” I did. It was not alt facts. It was an Obi Wan Kenobi truth.
See, Swift has two totally different ways of representing tuples. The first is in memory, as I mentioned before. The second is as passed to a function. On x64, Swift more or less follows the standard ABI of putting arguments into registers and eventually overflowing into the stack. When I call this function:

public func performFabulousTrick(spot: Dog, location: City, doJump: Bool, repeat: Int) -> () { /* ... */ }

spot will get passed in rdi, location in rsi, doJump in rcx, and repeat in rdx (assuming that Dog and City are classes). So essentially, when a tuple is passed to a function, each element goes in a register (unless it’s a value type that can fit in up to 3 registers, then it will consume that number of registers), until it runs out of registers then it will overflow into the stack. The problem here is what happens when you have arguments that themselves are tuples. The register packing rules don’t change.
So let’s say that I foolishly chose to represent an affine transform as a tuple of 6 floats and I want to get the (tx, ty) elements. I could write it like this:

public func getTxTy(mat:(_: Float, _: Float, _: Float, _: Float, tx: Float, ty: Float)) -> (Float, Float) {
    return (mat.tx, mat.ty)
}

But au contraire mon frère this is going to consume 6 registers. So you see that a tuple matches a struct in memory layout but not in argument passing. So this is a case of where do you put your language inconsistency? For argument passing they put the inconsistency in the difference between struct and tuple passing but chose to consistently handle all sub-tuples and to make functions “pure”. Whereas I would argue that subtuples should be treated more like structs: exceed 3 machine pointers and you get passed a copy by reference. It just makes pulling out elements of a 3 pointer-or-less sub-tuple somewhat harder – but no harder than accessing the elements of a struct. Like I said, I don’t agree with the choice, but I respect it – mostly because I like the cleanness of always taking 1 argument and nearly always returning 1 value. Plus Swift has an interesting way of handling functions that return nothing:

public func foo(x: Int, y: Int) { }

This function actually does return something – it’s an empty tuple. In fact you can also write it like this:

public func foo(x: Int, y: Int) -> () { }

So this is a function of (Int, Int) -> (). Nifty trivia, the empty tuple () is also an alias for the type Void, and an object of either type will consume 0 memory. So if I have this function:

public func foo(x: Int, a: (), b: (), c: (), y: Int) { }

x will go into rdi and y will go into rsi and a, b, and c are just empty placeholders. Similarly, if we lay out a tuple in memory the same way, the 3 middle elements will take up no space.

Again, this is an interesting intellectual exercise in analysis of the practical implementation of functions and argument passing to see where the Swift engineers drew the line – for the most part, they opted for purity (except for inout parameters — forget to mention those) with an eye towards practicality. That they drew the practicality line in a different place than where I would have chosen is fine, and since the Swift ABI is not yet finalized, it may yet change.

“Hang on. You tried to slip that lie about returning one value mostly nearly whatever.”
Aren’t you exceptional! No, I didn’t try to slip it by. That’s a topic for another day.

Magic Smoke

My dad is a retired electrical engineer who worked for Bell Labs for quite a few years. At home, he had a nice little set up in our basement with a Weller soldering iron, components, perf board, wire and host of other implements of destruction. Over the years, he built a clock, a calculator, a breadboard to play with a TI digital sound chip and other projects. He even made a carnival game for the cub scouts where you threw foil covered objects at a hole in a painted plywood sandwich board. If the object made it into the hole, it would short a couple exposed wires together and start a tape player sounding the win. And a Heathkit TV. Did I mention that? He built a flipping TV.

As kids, we hacked around with the things that were there, carefully sorted into colored tubs. The coolest things, of course, were the LEDs because, hey lights! There was also a nifty multi-cell battery lifted from the Bell Labs stock room. I tried to find a picture of it, but no luck. It was a heavy brick with the Western Electric logo on the side and a bunch of spring clips on the top. One was a common ground. The others were positive terminals that were rated at various voltages from .5 V up to 22.5 V. I liked taking out LEDs and hooking them up to the battery via clip leads and lighting them up. In particular, there was one kind of red LED with a black housing and red dome that if you hooked it up to 22.5V, would explode and shoot the red dome off into the distance like a rocket, leaving a contrail of acrid smoke behind it. We spent most of dad’s collection that way.

When I got older, I liked messing with example circuits from Radio Shack data books and when Craig Anderton wrote his book Electronics Projects For Musicians, I was all over it. Dad taught me how to use his wiring pen and how to solder properly and I built a distortion box from scratch, which 33 years later, still works quite well (although I looked for it and I’ve misplaced it to my chagrin).

With a couple friends, Mike Sadowski and Rick Veracco, we decided to start a business making these. We leaned how to lay out and etch circuit boards, prepare a BOM, source parts, and we got the father of Caitlin Hadtke (another friend) to design a label for it using some of our own crappy artwork.

And at our insistence, the controls went to 11.

We made and sold a few dozen of them, barely squeaking out a profit, but wow did we learn a lot. For example, we learned that you shouldn’t dump spent etchant down the drain of the basement slop sink, for example. We flushed it with a ton of water, but it turns out there was enough oomph left in the etchant to eat pinholes through the copper drain pipes, ensuring that the slop sink leaked and requiring my dad to pay to get it fixed. He had the patience of a saint.

Today, things are a little different. For one, Radio Shack is all but dead as a local source of electronic kits and components. On the other hand, there are a number other things that make learning how to work with electronics easier and more fun. For example, Little Bits – snap together electronics components. My 10 year old son has had a lot of fun playing with them.

After messing with the built-in ideas, he made a refrigerator alarm – a device that you put in the fridge and when light hits it, it sets off the alarm.

There’s also SparkFun, one of my favorite sources for hack projects.

The point is that while there really aren’t the accessible brick and mortar shops, online retailers have filled that gap very well and hacking around with electronics projects is easier than ever and that’s a very good thing. Even better is having public figures like Adam Savage promoting making and removing geek stigma.

I’m Old, Part XLIV: OCR and Support

At my last job, one of the many jobs I did was create .NET bindings to OCR engines. Optical Character Recognition is a tricky technology that is rife with hacks and tricks to try to get the recognition rate better on crappy quality scanned documents. In that technology space, there’s around 10 or so decent quality engines and I’ve worked with most of them in one way or another.

Before I go on, I want to talk about OCR companies. All of the ones that I worked with are batshiat insane to some degree. I don’t say this lightly. All of them had unusual licensing terms and/or unique run-time licensing. Most of them offered a way to build their tool into a toolkit and also had an end-user application that they sold. One company in particular, wrote a contract that said–and I swear, I’m not making this up–that you couldn’t use their toolkit to build software to recognize text and create documents. See what I mean? We hired an engineer, Justin, who early on was consistently appalled at this. Eventually, he got jaded enough that when one of these issues came up, if I started the sentence, “because all OCR manufacturers are…” he would quickly finish it “…batshiat insane.” while rolling his eyes.

When I was initially hired, as part of the interview I was given a task to design an OCR interface. I put on my architect hat and designed a nice little class hierarchy that created a decent, extensible, engine-neutral interface. When I was hired, my first task was to learn C#, my second was to implement the OCR interfacing for real. I was given an engine to work with that was implemented as a C library. I built a C# set of tools that hid the specifics and sharp edges of the C library and presented instead a friendly interface that was easy to get started with and had room to grow. For example, the initial toolkit had the ability to translate a scanned document into a few basic document types, including PDF. I exposed those tools as if they were separate objects. Eventually, we added our own PDF output tool that was far better than that engine’s and it stitched into the workflow without deep changes to our users. The toolkit was neutral enough that we were able to get 7 different OCR engines to work with the same front-facing interface.

The main problem with working with OCR engines is initializing their code, managing licensing and preparing them to run. Every single engine had unique problems. Every. Single. One. Explaining this to our poor users was an uphill battle that our support engineers dealt with. We wrote sample code, documentation, and tech notes all of which were routinely ignored.

One particular engine had truly inspired licensing and had odd requirements in terms of having certain directories available to it to find dlls and resource files. All of these things had to be done well in front of when you even touched the engine class or it would fail miserably. We documented this and set up examples that said “you must do this or you will see this error.” Many customers got this right.

Then there was this one customer. He called into support angry. Angry because the engine was expensive and it wasn’t working. Our engineer worked with him and explained what he needed to do (i.e. read the technote to him). He ignored the engineer, didn’t have luck and called back in and escalated to an engineer. He was sent to my peer, Lou, who is very patient and told him pretty much the same thing the support engineer told him, which he again ignored. He called back and wanted to escalate to me.

Now, we didn’t have a big office, so I knew exactly what was going on: angry customer who wouldn’t listen. Got it. Been there, done that, bought the t-shirt.

I got onto a remote desktop session with him and got on a speakerphone call. I had him show me his code to see what he was doing. I dictated breakpoints and asked him to show me the contents of particular variables. Great. I was pretty sure what was going on, but to be 100% sure I needed one more thi-he started pulling up a web browser of his code and started to search the web. I said very directly something along the lines of, “do you want me to help you or are you going to surf the web?” He minimized the the web browser and I looked at his code – yup – he had done nothing that any of the other engineers had suggested. I told him to give me control of the keyboard and mouse and I put into his code the magic that the technote suggested, ran it, and saw correct results.

He ended up sending Elaine, one of our support engineers, a bouquet of flowers and called me a prima donna. And to this day, I still believe he is without a clue.

I’m Old, Part XLIII: Steve, Steve, Steve

I started at Adobe in Mountain View, California in 1990, fresh out of college. It was a novel experience on many levels. I grew up in New Jersey in a nice little suburban community in a house that bordered on old woods that were slightly swampy. I had become accustomed to the flora and fauna of New Jersey and Silicon Valley was something completely different. The sky was the wrong color blue; the leaves on the trees were the wrong shade of green; there was relatively little humidity.

At that time, Adobe moved me and my then wife across the country and put us up in temporary corporate housing while I got started at the company and my wife looked for permanent housing. On the first day during orientation, we were told by HR that if you were married and your spouse was a woman, she would be sent a bouquet of roses and if your spouse was a man, he would be sent a bottle of champagne. How nice!

The roses never showed up. Weird.

We got daily copies of the San Jose Mercury News, as a tool for looking for apartments and keeping up with current events. I saw a headline in the paper, “ASTRONAUT STEVE HAWLEY TO JOIN NASA AMES”. I thought it was funny, so I cut it out and put it up in my cube.

Then we started noticing that mail we should have gotten never arrived. We’d ask at the main office at the housing and there was nothing. We knew it was supposed to have arrived. After poking around and asking questions, we finally put two and two together. Our mail (and the roses) had gone to a Steve Hawley. Just not me.

Eventually, we settled on a place in Morgan Hill, which was a brutal commute, but it was about all we could afford that wasn’t in an iffy neighborhood. We set up forwarding for mail from the corporate housing and settled in. After a week, I got an ATM card and PIN addressed to Steven W. Hawley from an unfamiliar bank. I brought them in to work and called up NASA Ames and had the switchboard connect me to his office, where I spoke with his assistant. Here was our conversation:

“Steve Hawley’s office.”

“Hi, I’d like to speak to Steve Hawley please.”

“Who may I say is calling?”

“Steve Hawley”

“No, to whom am I speaking.”

“Really. Steve Hawley. And I would like to speak to your Steve Hawley.”

“May I ask why?”

“Sure, I have your Steve Hawley’s ATM card and PIN and while I wouldn’t mind drawing from an astronaut’s salary, I figure that he would want it back.”

“Really?”

“Yup. It’s says here ‘Steven W. Hawley’. I’m not W.”

“Oh. That’s not him.”

“What?!”

“My Steve Hawley is Steve A. Hawley not W.”

“Huh. OK. Thanks for your time.”

If I got through to him, I would also have given him an earful about Sally Ride because when they got married, I had gotten a fair amount of ribbing about it because of our names.

Ultimately, I sent everything back to the bank, but I had never expected that there would be 3 Steve Hawleys (fortunately each with different middle initials) who all moved to Silicon valley in the span of a month.

Go figure.

I’m Old, Part XLII: Messing With the Landlord

When I was working for Axial/Newfire, we had a decent little offic suite in Saratoga, CA. It was a very California design in that the the building was very much an exterior design. If you wanted to go to the bathroom (or in the words of Cowboy Dave, “I have to go see a man about a dog”), you had to step outside since the entrance to the bathroom was only outdoors.

The building had a couple wings and in the center was a nice koi pond with attractive rocks and plants around it. The landlord was very proud of the grounds and the fish, but there was a problem. Since this was an open area that was not far from wilderness, the koi routinely got poached by something. Likely it was a bird of prey – maybe a red tailed hawk. Could also have been coyotes.

I was talking with the landlord and he was complaining about how much the koi cost. I suggested that he string a lattice of fine wire across the winds of the building, which would certainly sort out the problem if, when he installed it, he didn’t do such a half-assed job. Oh well.

So being gainfully employed, I decided to solve his koi problem and visited the local pet store and bough $20 worth of feeder goldfish. Do you know how many fish that is? At that time, way more than 100. I had a couple of plastic bags of feeders and a jar of food and I let them loose into the pond and fed them periodically. They were initially too small to be a temptation to birds. Over the months, a lot of them died, but the rest grew and I loved that my bargain feeder fish were hidden among his koi indistinguishable to the untrained eye.

Yeah, it was petty, but sometimes I’m petty.

 

I’m Old, Part XLI: Trolling Creative People

My mom had a number of skills. One was that she was a book hound. Over the years she found a vast number of truly interesting books on a wide variety of subjects. She often went to the Strand bookstore in New York and gathered all kinds of interesting books such as Triviata, Mrs. Byrne’s Dictionary, and The Charles Addams Mother Goose.

One book in particular that served me and my high school friends well was a book of Parlor Games (I can’t find a copy online). It was a compendium of very simple and entertaining games that you could play with very few extra accouterments. The games included things like “Pass the Orange”, “Honey I Love You”, “Spoons”, and so on.

When I was at Adobe, I remember being at a birthday party (I think it was Joe Holt’s) that was held at Adobe. We did the whole party thing and when things were kind of quiet, I pulled out a couple of these games to play. After a few rounds of other games, I suggested a game from the book called Decadence. This is an anti-game and it’s somewhat vindictive. It feels like a typical party game except that one person is a victim.

The rules are simple. You pick a person who is “it”. You tell them that everyone else is going to make up a story and they’re going to guess the story by asking us yes/no questions. You send them out of the room. Then you tell everyone else the real rules:

  1. If “it” asks a question that ends in a consonant, the answer is ‘no’
  2. If “it” asks a question that ends in a vowel, the answer is ‘yes’
  3. If “it” asks a question that ends in ‘y’, the answer is maybe

Simple. Then you tell the rest of the people that our responses will need some acting and we shouldn’t answer right away and confer on the questions so it doesn’t look so automatic. Then the group waits a few minutes before calling “it” back in so it feels like the group actually made up a story.

On this particular evening, the victim was Eric Zocher (you might know Eric from such games as Dark Castle) who was a manager at Adobe. He ran through some initial questions and things went screwy.

“Are the characters solid?”

“No.”

“Are they liquid?”

“No.”

“Are they gaseous?”

“No.”

Eric now looks totally puzzled. You could smell the heat coming off his brain as he’s thinking it through.

“Are they made of plasma?”

“Yes!”

Eric looked relieved.

“Would they fit in this room?”

“Nnnno.”

“Would they fit in this building?”

“No.”

“Would they fit…” Eric is struggling here.

“Would they fit in the Cow Palace?”

We look at each other and confer.

“Yes.”

We went on for another 10 minutes or so and as it happens in the game, the answers start to become contradictory. Eric was trying very hard to try to sort out the contradictions and eventually figured out that we had just trolled him big time.

Unfortunately, Decadence (like the Daffy Duck trick) is something that can only be played once with any one group of people, but man was it worth it.