A blog exploring functional programming and Swift.

SwiftUI and State Management Corrections

Tuesday Jul 30, 2019

This week we completed our 3-part introduction (part 1, part 2, part 3) to SwiftUI and the problems of state management and application architecture. All 3 episodes are completely free for everyone to watch and they aim to show what tools SwiftUI gives us for managing state in a moderately complex application.

Unfortunately, SwiftUI is still very much in beta and it seems that every 2 weeks there are substantial changes. These changes range from APIs being renamed to foundational changes to how SwiftUI behaves. Due to some of these changes our last 3 episodes now contain some misinformation, so we’d like to take an opportunity to correct these!

BindableObject versus ObservableObject

The main mechanism for turning your models into objects that can be bound in views was a protocol named BindableObject. Conforming to this protocol required you to provide a didChange publisher that you would ping just after you made any changes to your model. For example:

import SwiftUI

class AppState: BindableObject {
  let didChange = PassthroughSubject<Void, Never>()

  var count = 0 {
    didSet { self.didChange.send() }
  }

  var favoritePrimes: [Int] = [] {
    didSet { self.didChange.send() }
  }
}

However, as of Xcode 11 beta 5 this protocol has been renamed to ObservableObject (and moved from the SwiftUI framework to the Combine framework), and you are now required to notify a publisher when your model is about to change rather than after it is changed. This means the above code snippet should now look like this:

import Combine

class AppState: ObservableObject {
  let objectWillChange = ObservableObjectPublisher()

  var count = 0 {
    willSet { self.objectWillChange.send() }
  }

  var favoritePrimes: [Int] = [] {
    willSet { self.objectWillChange.send() }
  }
}

This now satisfies the compiler and is the correct way to implement this protocol.

The name of the property wrapper that connects our model to a view was also renamed in beta 5, from ObjectBinding to ObservedObject. To use it you can simply do:

struct ContentView: View {
  @ObservedObject var state: AppState

  var body: some View { ... }
}

ObservableObject boilerplate

There is also a change in Xcode 11 beta 5 that greatly simplifies how one creates observable objects. The amount of boilerplate required to implement the ObservableObject protocol was pretty significant. Just look at what happens to our AppState if we add two more properties:

import Combine

class AppState: ObservableObject {
  let objectWillChange = ObservableObjectPublisher()

  var count = 0 {
    willSet { self.objectWillChange.send() }
  }

  var favoritePrimes: [Int] = [] {
    willSet { self.objectWillChange.send() }
  }

  var activityFeed: [Activity] = [] {
    willSet { self.objectWillChange.send() }
  }

  var loggedInUser: User? = nil {
    willSet { self.objectWillChange.send() }
  }
}

This was one of the problems that we discussed in part 3 of our series, and luckily Xcode 11 beta 5 provides a solution. It is now possible for SwiftUI to automatically synthesize the objectWillChange for you, and by using the @Published property wrapper you can automatically have the publisher pinged when any of your fields change:

import Combine

class AppState: ObservableObject {
  @Published var count = 0
  @Published var favoritePrimes: [Int] = []
  @Published var activityFeed: [Activity] = []
  @Published var loggedInUser: User? = nil
}

Much nicer!

Derived bindings

Another problem we discussed in part 3 of our series is the idea that SwiftUI state didn’t appear to be “composable”. After much testing and playing around with SwiftUI we weren’t able to figure out how to easily derive bindings of sub-state from our main AppState.

For example, say we had an ActivityView screen that only needs access to the activityFeed field of AppState. We would love if there was a way to project out that single field into a binding, and hand it over to the activity view. We approached this by creating a view that had a binding to the activity feed:

struct ActivityView: View {
  @Binding var activityFeed: [Activity]

  var body: some View { ... }
}

Then, to create a Binding<Activity> to pass along to this view we could derive a binding from the AppState observable object:

struct ContentView {
  @ObservedObject var state: AppState

  var body: some View {
    NavigationView {
      List {
        ...
        NavigationLink(destination: ActivityView(activityFeed: self.$state.activityFeed)) {
          Text("Activity feed")
        }
        ...
      }
    }
  }
}

The most important part of this snippet is the following:

ActivityView(activityFeed: self.$state.activityFeed)

This first accesses the state as the underlying Binding<AppState> that comes from the property wrapper, and this is done via self.$state. Then we derive a Binding<[Activity]> from the Binding<AppState> by using dot-syntax, which is possible thanks to the Key Path Member Lookup feature of Swift 5.1

This is how we hoped derived bindings would work in SwiftUI, but unfortunately up until Xcode 11 beta 5 this did not work. There was a bug that prevented the ActivityView from re-rendering when the app state changed. This has now been fixed, and it’s a great way for creating views that operate on only a small subset of data instead of passing around the full AppState to all views!

Identifiable

And lastly, the Identifiable protocol has been moved out of the SwiftUI framework and into the standard library. This means you no longer need to import SwiftUI in order to get access to this protocol. However, in this change there appears to be a bug in which Int no longer conforms to Identifiable. We’re not sure if this was done on purpose, or if it’s a temporary bug, but it means that our code to show an alert from a binding no longer compiles:

struct CounterView: View {
  @State var alertNthPrime: Int?
  ...

  var body: some View {
    ...
      .alert(item: self.$alertNthPrime) { prime in
        ...
      }
  }
}

Since Int is no longer Identifiable, we cannot use a Binding<Int?> value in the alert(item:content:) method. The workaround is easy enough, just wrap the integer in a struct that you can make identifiable:

struct PrimeAlert: Identifiable {
  let prime: Int
  var id: Int { self.prime }
}

struct CounterView: View {
  @State var alertNthPrime: PrimeAlert?
  ...

  var body: some View {
    ...
      .alert(item: self.$alertNthPrime) { prime in
        ...
      }
  }
}

Now this works as it did before. Hopefully the conformance of integers to Identifiable is added back before Xcode 11 ships!

Move fast, correct things

The past few Xcode 11 betas have had some really nice improvements to SwiftUI, and we are really happy to see the changes. Some of the fixes have directly addressed some of the concerns we brought up in this week’s episode, and make SwiftUI much more appropriate for large, complex applications.

However, we still feel there is room for improvement in a number of key areas in application development. Next week we begin developing an architecture to directly address these problems using functional programming as our North Star.

Until next time!


Enterprise Subscriptions

Thursday May 9, 2019


Today we are excited to announce support for enterprise subscriptions on Point-Free. This makes it super easy for a large organization to obtain a subscription to our video series and share it with everyone in the company.

How team subscriptions work

Point-Free has supported team subscriptions from the day we launched. They allow a company to purchase multiple subscriptions at once for a discounted price. This works by specifying how many seats you want, and then you invite your colleagues to join your team. As owner of the subscription you get to add and remove teammates at anytime, and the billing rate will be adjusted accordingly.

This works great for smallish teams, but if your organization has a hundred engineers you probably don’t want to manually manage all of the seats on your team. It would be far better if everyone in your organization could simply get instant access to everything Point-Free has to offer. This is what inspired enterprise subscriptions!

How enterprise subscriptions work

If your organization is big enough where manually managing the seats of a team subscription is too cumbersome, then an enterprise subscription should help. After negotiating a yearly price with us, we will whitelist your company’s domain so that anyone with an email from your organization gets instant, full access to the site. You will get a white label landing page on our site, for example pointfree.co/enterprise/blob.biz, and anyone in your company can get access to Point-Free as long as they are in possession of an email from your company.

This greatly reduces the administrative overhead of managing a team subscription for large companies. We will even automatically remove teammates from your enterprise subscription once they leave your company and their email has been deactivated!

Interested?

If any of this sounds interesting to you then please get in touch with us to get more information. We can negotiate a yearly price with you based on your organization’s size. And if you already have a team subscription with us we can discount your enterprise subscription based on how much time you have left in your team subscription’s billing cycle.


Open Sourcing Enum Properties

Monday Apr 29, 2019


We wanted to make Swift enum data access as ergonomic as struct data access, so today we are open sourcing a code generation tool to do just that: generate-enum-properties.


We are excited to announce the 0.1.0 release of generate-enum-properties, a code generation tool for Swift that makes enum data access as ergonomic as struct data access!

Motivation

In Swift, struct data access is far more ergonomic than enum data access by default.

A struct field can be accessed in less than a single line using expressive dot-syntax:

user.name

An enum’s associated value requires as many as seven lines to bring it into the current scope:

let optionalValue: String?
if case let .success(value) = result {
  optionalValue = value
} else {
  optionalValue = nil
}
optionalValue

That’s a lot of boilerplate getting in the way of what we care about: getting at the value of a success.

This difference is also noticeable when working with higher-order functions like map and compactMap.

An array of struct values can be transformed succinctly in a single expression:

users.map { $0.name }

But an array of enum values requires a version of the following incantation:

results.compactMap { result -> String? in
  guard case let .success(value) = result else { return nil }
  return value
}

The imperative nature of unwrapping an associated value spills over multiple lines, which requires us to give Swift an explicit return type, name our closure argument, and provide two explicit returns.

Solution

We can recover all of the ergonomics of struct data access for enums by defining “enum properties”: computed properties that optionally return a value when the case matches:

extension Result {
  var success: Success? {
    guard case let .success(value) = self else { return nil }
    return value
  }

  var failure: Failure? {
    guard case let .failure(value) = self else { return nil }
    return value
  }
}

This is work we’re used to doing in an ad hoc way throughout our code bases, but by centralizing it in a computed property, we’re now free to access underlying data in a succinct fashion:

// Optionally-chain into a successful result.
result.success?.count

// Collect a bunch of successful values.
results.compactMap { $0.success }

By defining a computed property, we bridge another gap: our enums now have key paths!

\Result<String, Error>.success
// KeyPath<Result<String, Error>, String?>

Despite the benefits, defining these from scratch is a tall ask. Instead, enter generate-enum-properties.

generate-enum-properties

generate-enum-properties is a command line tool that will rewrite Swift source code to add ergonomic enum data access to any enum with associated data.

Given the following source file as input:

enum Validated<Valid, Invalid> {
  case valid(Valid)
  case invalid(Invalid)
}

It will be replaced with the following output:

enum Validated<Valid, Invalid> {
  case valid(Valid)
  case invalid(Invalid)

  var valid: Valid? {
    get {
      guard case let .valid(value) = self else { return nil }
      return value
    }
    set {
      guard case .valid = self, let newValue = newValue else { return }
      self = .valid(newValue)
    }
  }
}

Not only can you ergonomically access enum data, but you can update it as well!

Learn more

We’ve explored why “enum properties” are important on Point-Free, but we hope this library empowers folks to write source code generation tools to solve these kinds of problems more broadly.

To generate enum properties for your Swift source code projects, today, visit the repository and read through its installation and usage!


Older blog posts

Monday Mar 18, 2019

Open Sourcing Gen

Today we are open sourcing Gen: a lightweight wrapper around Swift's randomness API's that makes randomess more composable, transformable and controllable!

Tuesday Jan 8, 2019

Announcing swift-html 0.2.0

Announcing swift-html 0.2.0: support for CocoaPods, Carthage, SnapshotTesting, and more!

Wednesday Dec 19, 2018

2018 Year-in-Review

41 episodes, 19 hours of video, 25 blog posts, 8 open source libraries, 3.8K stars, 36K visitors, and we’re just getting started?

Wednesday Dec 19, 2018

Save 30% on Point-Free

To end 2018 on a high note we're offering a 30% discount to new subscribers for their first year. Just click through to read the full post below! We hope you'll join us for all of the great material we have planned for 2019.

Monday Dec 3, 2018

SnapshotTesting 1.0: Delightful Swift snapshot testing

Today we are open sourcing SnapshotTesting 1.0: a modern, composable snapshot testing library built entirely in Swift!

Monday Oct 29, 2018

Some news about contramap

We've seen that contramap is a powerful operation, but the name isn't fantastic. We propose a much more intuitive name for this operation, and in doing so make our code much easier to read.

Tuesday Oct 9, 2018

How to Control the World

APIs that interact with the outside world are unpredictable and make it difficult to test and simulate code paths in our apps. Existing solutions to this problem are verbose and complicated, so let's explore a simpler solution by embracing singletons and global mutation, and rejecting protocol-oriented programming and dependency injection.

Monday Oct 8, 2018

Watch episodes in your favorite podcast app!

Follow along with the newest Point-Free episodes using your favorite podcast app. We now support podcast-friendly RSS feeds for viewing all of our videos.

Thursday Sep 20, 2018

Random Zalgo Generator

Let's create a random Zalgo text generator using the simple Gen type we defined in this week's episode!

Thursday Sep 13, 2018

Type-safe HTML with Kitura

Today we're releasing a Kitura plug-in for rendering type-safe HTML. It provides a Swift compile-time API to HTML that prevents many of the runtime errors and vulnerabilities of traditional templated HTML rendering.

Thursday Sep 13, 2018

Type-safe HTML with Vapor

Today we're releasing a Vapor plug-in for rendering type-safe HTML. It provides a Swift compile-time API to HTML that prevents many of the runtime errors and vulnerabilities of traditional templated HTML rendering.

Wednesday Sep 12, 2018

Open sourcing swift-html: A Type-Safe Alternative to Templating Languages in Swift

Today we are open sourcing a new library for building HTML documents in Swift. It's extensible, transformable, type-safe, and provides many benefits over templating languages.

Friday Aug 17, 2018

Overture 0.3.0: Now with Zip

Today we are releasing Overture 0.3.0 with a bunch of useful zip functions.

Friday Aug 17, 2018

Open Sourcing Validated

Today we are open sourcing Validated, a tiny functional Swift library for handling multiple errors: functionality that you don't get from throwing functions and the Result type.

Thursday Aug 16, 2018

Solutions to Exercises: Zip Part 3

Today we solve the exercises to the third and final part of our introductory series on zip.

Wednesday Aug 15, 2018

Solutions to Exercises: Zip Part 2

Today we solve the exercises to the second part of our introductory series on zip.

Tuesday Aug 14, 2018

Solutions to Exercises: Zip Part 1

Today we solve the exercises to the first part of our introductory series on zip.

Monday Aug 6, 2018

Announcing Student Discounts

Get 50% off your Point-Free subscription with proof of enrollment at a university or coding school.

Monday Jul 30, 2018

Celebrating 6 Months

This week marks 6 months since our launch, and we’re making one of our most popular episodes free to the public!

Monday Jul 2, 2018

Conditional Coding

What happens when we combine Swift's conditional conformance with codability?

Monday Jun 25, 2018

Open Sourcing NonEmpty

Today we are open sourcing NonEmpty, a Swift library for modeling non-empty collection types. This small library can help make your code safer and more expressive with very little work.

Monday Jun 18, 2018

Tagged Seconds and Milliseconds

Let's create a type-safe interface for dealing with seconds and milliseconds in our programs. We'll use the `Tagged` type, which allows us to construct all new types in a lightweight way.

Wednesday May 30, 2018

Styling with Functions: Free for Everyone!

We are making one of our early episodes, “UIKit Styling with Functions”, free to everyone today! It’s a seminal episode that sets the foundation for some later work in the Point-Free series.

Tuesday May 15, 2018

Overture: Now with Functional Setters

Announcing Overture 0.2.0! This release is all about setters: functions that allow us to build complex transformations out of smaller units.

Monday May 7, 2018

Solutions to Exercises: Contravariance

This week we solve the exercises from our episode on contravariance, because there were _a lot_ of them!

Monday Apr 23, 2018

Case Study: Algebraic Data Types

Let’s look at a real world use for algebraic data types. We will refactor a data type that is used in the code on this very site so that the invalid states are unrepresentable by the compiler.

Monday Apr 23, 2018

Announcing Point-Free Pointers!

Today we are excited to announcement launch of Point-Free Pointers, a blog to supplement our video series for all the content we couldn’t fit in. Expect to find regularly postings here that dive even deeper into functional programming, showing real world use cases and more!