By Casey Liss
Mirror Mirror in the Code

For the last year and a half, I’ve been working full time as a Swift developer. I love Swift, and I’ve also been really enjoying diving into Functional Reactive Programming using RxSwift. Nevertheless, I find myself longing for something that I don’t have anymore: a robust introspection API.

When I was writing C#, I could write a simple class like this:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Now let’s say I want to send or receive a Person from a RESTful API. Perhaps the transmission will be JSON, and it will look something like this:

{
    "fn": "Casey",
    "ln": "Liss"
}

If we wanted to map a C# Person from a JSON dictionary, it’s reasonably straightforward, except that there’s an important discrepancy: we need to tie fn to FirstName and ln to LastName.

There’s a ton of ways one can create a link between those different names. My favorite, in C#, was to use introspection. In C#, this is called Reflection, and that’s how I still refer to it to this day.

Reflection is neat because it allows my code to learn about itself. That means I can add some metadata to my code—I can annotate it—in order to provide some supplementary information. How does that work in practice? Let’s augment the Person class, adding and leveraging a new Attribute.

public class JsonKeyAttribute: Attribute
{
    public string Key { get; set; }

    public JsonKeyAttribute(string key)
    {
        this.Key = key;
    }
}

public class Person
{
    [JsonKey("fn")]
    public string FirstName { get; set; }

    [JsonKey("ln")]
    public string LastName { get; set; }
}

Now we are annotating our properties with new metadata: we’re storing the keys needed to translate to/from JSON right there inline. How do we leverage it? Let’s write a static factory method:

public class Person
{
    [JsonKey("fn")]
    public string FirstName { get; set; }

    [JsonKey("ln")]
    public string LastName { get; set; }

    public static Person FromJson(string jsonString)
    {
        var retVal = new Person();
        var properties = typeof(Person).GetProperties();
        foreach (var property in properties)
        {
            var attribs = property.GetCustomAttributes(typeof(JsonKeyAttribute), true);
            var attrib = attribs.FirstOrDefault() as JsonKeyAttribute;
            if (attrib != null) 
            {
                var key = attrib.Key;
                var value = // Get value from JSON object 
                            // using the key we just discovered.
                // Set the property's value
                property.SetValue(retVal, value);
            }
        }

        return retVal;
    }
}

Admittedly I’ve fluffed over the conversion from JSON string to something meaningful, as well as glossing over extracting "Casey" and "Liss" from the JSON. However, the rest of the code is the point. We can leverage Reflection to look at the Person class and see what the key is for each of its properties.

Having the ability to annotate our code with information about itself is super powerful. Using an Attribute, we were able to leave information about how to convert between different representations of the same data right in the class that needs to know about it. Some purists say that’s a poor separation of concerns; to me, that’s improving local reasoning.


Furthermore, using annotations can accomplish interesting things in arguably far cleaner ways.

As an example, if you want to specify a “pretty printer” for the purposes of debugging a Swift class, you can use CustomDebugStringConvertible. However, to do so, you must implement the protocol. For example:

struct Person {
    var firstName: String
    var lastName: String
}

extension Person: CustomDebugStringConvertible {
    var debugDescription: String {
        return "\(firstName) \(lastName)"
    }
}

The approximate equivalent in C# is arguably cleaner, because it doesn’t require implementing a new interface. Instead, you simply leverage the DebuggerDisplayAttribute:

[DebuggerDisplay("{FirstName,nq} {LastName,nq}")]
public class Person
{
    [JsonKey("fn")]
    public string FirstName { get; set; }

    [JsonKey("ln")]
    public string LastName { get; set; }
}

I can think of a ton of other places where reflection is useful as well. I’m particularly interested in how cool it could be to really open up the already crazy-powerful Swift enums by adding the ability to annotate them, or reflect over them. Oh, the crazy things I could do… 🤔


Reflection isn’t for everyone. In fact, I got the following email from an ATP listener:

If you need reflection to reason about and execute code runtime, your API is poorly designed. Can you please explain why you feel the the need for a reflection API?

That’s a pretty severe take-down.

I understand the sentiment, and this particular listener isn’t necessarily wrong. But what I love about reflection is that it opens up the possibility for a whole new way of solving problems. A way that I’ve found to be quite convenient from time to time.

In fact, all of you Objective-C developers out there may enjoy doing things like this on occasion:

id person = [[NSClassFromString("Person") alloc] init];

To me, that’s reflection.

A while back there was a big kerfuffle amongst some Objective-C developers who were, erm, objecting to the lack of Begin scare quote dynamic End scare quote features in Swift. To me, the canonical, level-headed post about this was this wonderful post by my pal Brent Simmons. It’s an extremely short but accurate summary of what all of the Objective-C folks seemed to think Swift was lacking.

To me, I can summarize his post in one word: reflection.