Swift 4.2 improvements? Member/dot syntax for subscripts. Trying it out in a protocol-oriented, generic linked list.

The code shown herein will only compile and link in Xcode 10 beta and run on iOS 12 beta and/or OS X 10.14 beta.

While working on a Swift protocol-oriented and generic linked list, I got to thinking about Apple’s “improvements” to version 4.2 of their flagship language. Since a linked list is a list, I thought, “Why not add a subscript to my linked list to facilitate finding specific nodes in my list?” I did that in Swift 4.1 and got what most developers would’ve expected, e.g., used linkedList["node4"] to get the node in the list associated with the keyword “node4.” With Swift 4.2, I can use the controversial new @dynamicMemberLookup language attribute and implement dot/member notation, like linkedList.node4 to get that same node in the list associated with “node4.” Big improvement, huh? Well, maybe. We’ll talk about how this new and improved subscript is more than just about syntactic sugar, but that the “driving motivation for this feature is to improve interoperability with inherently dynamic languages like Python, Javascript, Ruby and others.” Note that all code shown in this tutorial was written in two Xcode 10 beta playgrounds.


Since you may be interested, first let me point you to what I’ve already discussed in regards to Swift 4.2’s new features, then we’ll get back to subscripts.

We’re in the middle of Apple’s annual product upgrade cycle and this article is the third in a series of tutorials meant to shed light on highly-focused and singular aspects of Swift 4.2. Instead of trying to cover all of the 4.2 features/improvements in one very long article, I’m talking about each aspect of the new 4.2 version. So far, I’ve covered these topics:

The old subscript notation

Let’s first look at the Swift 4.1 version of a subscript in my protocol-oriented and generic linked list. In this section, we’ll just concentrate on the custom subscript method I added to an extension for my LinkedListProtocol protocol. (If you want to examine the entire linked list, click here to go to the last section in this post). The tag member property in each Node instance in my LinkedList is of type String and is a convenience property enabling me to easily identify and find nodes in my doubly linked list. Here’s the bracketed subscript method — and note that I’ve highlighted lines 12 and 19 to draw your attention to my subscript declaration and definition, respectively:

In order for you to see how this subscript is working with my linked list, let’s look at some code in my Xcode 10 beta playground. I initialize an instance of my generic linked list for type UIView, create/initialize nodes, each with unique UIView instance and meaningful name, configure one of the UIView instances for display, add the nodes to my linked list, print all the nodes in my list to console, show an example of subscript usage, and then display the payload of one of the list’s nodes (a UIView), with tag “View 4,” on screen — and note that I’ve highlighted line 33 to draw your attention to use of a custom subscript:

Here’s what happens when I inspect the node retrieved using my custom subscript (linkedList["View 4"]) in my Xcode 10 beta playground:

I love how well Xcode allows me to inspect the run-time contents of one of my Node<AnyType> (at this point, Node<UIView>) instances. I can even see, expand, and inspect the node’s next and previous pointers, er, ah, references.

Here’s the output to console from the linkedList.showAll() call you saw above:

Here’s the view (with tag “View 4”) that I configured for drawing and rendered to screen:

The new subscript notation

The Swift evolution proposal, SE-0195, for a new subscript protocol, was adopted and implemented in Swift 4.2. The proposal states:

This proposal introduces a new @dynamicMemberLookup attribute. Types that use it provide “dot” syntax for arbitrary names which are resolved at runtime — in a completely type safe way. This provides syntactic sugar…

If I want to use the new dotted subscript in my code — e.g., write linkedList.View4 instead of writing linkedList["View 4"] as I did above — I just needed to take a few steps. I applied the new @dynamicMemberLookup attribute to my generic linked list’s
LinkedListProtocol. Then I applied the dynamicMember modifier to my protocol definition’s subscript method argument. I also applied the dynamicMember modifier to my protocol extension’s subscript method argument.

#ad

Now let’s look at the Swift 4.2 version of a subscript in my protocol-oriented and generic linked list. In this section, we’ll just concentrate on the custom subscript method I added to an extension for my LinkedListProtocol protocol. (If you want to examine the entire linked list, click here to go to the last section in this post). The tag member property in each Node instance in my LinkedList is of type String and is a convenience property enabling me to easily identify and find nodes in my doubly linked list. Here’s some code including the new subscript method — and note that I’ve highlighted lines 2 , 13, and 20 to draw your attention to the new Swift @dynamicMemberLookup attribute and the dynamicMember modifier in my subscript method’s argument:

In order for you to see how the new Swift 4.2 subscript protocol is working with my linked list, let’s look at some code in my Xcode 10 beta playground. I initialize an instance of my generic linked list for type UIView, create/initialize nodes, each with a unique UIView instance and meaningful name, configure one of the UIView instances for display, add the nodes to my linked list, print all the nodes in my list to console, make use of my custom subscript, experiment with the new subscript protocol, and then display one of the list’s nodes, with tag “View 4,” on screen — and note that I’ve highlighted lines 33 and 38 – 43 to draw your attention to use of a custom subscript:

Let’s inspect the node returned by using the new dotted subscript notation:

Here’s the output to console from the linkedList.showAll() call you saw above:

Here’s the view (with tag “View 4” and subscript .View4) that I configured for drawing and rendered to screen:

So what’s really new?

While the new dotted subscript syntax does provide a bit of syntactic sugar, the “driving motivation for this feature is to improve interoperability with inherently dynamic languages like Python, Javascript, Ruby and others.” Let’s concentrate on syntactic sugar in this section and leave talk about “interoperability with inherently dynamic languages” to the next section.


Unless you’re planning on interoperating with “inherently dynamic languages,” I would advise you to make use of subscripts sparingly and judiciously. In the case of my generic linked list, I determined that having the ability to find a node with a subscript to be helpful. Since my subscript method returns an optional, that reminds me to check it for nil before assuming that a Node matching the subscript (tag in this case) was found. I can get away with statements like this one at runtime:

The previous code snippet prints the following to console:

With Swift 4.2 and using my generic linked list as an experimental use case, we can see that an “old-fashioned” subscript like linkedList["View 4"] can now be written as linkedList.View4. Some may bring up the point that “View 4” is stringly-typed and thus prone to spelling errors. Remember too that the Swift evolution proposal, SE-0195 claims that the “dot ‘syntax'” for subscripts is “completely type safe” (their emphasis added). But is it really (type) safe?

In my @dynamicMemberLookup-attributed LinkedListProtocol extension, the subscript method is type safe in the sense that I can specify the input parameter(s) and their type(s) and I can specify the return type. A developer using my subscript method can glean the input parameters, their types, and the return type from reading the method’s signature — and documentation helps (click here for my Swift how-to on professional code commentary):

So technically it’s “safe…” well, almost. These Swift subscripts, whether bracketed (linkedList["View 4"]) or dotted (linkedList.View4), are not checked at compile time. They are “arbitrary names which are resolved at runtime.”

Let me edit the code shown above like so:

This compiles fine, but since there’s no Node with a tag of “View 6,” my code crashes at runtime because I’m trying to render a UIView which is nil. It crashes on lines 6,11 in the following code snippet:

Here’s what the crash looks like in the playground:

So remember that if you use bracketed (linkedList["View 4"]) or dotted (linkedList.View4), the compiler can’t prevent you from typos (spelling errors). Your typos will cause your app to crash at runtime. Auto-complete doesn’t provide direct assistance with dotted subscripts (but don’t give up on it yet…):

Auto-complete does know where to pick up after you fill in your subscript, and note that I added context sensitive help for my Node<AnyType> property named payload:

As you can see, the dotted subscript does perform as advertised and produce the node I wanted based on the subscript I typed:

Interoperating with dynamic languages

In the “Introduction” to the now-implemented Swift evolution proposal, SE-0195, for a new dotted subscript protocol, “syntactic sugar” is mentioned in the third sentence. My main job in this tutorial has been in showing you how an “old-fashioned” subscript like linkedList["View 4"] can now be written as linkedList.View4. Keep in my that you don’t have to use the new @dynamicMemberLookup attribute and you can still write and use bracketed subscript notation. And remember that:

You can define multiple subscripts for a single type, and the appropriate subscript overload to use is selected based on the type of index value you pass to the subscript. Subscripts are not limited to a single dimension, and you can define subscripts with multiple input parameters to suit your custom type’s needs.

For many of you just interested in using Swift for writing iOS and/or macOS apps, you can probably just read the next sentence, make a mental bookmark of its contents, and keep an eye out for the latest news on Swift (just in case something big happens). The main purpose for the new dotted subscript protocol is for Swift to stay relevant and see its developer base grow. In order to do so, Swift is going to have to keep up with all the other in-demand dynamic/scripting languages.

If you read on a bit farther into the proposal’s “Introduction” section, you find the real story:

The driving motivation for this feature is to improve interoperability with inherently dynamic languages like Python, Javascript, Ruby and others. That said, this feature is designed such that it can be applied to other inherently dynamic domains in a modular way. …

If you move on to the next section, “Motivation and Context,” you find that the first sentence states:

Swift is well known for being exceptional at interworking with existing C and Objective-C APIs, but its support for calling APIs written in scripting languages like Python, Perl, and Ruby is quite lacking.

#ad

There are pages of explanations, sample code, alternative approaches — even a section on “Reducing Potential Abuse” — that go on and on about dynamic languages. It’s beyond the scope of this tutorial to discuss all the details behind this proposal, but this information is there if you want it.

My protocol-oriented, generic linked list code

This is an experimental first draft of a protocol-oriented generic linked list. It’s working great so far, but there are some things I’d like to polish up. You’ll soon be seeing a tutorial on how I designed and built a protocol-oriented generic linked list, the hurdles I had to overcome, what I learned in the process, etc.

Enjoy!

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by https://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.