A blog exploring functional programming and Swift.

Introducing XCTUnimplemented

Wednesday Jun 29, 2022

We have just released 0.3.0 of our XCTest Dynamic Overlay library, which brings a new tool that aids in constructing stronger dependencies for tests.

Dynamic XCTFail

We first open sourced XCTest Dynamic Overlay over a year ago, and its sole purpose at that time was to allow using XCTFail in application code. This allows you to write test helpers right alongside feature code without importing XCTest, which otherwise does not compile for simulators or devices.

For example, suppose you have a lightweight dependency for tracking analytics in your client:

struct AnalyticsClient {
  var track: (Event) -> Void

  struct Event: Equatable {
    var name: String
    var properties: [String: String]
  }
}

For the production app you can use a “live” version of the dependency that actually sends data to an analytics server:

extension AnalyticsClient {
  static let live = Self(
    track: { event in
      // Send event to server
    }
  )
}

But for tests we can use an “unimplemented” version of the analytics client, which allows us to prove when we don’t expect a dependency to be used in a test:

import XCTestDynamicOverlay

extension AnalyticsClient {
  static let unimplemented = Self(
    track: { _ in XCTFail("\(Self.self).track is unimplemented.") }
  )
}

If you pass along AnalyticsClient.unimplemented to your feature in tests and the test passes, you have proof that the slice of your feature you are exercising definitely does not track any analytics. That is incredibly powerful.

Without XCTest Dynamic Overlay you would need to extract this unimplemented instance to its own module just so that it could only be imported in tests. That causes a proliferation of unnecessary modules for something that should be quite simple.

XCTUnimplemented

The new XCTUnimplemented function builds on XCTest Dynamic Overlay’s core functionality by making it even easier to construct unimplemented dependencies. It is a massively overloaded function that allows you to construct a function of any form (up to 5 arguments, throwing and non-throwing, async and non-async) that immediately fails the test suite if it is ever invoked.

For example, the Analytics.unimplemented instance can now be constructed simply as:

import XCTestDynamicOverlay

extension AnalyticsClient {
  static let unimplemented = Self(
    track: XCTUnimplemented("\(Self.self).track")
  )
}

And this helper really shines with more complicated dependencies with lots of endpoints:

struct AppDependencies {
  var date: () -> Date = Date.init,
  var fetchUser: (User.ID) async throws -> User,
  var uuid: () -> UUID = UUID.init
}

extension AppDependencies {
  static let unimplemented = Self(
    date: XCTUnimplemented("\(Self.self).date", placeholder: Date()),
    fetchUser: XCTUnimplemented("\(Self.self).fetchUser"),
    uuid: XCTUnimplemented("\(Self.self).uuid", placeholder: UUID())
  )
}

Start using it today!

Add XCTest Dynamic Overlay to your project today to start building testing tools right along side your application code!

If you are interested in learning more about the concept of “unimplemented” dependencies, be sure to check out our episode on the topic!


WWDC Sale 2022

Monday Jun 6, 2022

The year’s biggest Apple event is here, and to celebrate we are offering a 25% discount off the first year for first-time subscribers. Click here to redeem the coupon now. The offer will only remain valid until June 12th.

This is the perfect time to get full access to our videos:

  • We just kicked off our deep-dive into concurrency, starting with threads and queues, and building up to Swift’s modern tools.
  • Building an application architecture from scratch that is perfectly suited for SwiftUI and UIKit applications.
  • Case studies that dive deep into solving common, real-world problems.
  • A deep-dive into parsing exploring techniques for parsing complex string formats, with a focus on composition and performance.
  • An extensive and practical study of dependencies, showing how to take control of dependencies to unleash some amazing benefits.
  • And more…

We hope you’ll join us for all of the great material we have planned for the rest of the year!


Open Sourcing URLRouting and VaporRouting

Monday May 2, 2022

We are excited to announce two brand new open source projects that bring composable, type safe, and bidirectional routing to both iOS client applications and server-side Swift applications:

  • The URL Routing library gives you tools for transforming URL requests into first class data types, and the reverse to turn data back into URL requests. Learn more
  • The Vapor Routing library gives you tools for handling routing in a Vapor web application in a type safe way and for statically linking to any part of you website. Learn more

Both libraries are built on the back of our powerful Parsing library, and shows just how useful generalized parsing can be.

URLRouting

The URL Routing library gives you access to tools that can parse a nebulous URL request into a first class data type, with composability, type safety and ergonomics in mind. This can be useful for client-side iOS applications that need to support deep-linking, as well as server-side applications.

To use the library you first begin with a domain modeling exercise. You model a route enum that represents each URL you want to recognize in your application, and each case of the enum holds the data you want to extract from the URL.

For example, if we had screens in our Books application that represent showing all books, showing a particular book, and searching books, we can model this as an enum:

enum AppRoute {
  case books
  case book(id: Int)
  case searchBooks(query: String, count: Int = 10)
}

Notice that we only encode the data we want to extract from the URL in these cases. There are no details of where this data lives in the URL, such as whether it comes from path parameters, query parameters or POST body data.

Those details are determined by the router, which can be constructed with the tools shipped in URL Routing library. Its purpose is to transform an incoming URL into the AppRoute type. For example:

import URLRouting

let appRouter = OneOf {
  // GET /books
  Route(.case(AppRoute.books))) {
    Path { "books" }
  }

  // GET /books/:id
  Route(.case(AppRoute.books(id:))) {
    Path { "books"; Digits() }
  }

  // GET /books/search?query=:query&count=:count
  Route(.case(AppRoute.searchBooks(query:count:))) {
    Path { "books"; "search" }
    Query {
      Field("query")
      Field("count", default: 10) { Digits() }
    }
  }
}

This router describes at a high-level how to pick apart the path components, query parameters, and more from a URL in order to transform it into an AppRoute.

Once this router is defined you can use it to implement deep-linking logic in your application. You can implement a single function that accepts a URL, use the router’s match method to transform it into an AppRoute, and then switch on the route to handle each deep link destination:

func handleDeepLink(url: URL) throws {
  switch try appRouter.match(url: url) {
  case .books:
    // navigate to books screen

  case let .book(id: id):
    // navigate to book with id

  case let .searchBooks(query: query, count: count):
    // navigate to search screen with query and count
  }
}

This kind of routing is incredibly useful in client side iOS applications, but it can also be used in server-side applications. Even better, it can automatically transform AppRoute values back into URLs, which is handy for linking to various parts of your website:

appRoute.path(for: .searchBooks(query: "Blob Bio"))
// "/books/search?query=Blob%20Bio"
Node.ul(
  books.map { book in
    .li(
      .a(
        .href(appRoute.path(for: .book(id: book.id))),
        book.title
      )
    )
  }
)
<ul>
  <li><a href="/books/1">Blob Autobiography</a></li>
  <li><a href="/books/2">Blobbed around the world</a></li>
  <li><a href="/books/3">Blob's guide to success</a></li>
</ul>

This can be incredibly powerful for generating provably correct URLs within your site, and not having to worry about routes changing or typos being accidentally introduced. In fact, we use the URL routing to power routing on this very site, which you can see by peeking at the code since it is all open source.

VaporRouting

As we can see, URL Routing provides some useful tools for server-side applications, which is why we are also open sourcing Vapor Routing, which provides Vapor bindings to the URL Routing library.

Routing in Vapor has a simple API that is similar to popular web frameworks in other languages, such as Ruby’s Sinatra or Node’s Express. It works well for simple routes, but complexity grows over time due to lack of type safety and inability to generate correct URLs to pages on your site.

To see this, consider an endpoint to fetch a book that is associated with a particular user:

// GET /users/:userId/books/:bookId
app.get("users", ":userId", "books", ":bookId") { req -> Response in
  guard
    let userId = req.parameters.get("userId", Int.self),
    let bookId = req.parameters.get("bookId", Int.self)
  else {
    struct BadRequest: Error {}
    throw BadRequest()
  }

  // Logic for fetching user and book and constructing response...
  let user = try await database.fetchUser(user.id)
  let book = try await database.fetchBook(book.id)
  return BookResponse(...)
}

When a URL request is made to the server whose method and path matches the above pattern, the closure will be executed for handling that endpoint’s logic.

Notice that we must sprinkle in validation code and error handling into the endpoint’s logic in order to coerce the stringy parameter types into first class data types. This obscures the real logic of the endpoint, and any changes to the route’s pattern must be kept in sync with the validation logic, such as if we wanted to rename the :userId or :bookId parameters.

In addition to these drawbacks, we often need to be able to generate valid URLs to various server endpoints. For example, suppose we wanted to [generate an HTML page][swift-html-vapor] with a list of all the books for a user, including a link to each book. We have no choice but to manually interpolate a string to form the URL, or build our own ad hoc library of helper functions that do this string interpolation under the hood:

Node.ul(
  user.books.map { book in
    .li(
      .a(.href("/users/\(user.id)/book/\(book.id)"), book.title)
    )
  }
)
<ul>
  <li><a href="/users/42/book/321">Blob autobiography</a></li>
  <li><a href="/users/42/book/123">Life of Blob</a></li>
  <li><a href="/users/42/book/456">Blobbed around the world</a></li>
</ul>

It is our responsibility to make sure that this interpolated string matches exactly what was specified in the Vapor route. This can be tedious and error prone.

In fact, there is a typo in the above code. The URL constructed goes to “/book/:bookId”, but really it should be “/books/:bookId”:

- .a(.href("/users/\(user.id)/book/\(book.id)"), book.title)
+ .a(.href("/users/\(user.id)/books/\(book.id)"), book.title)

VaporRouting aims to solve these problems, and more, when dealing with routing in a Vapor application.

To use the library, one starts by constructing an enum that describes all the routes your website supports. For example, the book endpoint described above can be represented as:

enum SiteRoute {
  case userBook(userId: Int, bookId: Int)
  // more cases for each route
}

Then you construct a router, which is an object that is capable of parsing URL requests into SiteRoute values and printing SiteRoute values back into URL requests. Such routers can be built from various types the library vends, such as Path to match particular path components, Query to match particular query items, Body to decode request body data, and more:

import VaporRouting

let siteRouter = OneOf {
  // Maps the URL "/users/:userId/books/:bookId" to the
  // SiteRouter.userBook enum case.
  Route(.case(SiteRouter.userBook)) {
    Path { "users"; Digits(); "books"; Digits() }
  }

  // More uses of Route for each case in SiteRoute
}

Note: Routers are built on top of the Parsing library, which provides a general solution for parsing more nebulous data into first-class data types, like URL requests into your app’s routes.

Once that little bit of upfront work is done, using the router doesn’t look too dissimilar from using Vapor’s native routing tools. First you mount the router to the application to take care of all routing responsibilities, and you do so by providing a closure that transforms SiteRoute to a response:

// configure.swift
public func configure(_ app: Application) throws {
  ...

  app.mount(siteRouter, use: siteHandler)
}

func siteHandler(
  request: Request,
  route: SiteRoute
) async throws -> AsyncResponseEncodable {
  switch route {
  case .userBook(userId: userId, bookId: bookId):
    let user = try await database.fetchUser(user.id)
    let book = try await database.fetchBook(book.id)
    return BookResponse(...)

  // more cases...
  }
}

Notice that handling the .userBook case is entirely focused on just the logic for the endpoint, not parsing and validating the parameters in the URL.

With that done you can now easily generate URLs to any part of your website using a type safe, concise API. For example, generating the list of book links now looks like this:

Node.ul(
  user.books.map { book in
    .li(
      .a(
        .href(siteRouter.path(for: .userBook(userId: user.id, bookId: book.id)),
        book.title
      )
    )
  }
)

Note there is no string interpolation or guessing what shape the path should be in. All of that is handled by the router. We only have to provide the data for the user and book ids, and the router takes care of the rest. If we make a change to the siteRouter, such as recognizer the singular form “/user/:userId/book/:bookId”, then all paths will automatically be updated. We will not need to search the code base to replace “users” with “user” and “books” with “book”.

Get started today!

That’s a short summary of the powers these libraries contain, but there is a lot more to discover. If you currently maintain deep-linking in your iOS application or a server-side Swift application, try our libraries today for improved compile-time safety and composability! Version 0.1.0 of URLRouting and VaporRouting have just been released.


Older blog posts

Monday Apr 11, 2022

Parser-printer unification

A new release of swift-parsing brings printing capabilities to your parsers for transforming structured data back into unstructured data.

Monday Feb 14, 2022

Parser Errors

A new release of swift-parsing that brings delightful and informative error messaging to parser failures.

Wednesday Feb 9, 2022

Backtracking Parsers

Monday Jan 24, 2022

Introducing Parser Builders

Today we are releasing 0.5.0 of our swift-parsing library, which leverages result builders for creating complex parsers with a minimal amount of syntactic noise. Learn how in this week's blog post, and give the library a spin today!

Monday Jan 3, 2022

Unobtrusive runtime warnings for libraries

Runtime warnings in libraries are a great way to notify your users that something unexpected has happened, or that an API is being used in an incorrect manner. In this post we give an overview of some techniques that can be employed easily today, as well as discuss a technique for surfacing runtime warnings that is both very visible and unobtrusive.

Wednesday Dec 22, 2021

2021 Year-in-review

Point-Free year in review: 42 episodes, 72k visitors, 5 new open source projects, and more!

Tuesday Nov 16, 2021

Open Sourcing SwiftUI Navigation

Today we are open sourcing SwiftUI Navigation, a collection of tools for making SwiftUI navigation simpler, more ergonomic and more precise.

Tuesday Oct 26, 2021

Give the Gift of Point-Free

Today we are excited to announce that you can now gift a Point-Free subscription to your friends, colleagues and loved ones.

Wednesday Sep 15, 2021

Point Freebies: Swift Concurrency and More

We're celebrating the release of Xcode 13 by making all of our WWDC 2021 videos free! Explore SwiftUI's new refreshable and FocusState APIs, both in the context of vanilla SwiftUI and the Composable Architecture, and learn how to build a map-powered application from scratch using the new searchable API.

Monday Sep 6, 2021

The Composable Architecture ❤️ SwiftUI Bindings

Today we are improving the Composable Architecture's first-party support for SwiftUI bindings with a safer, even conciser syntax.

Monday Aug 23, 2021

Open Sourcing: Custom Dump

Today we are open sourcing Custom Dump, a collection of tools for debugging, diffing, and testing your application's data structures.

Wednesday Jul 14, 2021

Better Performance Bonanza

The past 3 weeks we've shipped updates to 3 of our libraries, focused on improving the performance of your Composable Architecture applications, and more!

Monday Jul 12, 2021

Open Sourcing Identified Collections

Today we are open sourcing Identified Collections, a library of data structures for working with collections of identifiable elements in a performant way.

Monday Jun 14, 2021

Announcing SwitchStore for the Composable Architecture

We are adding new tools for handling enum state in the Composable Architecture, with a focus on safety and performance.

Wednesday May 12, 2021

A Tour of isowords

This past month we released four completely free videos dedicated to diving into the real-world Swift code base of an iOS game we recently launched and open sourced: isowords.

Monday Mar 22, 2021

Better Testing Bonanza

We're open sourcing a library that makes it easier to be more exhaustive in writing tests.

Wednesday Mar 17, 2021

Open Sourcing isowords

We're open sourcing the entire code base to our newly released iOS word game, isowords!

Wednesday Mar 17, 2021

Announcing: isowords

We are excited to release isowords to the App Store, a new word search game for your phone. Download today!

Monday Mar 8, 2021

Composable Architecture Test Store Improvements

Composable Architecture 0.16.0 comes with significant improvements to its testing capabilities for tracking down effect-related failures.

Monday Feb 1, 2021

Composable Forms: Say "Bye" to Boilerplate!

Today we are releasing first-party support for concisely handling form data in the Composable Architecture.

Wednesday Dec 23, 2020

2020 Year-in-review

The Composable Architecture, dependency management, parsers, Combine schedulers and more! Join us for a review of everything we accomplished in 2020!

Monday Dec 21, 2020

Open Sourcing Parsing

Today we are open sourcing Parsing, a library for turning nebulous data into well-structured data, with a focus on composition, performance, and generality.

Tuesday Jun 30, 2020

The Composable Architecture and SwiftUI Alerts

Today we are releasing a new version of the Composable Architecture with helpers that make working with SwiftUI alerts and action sheets a breeze.

Monday Jun 22, 2020

Core Motion support in the Composable Architecture

We are releasing our second mini-library for the Composable Architecture, which makes it easy to use Core Motion.

Monday Jun 15, 2020

Open Sourcing CombineSchedulers

Today we are open-sourcing CombineSchedulers, a library that introduces a few schedulers that makes working with Combine more testable and more versatile.

Wednesday May 27, 2020

Instrumenting features built in the Composable Architecture

Today we are releasing first-party support for instrumenting features built in the Composable Architecture.

Wednesday May 20, 2020

Core Location support in the Composable Architecture

We are releasing a mini-library that makes it easy to use Core Location inside the Composable Architecture.

Tuesday May 12, 2020

Regional Discounts

Regional discounts takes 50% off a monthly or yearly personal subscription to anyone whose credit card is issued from a particular list of countries.

Monday May 4, 2020

Composable Architecture, the library

Today we are releasing the Composable Architecture as an open-source library. It is a way to build applications in a consistent and understandable way, with composition, testing and ergonomics in mind.

Wednesday Mar 11, 2020

Announcing Episode Collections

After over two years and nearly 100 episodes we are finally launching episode collections on Point-Free!

Friday Feb 21, 2020

Share Point-Free with friends and save!

Today we're excited to announce support for referral bonuses! When friends and colleagues of yours subscribe to Point-Free with your referral link, both of you will get one month free.

Tuesday Feb 4, 2020

Open Sourcing Case Paths

Today we are open sourcing CasePaths, a library that introduces the power and ergonomics of key paths to enums!

Monday Dec 30, 2019

2019 Year-in-review

Random number generators, parsers, SwiftUI, composable architecture and more! Join us for a review of everything we accomplished in 2019!

Monday Dec 23, 2019

Snapshot Testing SwiftUI

Snapshot testing gives us broad test coverage on our SwiftUI views with very little up front work.

Wednesday Dec 18, 2019

Free Video: Testing SwiftUI

A free video exploring how to test SwiftUI.

Wednesday Nov 20, 2019

A Crash Course in Combine

Two free videos exploring Apple's new Combine framework, its core components, and how to integrate it in your code.

Thursday Nov 7, 2019

Higher-Order Snapshot Testing

How to enrich snapshot testing strategies with additional behavior using higher-order constructions.

Tuesday Jul 30, 2019

SwiftUI and State Management Corrections

Xcode 11 beta 5 has brought lots of changes to SwiftUI, and we'd like to take a moment to provide corrections to our episodes based on these changes.

Thursday May 9, 2019

Enterprise Subscriptions

Point-Free now supports enterprise subscriptions, making it easier than ever to manage a team subscription for larger organizations! For a fixed yearly rate, everyone with an email from your company's domain will get instant access to everything Point-Free has to offer. Contact us for more info!

Monday Apr 29, 2019

Open Sourcing Enum Properties

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!

Monday Mar 18, 2019

Open Sourcing Gen

Today we are open sourcing Gen: a lightweight wrapper around Swift's randomness API's that makes randomness 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?

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!