What's new in Swift 3 and 3.1

What's new in Swift 3 and 3.1

I continue my series of post describing the evolution of the Swift language, this time with the improvements in Swift 3 and 3.1.

API Changes

Consistent First Argument Labels

The first parameter in functions and methods has always an external name.

Omit Needless Words

Type and protocol names are shorter and so simplified.

Capitalization on Enumeration Cases

Enum case are now capitalized camel-case (i.e. the first letter is lowercase).

Methods that Return or Modify

A method that finishes with -ed or -ing is a name so returns a new object;
otherwise it is a verb and it applies a modification on the current object.

Function Types

Now it's possible to pass function types are parameters, for example:

func g(a: (Int) -> Int) -> (Int) -> Int  { ... }

API Additions

Accessing the Containing Type

Now it's possible to use Self to refer to the current type, while self still points to the current instance.

Inline Sequences

It's possible to create now infinite sequences with sequence(first:next:) and sequence(state:next:).
For example:

for view in sequence(first: someView, next: { $0.superview }) {
    // someView, someView.superview, someView.superview.superview, ...
}

You can also limit the collection with another closure:

for x in sequence(first: 0.1, next: { $0 * 2 }).prefix(while: { $0 < 4 }) {
	print (x)
}
// >> 0.1
// >> 0.2
// >> 0.4
// >> 0.8
// >> 1.6
// >> 3.2

#keyPath()

#keyPath() can be used to check at compile time for spelling errors in type and member names; it's also very useful in case of refactorings.
For example the following code will raise a compile-time error:

class Foo
{
    @objc let aRenamedProp: String = "A Value"
}
let anObject = NSObject()
anObject.addObserver(anObject, forKeyPath: #keyPath(Foo.aProp), options: [], context: nil)
// Compile time error is produced since #keyPath() contains the old property name

Note that in later versions of Swift there is a more compact version:

print(myInstance[keyPath: \Foo.aRenamedProp])

Failable Numeric Conversion Initializers

A failable initializer can fail and return nil. So this makes not necessary to create a factory to create instances of our type.

class Student {
	let name: String
	let grade: Int
	
	init?(_ name: String, _ grade: Int) {
		guard !name.contains(" "),
			grade > 0  // <-- 3.1 feature here
			else {
				return nil
		}
		
		self.name = name
		self.grade = grade
	}
}

let student1 = Student("Curia Damiano", 3)     // nil
let student2 = Student("Damiano", 0)           // nil
let student3 = Student("Damiano", 5)           // Student

Now the numeric types (Int, Int8, Int16, Int32, Int64, UInt, UInt8, UInt16, UInt32, UInt64, Float, Float80, Double) have failable initializers.

let grade = Int(exactly: gradeDouble)

In the example above, grade will not be nil only if gradeDouble is a double storing an integer value (like 16.0).

New Sequence Functions

There is now the possibility to define lazy sequences with the prefix function, for example:

let fibonacci = sequence(state: (0, 1)) {
  (state: inout (Int, Int)) -> Int? in
  defer {state = (state.1, state.0 + state.1)}
  return state.0
}

// Swift 3.0
for number in fibonacci.prefix(10) {
  print(number)  // 0 1 1 2 3 5 8 13 21 34
}

Swift 3.1 introduces the possibility to define the min and max value of the sequence with prefix and drop:

// Swift 3.1
let interval = fibonacci.prefix(while: {$0 < 1000}).drop(while: {$0 < 100})
for element in interval {
  print(element) // 144 233 377 610 987
}

Or, with a more compact syntax:

let interval = fibonacci.prefix{$0 < 1000}.drop{$0 < 100}

Concrete Constrained Extensions

Swift 3.1 allows to extend a Protocol with a constrain based on a concrete class. Before, the constrain could be only another Protocol.

For example, previously to extend the Optional<String> class it was needed to define a custom protocol:

// Swift 3.0
extension String {
  var isBlank: Bool {
    return trimmingCharacters(in: CharacterSet.whitespaces).isEmpty
  }
}

protocol StringProvider {
  var string: String {get}
}

extension String: StringProvider {
  var string: String {
    return self
  }
}

extension Optional where Wrapped: StringProvider {
  var isBlank: Bool {
	return self?.string.isBlank ?? true
  }
}

let foo: String? = nil
let bar: String? = "  "
let baz: String? = "x"

foo.isBlank // true
bar.isBlank // true
baz.isBlank // false

Now it's possible to do it directly, without the need of defying with custom protocol:

// Swift 3.1
extension Optional where Wrapped == String {
  var isBlank: Bool {
    return self?.isBlank ?? true
  }
}

Nested Generics

In Swift 3.1 it's possible to mix nested types of an outer class with generics, without even the need of declaring them.

For example:

class Team<T> {
  enum TeamType {
    case swift
    case iOS
    case macOS
  }
  
  class BlogPost<T> {
    enum BlogPostType {
      case tutorial
      case article
    }
    
    let title: T
    let type: BlogPostType
    let category: TeamType
    let publishDate: Date
    
    init(title: T, type: BlogPostType, category: TeamType, publishDate: Date) {
      self.title = title
      self.type = type
      self.category = category
      self.publishDate = publishDate
    }
  }
  
  let type: TeamType
  let author: T
  let teamLead: T
  let blogPost: BlogPost<T>
  
  init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost<T>) {
    self.type = type
    self.author = author
    self.teamLead = teamLead
    self.blogPost = blogPost
  }
}

can be simplified:

class Team<T> {
  // original code 
  
  class BlogPost {
    // original code
  }  
  
  // original code 
  let blogPost: BlogPost
  
  init(type: TeamType, author: T, teamLead: T, blogPost: BlogPost) {
    // original code   
  }
}

Availability by Swift version

Before it was already possible to define some statements only for some Swift versions:

// Swift 3.0
#if swift(>=3.1)
  func intVersion(number: Double) -> Int? {
    return Int(exactly: number)
  }
#elseif swift(>=3.0)
  func intVersion(number: Double) -> Int {
    return Int(number)
  }
#endif

But this required to compile the code for each possible Swift version.

Now it's possible to use the @available attribute, so that the code doesn't need to be compiled for all Swift versions:

// Swift 3.1
@available(swift 3.1)
func intVersion(number: Double) -> Int? {
  return Int(exactly: number)
}

@available(swift, introduced: 3.0, obsoleted: 3.1)
func intVersion(number: Double) -> Int {
  return Int(number)
}

Convert Non-Escaping Closures to Escaping Ones

Closure arguments to functions were made non-escaping by default in Swift 3.0.
In Swift 3.1, you can convert non-escaping closures to escaping ones temporarily by using the new withoutActuallyEscaping() helper function.