Skip to content

Instantly share code, notes, and snippets.

@phucb
Forked from pcantrell/retromodeling.md
Created December 10, 2016 06:55
Show Gist options
  • Save phucb/f999c03215b715853adc764f4a7210cf to your computer and use it in GitHub Desktop.
Save phucb/f999c03215b715853adc764f4a7210cf to your computer and use it in GitHub Desktop.

Allow Retroactive Remodeling of Modules by External Clients

  • Proposal: SE-NNNN
  • Author: Paul Cantrell
  • Status: Awaiting review
  • Review manager: TBD

Introduction

This proposal provides a robust, generalized mechanism for altering the behavior and API design of third-party libraries.

Motivation

Proposal SE-0117 proved controversial, with many on the swift-evolution list raising concerns about the proposal’s effect on clients of third-party libraries. Opponents of the proposal argued that discouraging subclassing would remove a valuable mechanism for externally altering undesired library behavior, and fixing the modeling mistakes that libraries authors inevitably make.

Proponents, however, countered that Swift already extensively discourages such retroactive modelling from the outside:

  • Swift already makes types internal by default, and strictly enforces access control across modules.
  • Library authors may opt to make classes final, closing off retro-fixing by subclassing.
  • Structs and enums are not subclassable, so patching by subclassing is already unavailable for them.
  • Members are not dynamic by default, so method swizzling is unavailable for most Swift methods.

Given these factors, even if subclassability remains available by default, it can only address a tiny fraction of the modeling problems which libraries will inevitably contain. Chris Lattner indicated on-list that SE-0117 should thus not be viewed in light of this external library fixing, and instead those concerned about the issue should propose a more robust solution to the problem if they wish it to be solved.

Furthermore, such modeling by subclassing does not notify library authors of the shortcomings of their code, causing possible duplication of effort between library clients and the loss of potential community benefit.

Proposed solution

A custom subclass effectively functions as a memberwise delta from an existing class. The shortcomings listed above of fixing by subclassing boil down to three limitations of this delta: (1) it operates at the member level (2) of classes (3) whose access controls allow subclassing.

Instead, Swift should allow third parties to create a subclass-like delta that operates on any subset of a library’s AST. We will call this fully generalized delta against a module a knife, because it cuts down the barriers between library authors and library clients.

Detailed design

A knife consists of a zero or more deltas against the AST of a module, plus a canonical reference to the version of the module from which the delta was produced. For full generality, these deltas are encoded as substring replacements of a textual representation of the AST. (Ideally, this textual representation would be human-readable, but this is probably unrealistic given the complexity of the Swift language.)

Every knife keeps a canonical reference to the module it alters, and is pinned to a specific version of that module. When the underlying module changes, a knife may go out of sync. It is thus necessary to introduce a tool to manage the deltas comprising a knife. We will call this tool biter. Library authors use biter to store their modules, and knife authors use biter to keep their knives in sync with the modules they alter.

To facilitate collaboration between library authors and clients, a new web site, biternexus.com, allows a knife author to send their knife to a library’s original author(s) as a tug proposal. If the library author chooses to accept a tug proposal, BiterFulcrum automatically generates a new version of the module including the knife’s modifications, and credits the knife author as a co-author of the parent module.

Of course, care must therefore be given to the command-line interface for biter to ensure that it contains a confusing array of ill-named operations, ideally mixing high- and low-level concepts in ways that do not map to common use cases without the use of obscure command-line flags. This will prevent unwanted participation by casual coders, and will also help generate community engagement in neglected technical Q&A sites such as Queue Overrun. It will also ensure that students learning to use biter will regularly attend the office hours of their professors, who might otherwise be idle, bored, and thus inclined to invent dangerous new uses for category theory.

This combination of knife, biter, biternexus, and tug proposal addresses all the concerns of library clients, and far outstrips the capabilities of any mechanism available today.

Impact on existing code

Existing code may opt into this new mechanism without modification.

Although this is a non-breaking change, in order to advance the cause of liberty and the human spirit, it should be introduced immediately in a special release, Swift 2.2.1.

Alternatives considered

To allow knives to be written even without the consent of a module author, knives could consist of binary deltas against the compiled module instead of against the AST.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment