Anonymous classes for Swift

Table of contents

Abstract

All classes, structs and enums in Swift are named and they are concrete in the sense that there are no abstract members, like abstract methods or properties. Especially for classes with very little functionality, it would sometimes be handy to have a lightweight approach to define a single instance of a class or struct. This post introduces a Swift-specific design pattern for creating such lightweight anonymous class and struct instances.

Anonymous class design pattern

Implementing small classes and structs

Let’s assume we would want to implement Java-like iterators in Swift. Swift’s approach to iterators is defined in terms of the GeneratorType protocol:

protocol GeneratorType {
  typealias Element
  mutating func next() -> Element?
}

This protocol defines a function next which returns the elements of a collection of objects incrementally. If no elements are left, next returns nil. All of Swift’s collection classes, like Array<T>, Set<T>, and Dictionary<K, V>, return generators for iterating over their elements. This mechanism is also used for implementing the for loop in Swift.

Java-like iterators are a little more expressive: they also define a hasNext method which returns true if there are more elements left. We could define a corresponding protocol, which is compatible to Swift’s GeneratorType protocol, in the following way:

protocol IteratorType: GeneratorType {
  var hasNext: Bool { get }
}

This protocol defines a hasNext property and inherits function next from GeneratorType.

If we would have to implement iterators for a large number of collection classes, we would have to define a lot of small, very similar classes or structs which implement the IteratorType protocol for a specific collection class.

Here’s an example showing how we can implement an iterator over arrays in Swift:

struct ArrayIterator<T>: IteratorType {
  let array: [T]
  var i = 0
  init(_ array: [T]) {
    self.array = array
  }
  var hasNext: Bool {
    return i < array.count
  }
  mutating func next() -> T? {
    return i < array.count ? array[i] : nil
  }
}

We can now equip the Array<T> struct with a method iterator() which returns an iterator over the array elements:

extension Array {
  func iterator() -> ArrayIterator<Element> {
    return ArrayIterator(self)
  }
}

Minimizing overhead without giving up readability

The previous section showed the boilerplate code that needed to be written to create an iterator implementation and extend a struct to return iterators. We can reduce this implementation overhead with an idea that was briefly described already in the post on abstract classes in Swift: we implement a generic implementation of iterators by delegating the methods to individual closures that are provided via init.

Here’s a minimal implementation of such a generic implementation:

struct Iterator<T>: IteratorType {
  private let _hasNext: () -> Bool
  private let _next: () -> T?
  init(hasNext: () -> Bool, next: () -> T?) {
    self._hasNext = hasNext
    self._next = next
  }
  var hasNext: Bool {
    return _hasNext()
  }
  func next() -> T? {
    return _next()
  }
}

The following code shows how we can now implement an iterator over arrays without defining a specific ArrayIterator:

extension Array {
  func iterator() -> Iterator<Element> {
    var i = 0
    return Iterator(
      hasNext: { i < self.count },
      next: { return i < self.count ? self[i++] : nil }
    )
  }
}

This approach has the following advantages:

  • No Array-specific class or struct needs to be defined.
  • The implementation is completely encapsulated within the iterator()
    method of Array<T>.
  • The definition of the iterator for Array is intuitive; it really looks like
    an anonymous class instantiation in Java. This is due to the fact that we gave the parameter
    labels in the Iterator constructor the same name like the methods/properties
    they implement.

There is one caveat that needs to be considered: even though we used a struct to define Iterator<T>, all instances of Iterator<T> will have reference semantics. This is because the state that this iterator encapsulates is contained in the context of the closures that are passed to the init method. Variable i in line 3 of the listing above is a good example for such implicitly captured state.

Since the struct itself doesn’t directly contain mutable state, we also do not need to tag the next() method with modifier mutating. Nevertheless, next() does mutate indirectly captured state. This is also why I would consider the usage of modifier mutating in Swift highly misleading.

Encoding variants

If there are common patterns for implementing an iterator, for instance by using other existing methods, this can be easily supported in terms of additional init methods. The following code shows how we could generically support iterators that are defined in terms of a standard Swift generator:

struct Iterator<T>: IteratorType {
  private let _hasNext: () -> Bool
  private let _next: () -> T?
  init(hasNext: () -> Bool, next: () -> T?) {
    self._hasNext = hasNext
    self._next = next
  }
  init(_ generate: () -> T?) {
    var lookahead: T? = generate()
    self.init(
      hasNext: { return lookahead != nil },
      next: {
        if lookahead != nil {
          let res = lookahead
          lookahead = generate()
          return res
        }
        return lookahead
      }
    )
  }
  var hasNext: Bool {
    return _hasNext()
  }
  func next() -> T? {
    return _next()
  }
}

This second init method accepts as its parameter a next() function of a regular Swift generator. It implements both hasNext and next() in terms of this function. This gives us now a second way to quickly implement iterators for all collection classes which have a standard Swift generator already. Here’s how we could make use of this in class Array<T>:

extension Array {
  func iterator() -> Iterator<Element> {
    var generator = generate()
    return Iterator { generator.next() }
  }
}

This code compiles and works as expected. Nevertheless, it’s not the shortest possible way. My first attempt to eliminate the unnecessary closure, which gets passed to the init method of Iterator, does not seem to work:

extension Array {
  func iterator() -> Iterator<Element> {
    var generator = generate()
    return Iterator(generator.next)
  }
}

This code results in the following compiler error message: “Partial application of ‘mutating’ method is not allowed”. I’m puzzled that this isn’t allowed given that a programmer can easily wrap the full application of the mutating method into a closure and achieve the exact same thing.

My very first attempt to stuff everything into a single line, does not work for yet another reason:

extension Array {
  func iterator() -> Iterator<Element> {
    return Iterator(generate().next)
  }
}

Here, the compiler complains with the message: “Value of type ‘IndexingGenerator<[Element]>’ has no member ‘next’. This must be a compiler bug, or a misleading compiler error message, because IndexingGenerator<[Element]> clearly does have a member next.

Summary

  • Swift does not have a lightweight approach to define small classes and structs which
    implement a small protocol.
  • As a workaround, it is often sufficient to define a generic implementation of the protocol
    which forwards the methods and properties of the protocol to closures that are provided by
    clients instantiating the generic implementation.
  • By using the method/property names of the protocol as labels in the init
    method of the generic implementation, we can enable an intuitive syntax for instantiating
    the implementation that is very similar to the anonymous class syntax in Java.

Leave a Comment

Your email address will not be published. Required fields are marked *