This blog entry was inspired by Objc.io’s snippet titled “Enums instead of Booleans”. I really loved the clarity that using enumerations brought to even the simplest of examples that was presented in that snippet. If you haven’t seen it, check it out before continuing on!

Objc.io’s snippet focused primarily on the definition and consumption of the enumeration values. What I’d like to focus on here is the implementation of the thing that produces those values for the switch-case that will consume them later on.

Example scenario

To put an example before us, consider the following scenario:

Suppose that we’re building an app that utilizes a subscription-style service to deliver premium content.

Special things, such as providing access to the premium content, need to happen in the app if the user is a Subscriber in good standing.

Other things need to happen, such as denial of access to the premium content, if the user had a subscription, but it’s expired.

Finally, if the user has never had a subscription, we’d still like to deny access to the content, but perhaps offer them the opportunity to subscribe.

Using Objc.io’s idea as a springboard, we could program this in a couple of ways:

1 – We could define a few boolean properties throughout that would indicate the user’s subscription status:

isSubscriber

isSubscriptionExpired

isNonSubscriber

What I find interesting about this approach is that it’s not clear, from looking at the properties, that they’re all mutually exclusive. Can I be a subscriber whose subscription has expired? If my subscription expired, am I a non-subscriber?

It could be that I’ve chosen poor names for the properties, but if I wanted to make clear that the statuses are mutually exclusive, there’s a better way to encapsulate them. Objc.io helpfully pointed us in the direction of that better encapsulation method. Yep… you got it: enumerations!

2 – As the title of the blog entry signals, we could replace the booleans with an enumeration:

1 public enum SubscriberStatus { 2 case CurrentSubscriber 3 case ExpiredSubscriber 4 case NonSubscriber 5 }

Immediately, this clarifies the mutually exclusive part. Enumerations, by definition, expose mutually exclusive values. By defining the SubscriberStatus enumeration, I’ve made clear that my intent is to have someone be either a CurrentSubscriber , an ExpiredSubscriber , or a NonSubscriber , but not combinations of each.

Not only that, but rather than including complicated branching logic when I need to determine someone’s subscription status, I can simply switch-case over the enumeration possibilities and perform the appropriate behavior.

1 func checkSubscriberStatusForRegistrant ( registrant : Registrant ) { 2 // We're coming to the definition of Registrant... 3 // In fact, Registrant's implementation is the goal of this blog entry! 4 5 switch ( registrant . subscriberStatus ) { 6 case . CurrentSubscriber : 7 showPremiumContent () 8 case . ExpiredSubscriber : 9 alertExpiredSubscription () 10 case . NonSubscriber : 11 offerSubscription () 12 } 13 14 }

Producing the enumeration values

The one thing that left me scratching my head on at first was the part of the whole scheme that would produce the enumeration values. In my example above, I’ve left out what the implementation of Registrant looks like.

When I’m consuming the enumeration values, I’m riding on the fact that registrant.subscriberStatus has some way of producing a correct SubscriberStatus for the registrant. But what does that look like? Well… here’s one possibility:

1 public struct Registrant { 2 public var subscriberStatus : SubscriberStatus { 3 get { 4 if ( noSubscriptionOnFile ()) { 5 return . NonSubscriber 6 } 7 8 if ( subscriptionOverdueForPayment ()) { 9 return . ExpiredSubscriber 10 } 11 12 return . CurrentSubscriber 13 } 14 } 15 16 private func noSubscriptionOnFile () -> Bool { 17 // Do what needs to be done to check if the registrant has a subscription on file or not 18 } 19 20 private func subscriptionOverdueForPayment () -> Bool { 21 // Do what needs to be done to check if the registrant's subscription is overdue for payment 22 } 23 }

So as you can see, the thing that produces the enumeration values does have some if s and Bool s in it. I couldn’t really think of another way to do this. To simplify the readability of the subscriberStatus property’s implementation, I’ve abstracted the more complicated computational logic for figuring out whether or not a subscription is on file or if the registrant is overdue for payment into functions.