If you’ve been following along with my recent posts regarding enums and Objective C, you’ll notice a theme: Objective C is quite capable of expressing what we want, it’s just extremely verbose, especially compared to the improved syntax that Swift brings to the table.
There are many significant drawbacks to Swift, especially when you need to interop with ObjC code. In this world, we need something better. We need to be able to transparently bridge between the world of modern syntax and conveniences without being shackled to the days of C programming, while at the same time, being able to maintain 100% interop with all of our existing ObjC code.
We could continue to suffer through the ObjC syntax, or, we can do something about it.
Framing the Solution One solution to solving the problems I exposed in the series with enums is to use a bunch of MACROs. That works, but it doesn’t get us nearly where we want to be: a modern, sleek syntax that is both easy to write, and more importantly, easy to read and reason about.
This is where we want to be:
enum CompassPoint: North | South | East | West
That’s it. That’s all it should take to define one of the “traditional” enums.
enum Barcode:
| UPCA(numberSystem :: int, manufacturer :: int, product :: int, checkInt :: int)
| QRCode(code :: NSString)
And above is what the “associative value” enum looks like. I’d like to call out something here, we actually have more information encoded in the enum then Swift here – we capture the name of the components. This adds much more clarity to what the values actually are.
And finally, the raw values:
enum ASCIIControlCharacter :: NSString:
| Tab := "\t"
| LineFeed := "\n"
| CarriageReturn := "\r"
You might be wondering at how we are going to accomplish this. Well, it’s actually pretty straight forward. Here are the items we’ll be building:
- A parser for our enum syntax
- A tool to convert our parse tree to ObjC code
That’s it. We don’t actually need anything else. I’ll show how we can leverage Xcode’s built-in extensibility points to give us nice error reporting and seamless integration of our new enum definition.
I will be calling this new language: Proteus.
Building the Parser There are basically two ways to generate the parser: handwrite one or use some tools to generate one from a grammar. I’m going to handwrite our parser, primarily because our enum grammar is quite simple and it’s really easy to provide very friendly error messages with a handwritten parser.
Note: I’ll only be showing building the most simple of parsers accepting only the basic version of the enum. The full github link will be posted at the end. Overtime I’ll continue to add support more features.
The work is going to be broken up into the following components:
Scanner
– this is going to break up the input file into a set of tokens.
Analyzer
– this is going to take the tokens from the Scanner
and apply meaning to them, returning an array of Constructs
.
Construct
– a representation of the different type of language constructs, such as enum
or func
.
Rewriter
– a function that can take a Construct
and turn it into the appropriate Objective C header and implementation files.
I will be writing the components in Swift – I like the irony of building a better Objective C in a language that I think didn’t live up to that promise. =)
The full source for the project can be found here: https://github.com/owensd/proteus.
If you take a look at the code for the scanner (in lexer.swift
), the output for the CompassPoint
declaration are the following tokens:
- Token(Keyword) “enum”
- Token(Identifier) “CompassPoint”
- Token(Colon) “:”
- Token(Identifier) “North”
- Token(Pipe) “|”
- Token(Identifier) “South”
- Token(Pipe) “|”
- Token(Identifier) “East”
- Token(Pipe) “|”
- Token(Identifier) “West”
This input is passed into the Analyzer
which outputs an Enum
construct.
Enum:
typeName = "enum"
identifier = "CompassPoint"
options = [
"North",
"South",
"East",
"West"
]
Then there is the rewriteEnumToObjC
rewriter function. The full code for that is below:
private func rewriteEnumToObjC(value: Enum) -> (header: String, implementation: String)
{
var header = "@interface \(value.identifier) : NSObject\n\n"
var implementation = "#include \"\(value.identifier).h\"\n\n"
implementation += "#define RETURN_ENUM_INSTANCE() \\\n"
implementation += " static \(value.identifier) *instance = nil;\\\n"
implementation += " static dispatch_once_t onceToken;\\\n"
implementation += " dispatch_once(&onceToken, ^{\\\n"
implementation += " instance = [[\(value.identifier) alloc] init];\\\n"
implementation += " });\\\n"
implementation += " return instance;\n\n"
implementation += "@implementation \(value.identifier)\n\n"
for option in value.options {
header += "+ (\(value.identifier) *)\(option.name);\n"
implementation += "+ (\(value.identifier) *)\(option.name) { RETURN_ENUM_INSTANCE(); }\n"
}
header += "\n+ (NSArray *)values;\n"
implementation += "\n+ (NSArray *)values\n"
implementation += "{\n"
implementation += " static NSArray *values = nil;\n"
implementation += " static dispatch_once_t onceToken;\n"
implementation += " dispatch_once(&onceToken, ^{\n"
implementation += " values = @[ "
for (idx, option) in enumerate(value.options) {
implementation += "\(value.identifier).\(option.name)"
if (idx != value.options.count - 1) {
implementation += ", "
}
}
implementation += " ];\n"
implementation += " });\n\n"
implementation += " return values;\n"
implementation += "}\n"
header += "\n@end\n"
implementation += "\n@end\n"
return (header, implementation)
}
swift
The basic concept is to literally just write the header and implementation files as you would normally.
With each of those components in place, it’s time to hook it up!
Integration with Xcode If you download the project I linked, there will be a command-line tool called protc
. It takes two parameters:
-file
– the path to the .prot
file that contains our enum
definition
-output
– the path that the .h
and .m
files will be written to
So here’s the magic… Xcode has these things called “Build Rules”. It’s basically how anything gets compiled within Xcode. Well, we can create our own build rules for our .prot
files.
Step 1: Build Rules To do that:
- Select your project in the project navigator
- Select the target for your app/tool
- Select the “Build Rules” tab in the project editor
- Add a new build rule
The script will be filled in with this content:
rm "${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.h" 2> /dev/null
rm "${DERIVED_FILE_DIR}/${INPUT_FILE_BASE}.m" 2> /dev/null
/Users/owensd/Library/Developer/Xcode/DerivedData/protc-ecehehjngfljckcirxwdltnqqayl/Build/Products/Debug/protc -file ${INPUT_FILE_PATH} -output ${DERIVED_FILE_DIR}
Then be sure to set the “Output Files” to:
$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).h
$(DERIVED_FILE_DIR)/$(INPUT_FILE_BASE).m
Here’s a screenshot of what it looks like:

Custom build rules allow us great flexibility.
: .caption
Step 2: Create your .prot file Next, create your .prot
file just as you would any file. The trick is to add it to your “Compile Sources”.
- Select your project in the project navigator
- Select the target for your app/tool
- Select the “Build Phases” tab in the project editor
- Add your
.prot
file to the list of “Compile Sources”

Don’t forget this step or nothing will seem to be working!
: .caption
Step 3: Use your new enum! That’s really it. Now when you build your project, the .prot
will be processed and in turn the generated .m
file will be compiled into your project’s target.
To use it, simply add the header file as normal:
#import <Foundation/Foundation.h>
#import "CompassPoint.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
for (CompassPoint *point in CompassPoint.values) {
if (point == CompassPoint.North) {
NSLog(@"direction is north");
}
else if (point == CompassPoint.South) {
NSLog(@"direction is south");
}
else if (point == CompassPoint.East) {
NSLog(@"direction is east");
}
else if (point == CompassPoint.West) {
NSLog(@"direction is west");
}
}
}
return 0;
}
objc
If you set your “Output Files” to be ${DERIVED_FILE_DIR}
, the header paths have no trouble finding the generated header.
Step 4: Handling Build Errors Of course, sometimes you might make a mistake in your .prot
file. It would suck if there was no way to handle this or to be notified of this… but of course that’s not the case!
Change your .prot
file to this:
enum CompassPoint North | South | East | West
Notice the missing :
between CompassPoint
and North
. Re-build your project, and voila!

Errors are reported and clickable!
: .caption
Not only can the error be reported, but it will cause your project to report a build failure. Those errors are also linked back to your source, so double-clicking will open your .prot
file and show the error there.
Pretty cool.
The only missing thing is code completion and colorization. Unfortunately, to the best of my knowledge, those two features require full-blown Xcode plug-ins – way out of scope for this blog entry.
Next Steps Over the years, Objective C has attempted to get facelifts. Way back the 1997 timeframe, there was a project to create a “modern syntax” for ObjC. It didn’t go well. Then there was the ObjC-Java bridge that came in 2001. That also didn’t go well.
However, in 2006 we got ObjC 2.0. That was pretty good step forward for the Objective C language. And of course, in 2014, we got Swift.
I think the biggest disservice we can do to the Cocoa developer community is remove the underpinnings of the ObjC runtime. It is the language’s, and I truly believe, the platforms’ greatest strength.
I believe if we hide the complexities of C from our source code and focus on letting the power of the ObjC runtime shine through in our code, we can create a new language that provides of the great flexibility of the ObjC runtime while still accomplishing many of the goals that Swift is attempting to solve – namely safer code by default.
So I guess this is the start of the project I’m calling Proteus. We’ll see how far it gets.