2022-10-07T10:57:30-07:00https://nshipster.com/feed.xmlNSHipsterNSHipster is a journal of the overlooked bits in Objective-C, Swift, and Cocoa.
Matttmattt@nshipster.comhttps://nshipster.com/authors/matttAs We May Code2020-07-07T00:00:00-07:002020-07-07T00:00:00-07:00https://nshipster.com/as-we-may-code
<p>Chris Lattner often describes <a href="http://llvm.org/" rel="noopener noreferrer">LLVM</a> as a process of <dfn>lowering</dfn>.</p>
<p><img alt="Swift Compiler Architecture Diagram" src="/assets/swift-compilation-diagram-32f5a8f51b322cce3d014fb7a595c5c5c81bb86f0b6b1dc1fd0d8799178cad1f6c3935b23202f38ced5d1ffce1c6a62b14f2e4ef33aa68a68ea3830162e45166.png" integrity="sha512-MvWo9RsyLM49AU+3pZXFxcgbuG8Lax3B/Q2HmReMrR9sOTWyMgLzjO1dH/zhxqYrFPLk7zOqaKaOo4MBYuRRZg==" crossorigin="anonymous"></p>
<p>You start at the highest level of abstraction,
source code written in a programming language like Swift or Objective-C.
That code is parsed into an abstract syntax tree,
(<abbr title="Abstract Syntax Tree">AST</abbr>),
which is progressively transformed into
lower-level, intermediate representations
until it finally becomes executable binary.</p>
<p>What if,
instead of lowering source code down for the purpose of execution,
<!-- *bong rip* -->
we <em>raised</em> source code for the purpose of understanding?</p>
<aside class="parenthetical">
<p>It’s a weird premise, I know. Bear with me.</p>
</aside>
<p>You could say that we already do this to some degree with
<a href="/swiftsyntax/#highlighting-swift-code">syntax highlighting</a> <br>
(<span class="nohighlight"><code>func f()</code></span> → <code><span class="kd">func</span> <span class="nf">f</span><span class="p">()</span></code>),
<a href="/swiftsyntax/">structured editing</a>, and
<a href="/swift-documentation/">documentation generation</a>.
But how far could we take it?</p>
<hr><a id="get-on-with-it"></a>
<p>In this article,
I’d like to share an idea that I’ve been kicking around for a while.
It’s something that’s come into greater focus with
my recent work on <a href="https://github.com/SwiftDocOrg/swift-doc/" rel="noopener noreferrer"><code>swift-doc</code></a>,
but first started to form during tenure in Apple Developer Publications,
back in 2015.</p>
<p>The idea is this: <br>
<strong>What if we took the lessons of the <a href="https://en.wikipedia.org/wiki/Semantic_Web" rel="noopener noreferrer">semantic web</a>
and applied them to source code?</strong></p>
<p>Specifically:</p>
<ul>
<li>
<strong>Representation</strong>:
Software components should be represented by
a common, language-agnostic data format.</li>
<li>
<strong>Addressability</strong>:
Packages, modules, and their constituent APIs
should each have a unique URL identifier.</li>
<li>
<strong>Decentralization</strong>:
Information should be distributed across a federated network of data sources,
which can cross-reference one another by URL.</li>
</ul>
<p>I grew up with the Internet,
and got to see it, first-hand,
go from an obscure technology to <em>the</em> dominant cultural force.
So much of what I see in software development today
reminds me of what I remember about the web from 20 years ago.
And if you’ll forgive the extended wind-up,
I think there’s a lot we can learn by looking at that evolution.</p>
<aside class="parenthetical">
<p>As I wrote in my article about <a href="/cross-pollination">cross-pollination</a>,
great ideas often arise from unlikely connections.</p>
</aside>
<aside class="admonition warning">
<p>If you’re already familiar with semantic web
or aren’t all that interested in a history lesson
feel free to <a href="#skip" rel="noopener noreferrer">skip ahead to the technical details</a>.</p>
</aside>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="web-10-the-web-of-documents" href="#web-10-the-web-of-documents"></a><small>Web 1.0</small> The Web of Documents</h2>
<p>Tim Berners-Lee launched the World Wide Web
from a NeXT workstation 27 years ago.
His vision for a
globally-distributed, decentralized network of inter-connected documents
gave rise to the Internet as we know it today.
But it was also part of an intellectual tradition dating back to the 1940s,
which includes
Vannevar Bush’s <em><a href="https://en.wikipedia.org/wiki/Memex" rel="noopener noreferrer">Memex</a></em>,
Ted Nelson’s <em><a href="https://en.wikipedia.org/wiki/Project_Xanadu" rel="noopener noreferrer">Xanadu</a></em>, and
Doug Engelbart’s <em><a href="https://en.wikipedia.org/wiki/The_Mother_of_All_Demos" rel="noopener noreferrer">Mother of All Demos</a></em>.</p>
<aside class="admonition info">
<p>Dr. Bush coined the term <dfn>memex</dfn> in an essay titled
<a href="https://www.theatlantic.com/magazine/archive/1945/07/as-we-may-think/303881/" rel="noopener noreferrer">“As We May Think”</a>,
published in the July 1945 issue of <em>The Atlantic</em>.</p>
</aside>
<p>In those early days,
the knowledge being shared was primarily academic.
As the userbase grew over time,
so too did the breadth and diversity of the information available.
And, for a time,
that’s what the Internet was:
<a href="http://www.automaticbeyondbelief.org" rel="noopener noreferrer">fan sites</a> for Sunbeam toasters,
<a href="http://www.varasanos.com/PizzaRecipe.htm" rel="noopener noreferrer">recipes</a> for Neapolitan-style pizza, and
<a href="https://www.spacejam.com" rel="noopener noreferrer">the official website</a> for the 1996 film <em>Space Jam</em>.</p>
<p>But the web of documents had limits.</p>
<p>If you wanted to
shop for appliances,
see the menu of a pizza shop, or
get local showtimes for a movie,
you <em>might</em> be able to do that on the early Internet.
But you really had to work at it.</p>
<p>Back then,
you’d start by going to a directory like <a href="https://en.wikipedia.org/wiki/Yahoo!_Directory" rel="noopener noreferrer">Yahoo!</a> or <a href="https://en.wikipedia.org/wiki/DMOZ" rel="noopener noreferrer">DMOZ</a>,
navigate to the relevant topic,
and click around until you found a promising lead.
Most of the time, you wouldn’t find what you were looking for;
instead, you’d disconnect your modem to free up your landline
and consult the <a href="https://en.wikipedia.org/wiki/Yellow_pages" rel="noopener noreferrer">yellow pages</a>.</p>
<aside class="admonition info">
<p>As it were,
the difficulty of finding information on the web
gave us the term <a href="https://en.wikipedia.org/wiki/Sherlock_(software)#Sherlocked_as_a_term" rel="noopener noreferrer"><dfn>Sherlocked</dfn></a>.
Apple’s v3 release of the eponymous system software
was widely seen to have killed Karelia Software’s
<a href="https://en.wikipedia.org/wiki/Karelia_Watson" rel="noopener noreferrer">Watson</a>:
a similar (paid) application for Mac OS X
that offered a uniform interface to information like stocks, movies, and flights.</p>
</aside>
<p>This started to change in the early ’00s.</p>
<h2>
<a class="anchor" aria-hidden="true" id="web-20-the-social-web" href="#web-20-the-social-web"></a><small>Web 2.0</small> The Social Web</h2>
<p>With <a href="https://en.wikipedia.org/wiki/Common_Gateway_Interface" rel="noopener noreferrer">Perl CGI</a> and <a href="https://en.wikipedia.org/wiki/PHP" rel="noopener noreferrer">PHP</a>,
you could now easily generate web pages on-the-fly.
This enabled eCommerce and the first commercial uses of the Internet.</p>
<p>After the ensuing <a href="https://en.wikipedia.org/wiki/Dot-com_bubble" rel="noopener noreferrer">dot-com bubble</a>,
you had technologies like <a href="https://en.wikipedia.org/wiki/Java_applet" rel="noopener noreferrer">Java applets</a> and <a href="https://en.wikipedia.org/wiki/Adobe_Flash" rel="noopener noreferrer">Flash</a>
bring a new level of interactivity to web sites.
Eventually, folks figured out how to use
<a href="https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest" rel="noopener noreferrer">an obscure API from Internet Explorer 5</a>
to replicate this interactivity on normal webpages —
a technique dubbed <a href="https://en.wikipedia.org/wiki/Ajax_(programming)" rel="noopener noreferrer">AJAX</a>.
Interacting with a page and seeing results live, without reloading a page?
This was <em>huge</em>.
Without that,
social media might not have taken off as it did.</p>
<p>Anyway,
the server-side APIs powering those AJAX interactions on the client,
they were the secret sauce that let the Internet evolve into what it is today.</p>
<p>Remember <dfn>“<a href="https://en.wikipedia.org/wiki/Mashup_(web_application_hybrid)" rel="noopener noreferrer">mashups</a>”</dfn>?</p>
<p>Thanks to all of these (often unsecured) AJAX endpoints,
developers could synthesize information across multiple sources
in ways that nobody had ever thought to do.
You could get someone’s location from <a href="https://en.wikipedia.org/wiki/Fire_Eagle" rel="noopener noreferrer">Fire Eagle</a>,
search for photos taken nearby on <a href="https://www.flickr.com" rel="noopener noreferrer">Flickr</a>,
and use <a href="https://www.moo.com/us/" rel="noopener noreferrer">MOO</a> to print and deliver prints of them on-demand.</p>
<aside class="parenthetical">
<p>Mashups felt like punk rock.
I have a lot of fond memories from this time.</p>
</aside>
<p>By the end of the decade,
the rise of social networks and the early promise of mashups
started to coalesce into the modern Internet.</p>
<h2>
<a class="anchor" aria-hidden="true" id="web-30-the-web-of-data" href="#web-30-the-web-of-data"></a><small>Web 3.0</small> The Web of Data</h2>
<p>The term “Web 3.0” didn’t catch on like its predecessor,
but there’s a clear delineation between
the technologies and culture of the web between the early and late ’00s.</p>
<p>It’s hard to overstate how much the iPhone’s launch in 2007
totally changed the trajectory of the Internet.
But many other events played an important role in
shaping the web as we know it today:</p>
<ul>
<li>Google acquiring the company behind <a href="https://en.wikipedia.org/wiki/Freebase_(database)" rel="noopener noreferrer">Freebase</a>,
giving it a knowledge graph to augment its website index.</li>
<li>Facebook launching <a href="https://ogp.me" rel="noopener noreferrer">Open Graph</a>,
which meant everything could now be “Liked”
(and everyone could be targeted for advertisements).</li>
<li>Yahoo releasing <a href="https://en.wikipedia.org/wiki/Yahoo!_SearchMonkey" rel="noopener noreferrer">SearchMonkey</a> and
<a href="https://en.wikipedia.org/wiki/Yahoo!_Search_BOSS" rel="noopener noreferrer"><abbr title="Build your Own Search Service">BOSS</abbr></a>,
two ambitious (albeit flawed) attempts
to carve out a niche from Google’s monopoly on search.</li>
<li>Wolfram launching <a href="https://www.wolframalpha.com" rel="noopener noreferrer">Wolfram|Alpha</a>,
which far exceeded what many of us thought was possible
for a question answering system.</li>
</ul>
<p>The Internet always had a lot of information on it;
the difference now is that
the information is accessible to machines as well as humans.</p>
<p>Today,
you can ask Google
<a href="https://www.google.com/search?q=Who+was+the+first+person+to+land+on+the+moon%3F" rel="noopener noreferrer"><em>“Who was the first person to land on the moon?”</em></a>
and get an info box saying, <em>“Commander Neil Armstrong”</em>.
You can post a link in Messages
and see it represented by
<a href="/ios-13/#generate-rich-representations-of-urls">a rich visual summary</a>
instead of a plain text URL.
You can ask Siri,
<em>“What is the <a href="https://twitter.com/AirspeedSwift" rel="noopener noreferrer">airspeed velocity</a> of an unladen swallow?”</em> and hear back
<del><em>“I can’t get the answer to that on HomePod”</em></del>
<ins><em>About 25 miles per hour</em></ins>.</p>
<aside class="parenthetical">
<p>We’re just kidding about that last one.
Siri has gotten a lot better in recent years.</p>
</aside>
<p>Think about what we take for granted about the Internet now,
and try to imagine doing that on the web when it looked
<a href="https://www.spacejam.com" rel="noopener noreferrer">like this</a>.
It’s hard to think that any of this would be possible without the semantic web.</p>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="githubcom-present-day-the-spider-and-the-octocat" href="#githubcom-present-day-the-spider-and-the-octocat"></a><small>GitHub.com, Present Day</small> The Spider and The Octocat</h2>
<p>READMEs on GitHub.com today remind me of
personal home pages on <a href="https://en.wikipedia.org/wiki/Yahoo!_GeoCities" rel="noopener noreferrer">Geocities</a> back in the Web 1.0 days.</p>
<aside class="admonition info">
<p>Compare the “build passing” SVG badges found at the top of READMEs in 2020
to the 80×15px “XHTML 1.1 ✓” badges found at the bottom of websites in 2000.</p>
<p><img width="800" src="/assets/as-we-may-code-badges-0f6950f9abfe7232857701c91011db3e910db384fea0e066d95db39346ed4f43fbe936b6ca82b24045917804b894acf51fe431a02bd7d71df6598d1923dd33b4.png" integrity="sha512-D2lQ+av+cjKFdwHJEBHbPpENs4T+oOBm2V2zk0btT0P76Ta2yoKyQEWReAS4lKz1H+QxoCvX1x32WY0ZI90ztA==" crossorigin="anonymous" alt=""></p>
</aside>
<p>Even with the <a href="https://primer.style/css/" rel="noopener noreferrer">standard coat of paint</a>,
you see an enormous degree of variance across projects and communities.
Some are sparse; others are replete with adornment.</p>
<p>And yet,
no matter what a project’s README looks like,
onboarding onto a new tool or library entails, well <em>reading</em>.</p>
<aside class="parenthetical">
<p>I mean, it’s right there in capital letters: “READ ME”</p>
</aside>
<p>GitHub offers some structured informational cues:
language breakdown, license, some metadata about commit activity.
You can search within the repo using text terms.
And thanks to <a href="https://github.com/github/semantic" rel="noopener noreferrer">semantic</a> / <a href="https://github.com/tree-sitter" rel="noopener noreferrer">tree-sitter</a>,
you can even click through to find declarations in some languages.</p>
<p><em>But where’s a list of methods?</em>
<em>Where are the platform requirements?</em> <br>
You have to read the README to find out!
(Better hope it’s up-to-date 😭)</p>
<p>The modest capabilities of browsing and searching code today
more closely resemble <a href="https://en.wikipedia.org/wiki/AltaVista" rel="noopener noreferrer">AltaVista</a> circa 2000 than Google circa 2020.
Theres so much more that we could be doing.</p>
<hr>
<p><a name="skip"></a></p>
<h2>
<a class="anchor" aria-hidden="true" id="rdf-vocabularies-the-owl-and-the-turtle" href="#rdf-vocabularies-the-owl-and-the-turtle"></a><small>RDF Vocabularies</small> The Owl and The Turtle</h2>
<p>At the center of the semantic web is something called
<abbr title="Resource Description Framework"><a href="https://en.wikipedia.org/wiki/Resource_Description_Framework" rel="noopener noreferrer">RDF</a></abbr>,
the Resource Description Framework.
It’s a collection of standards for representing and exchanging data.
The atomic data entity in <abbr>RDF</abbr>
is called a <dfn>triple</dfn>, which comprises:</p>
<ul>
<li>a subject <em>(“the sky”)</em>
</li>
<li>a predicate <em>(“has the color”)</em>
</li>
<li>an object <em>(“blue”</em>)</li>
</ul>
<p>You can organize triples according to a
<dfn>vocabulary</dfn>, or <dfn>ontology</dfn>,
which defines rules about how things are described.
RDF vocabularies are represented by the
Web Ontology Language
(<abbr title="Web Ontology Language"><a href="https://en.wikipedia.org/wiki/Web_Ontology_Language" rel="noopener noreferrer">OWL</a></abbr>).</p>
<p>The ideas behind RDF are simple enough.
Often, the hardest part is navigating
its confusing, acronym-laden technology stack.
The important thing to keep in mind is that
information can be represented in several different ways
without changing the meaning of that information.</p>
<p>Here’s a quick run-down:</p>
<dl>
<dt><a href="https://en.wikipedia.org/wiki/RDF/XML" rel="noopener noreferrer">RDF/XML</a></dt>
<dd>An XML representation format for <abbr>RDF</abbr> graphs.</dd>
<dt><a href="https://en.wikipedia.org/wiki/JSON-LD" rel="noopener noreferrer">JSON-LD</a></dt>
<dd>A JSON representation format for <abbr>RDF</abbr> graphs.</dd>
<dt><a href="https://en.wikipedia.org/wiki/N-Triples" rel="noopener noreferrer">N-Triples</a></dt>
<dd>A plain text representation format for <abbr>RDF</abbr> graphs
where each line encodes a subject–predicate–object triple.</dd>
<dt><a href="https://en.wikipedia.org/wiki/Turtle_(syntax)" rel="noopener noreferrer">Turtle</a></dt>
<dd>A human-friendly, plain text representation format for <abbr>RDF</abbr> graphs.
A superset of N-Triples,
and the syntax used in <abbr>SPARQL</abbr> queries.</dd>
<dt><a href="https://en.wikipedia.org/wiki/SPARQL" rel="noopener noreferrer">SPARQL</a></dt>
<dd>A query language for <abbr>RDF</abbr> graphs.</dd>
</dl>
<h3>
<a class="anchor" aria-hidden="true" id="defining-a-vocabulary" href="#defining-a-vocabulary"></a>Defining a Vocabulary</h3>
<p>Let’s start to define a vocabulary for the Swift programming language.
To start,
we’ll define the concept of a
<code>Symbol</code> along with two subclasses, <code>Structure</code> and <code>Function</code>.
We’ll also define a <code>name</code> property that holds a token (a string)
that applies to any <code>Symbol</code>.
Finally,
we’ll define a <code>returns</code> property that applies to a <code>Function</code>
and holds a reference to another <code>Symbol</code>.</p>
<div class="highlight-group">
<div role="tablist" aria-label="Languages">
<button role="tab" id="code-listing-1-turtle-tab" class="turtle" aria-label="Languages" aria-controls="code-listing-1-turtle" aria-selected="true" tabindex="-1">
Turtle
</button>
<button role="tab" id="code-listing-1-xml-tab" class="xml" aria-label="Languages" aria-controls="code-listing-1-xml" aria-selected="false" tabindex="-1">
XML
</button>
</div>
<pre class="highlight" data-lang="Turtle" id="code-listing-1-turtle" role="tabpanel" tabindex="0" aria-labelledby="code-listing-1-turtle-tab"><code><span class="kd">@prefix</span><span class="w"> </span><span class="nn">:</span><span class="w"> </span><span class="nl"><http://www.swift.org/#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">owl:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2002/07/owl#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">rdf:</span><span class="w"> </span><span class="nl"><http://www.w3.org/1999/02/22-rdf-syntax-ns#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">rdfs:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2000/01/rdf-schema#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">xsd:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2001/XMLSchema#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">:</span><span class="n">Symbol</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">owl:</span><span class="n">Class</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">:</span><span class="n">name</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">owl:</span><span class="n">Functional<wbr></wbr>Property</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">rdfs:</span><span class="n">domain</span><span class="w"> </span><span class="nn">:</span><span class="n">Symbol</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">rdfs:</span><span class="n">range</span><span class="w"> </span><span class="nn">xsd:</span><span class="n">token</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">:</span><span class="n">Structure</span><span class="w"> </span><span class="nn">rdfs:</span><span class="n">sub<wbr></wbr>Class<wbr></wbr>Of</span><span class="w"> </span><span class="nn">:</span><span class="n">Symbol</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">:</span><span class="n">Function</span><span class="w"> </span><span class="nn">rdfs:</span><span class="n">sub<wbr></wbr>Class<wbr></wbr>Of</span><span class="w"> </span><span class="nn">:</span><span class="n">Symbol</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">:</span><span class="n">returns</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">owl:</span><span class="n">Functional<wbr></wbr>Property</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">rdfs:</span><span class="n">domain</span><span class="w"> </span><span class="nn">:</span><span class="n">Function</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">rdfs:</span><span class="n">range</span><span class="w"> </span><span class="nn">:</span><span class="n">Symbol</span><span class="w"> </span><span class="p">.</span><span class="w">
</span></code></pre>
<pre class="highlight" data-lang="XML" id="code-listing-1-xml" role="tabpanel" tabindex="0" aria-labelledby="code-listing-1-xml-tab" hidden="hidden"><code><span class="cp"><?xml version="1.0" encoding="utf-8" ?></span>
<span class="nt"><rdf:RDF</span> <span class="na">xmlns:rdf=</span><span class="s">"http://www.w3.org/1999/02/22-rdf-syntax-ns#"</span>
<span class="na">xmlns:rdfs=</span><span class="s">"http://www.w3.org/2000/01/rdf-schema#"</span>
<span class="na">xmlns:owl=</span><span class="s">"http://www.w3.org/2002/07/owl#"</span><span class="nt">></span>
<span class="nt"><owl:Class</span> <span class="na">rdf:about=</span><span class="s">"http://www.swift.org/#Symbol"</span><span class="nt">></owl:Class></span>
<span class="nt"><owl:Functional<wbr></wbr>Property</span> <span class="na">rdf:about=</span><span class="s">"http://www.swift.org/#name"</span><span class="nt">></span>
<span class="nt"><rdfs:domain</span> <span class="na">rdf:resource=</span><span class="s">"http://www.swift.org/#Symbol"</span><span class="nt">/></span>
<span class="nt"><rdfs:range</span> <span class="na">rdf:resource=</span><span class="s">"http://www.w3.org/2001/XMLSchema#token"</span><span class="nt">/></span>
<span class="nt"></owl:Functional<wbr></wbr>Property></span>
<span class="nt"><rdf:Description</span> <span class="na">rdf:about=</span><span class="s">"http://www.swift.org/#Structure"</span><span class="nt">></span>
<span class="nt"><rdfs:sub<wbr></wbr>Class<wbr></wbr>Of</span> <span class="na">rdf:resource=</span><span class="s">"http://www.swift.org/#Symbol"</span><span class="nt">/></span>
<span class="nt"></rdf:Description></span>
<span class="nt"><rdf:Description</span> <span class="na">rdf:about=</span><span class="s">"http://www.swift.org/#Function"</span><span class="nt">></span>
<span class="nt"><rdfs:sub<wbr></wbr>Class<wbr></wbr>Of</span> <span class="na">rdf:resource=</span><span class="s">"http://www.swift.org/#Symbol"</span><span class="nt">/></span>
<span class="nt"></rdf:Description></span>
<span class="nt"><owl:Functional<wbr></wbr>Property</span> <span class="na">rdf:about=</span><span class="s">"http://www.swift.org/#returns"</span><span class="nt">></span>
<span class="nt"><rdfs:domain</span> <span class="na">rdf:resource=</span><span class="s">"http://www.swift.org/#Function"</span><span class="nt">/></span>
<span class="nt"><rdfs:range</span> <span class="na">rdf:resource=</span><span class="s">"http://www.swift.org/#Symbol"</span><span class="nt">/></span>
<span class="nt"></owl:Functional<wbr></wbr>Property></span>
<span class="nt"></rdf:RDF></span>
</code></pre>
</div>
<h3>
<a class="anchor" aria-hidden="true" id="parsing-code-declarations" href="#parsing-code-declarations"></a>Parsing Code Declarations</h3>
<p>Now consider the following Swift code:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Widget</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">foo</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Widget</span> <span class="p">{</span><span class="err"><var class="placeholder">…</var></span><span class="p">}</span>
<span class="kd">func</span> <span class="nf">bar</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Widget</span> <span class="p">{</span><span class="err"><var class="placeholder">…</var></span><span class="p">}</span>
</code></pre>
<p>We can use <a href="https://github.com/apple/swift-syntax" rel="noopener noreferrer">SwiftSyntax</a> to parse the code into an AST
and <a href="https://github.com/SwiftDocOrg/SwiftSemantics" rel="noopener noreferrer">SwiftSemantics</a> to convert those AST nodes
into a more convenient representation.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Swift<wbr></wbr>Syntax</span>
<span class="kd">import</span> <span class="kt">Swift<wbr></wbr>Semantics</span>
<span class="k">var</span> <span class="nv">collector</span> <span class="o">=</span> <span class="kt">Declaration<wbr></wbr>Collector</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">tree</span> <span class="o">=</span> <span class="k">try</span> <span class="kt">Syntax<wbr></wbr>Parser</span><span class="o">.</span><span class="nf">parse</span><span class="p">(</span><span class="nv">source</span><span class="p">:</span> <span class="n">source</span><span class="p">)</span>
<span class="n">collector</span><span class="o">.</span><span class="nf">walk</span><span class="p">(</span><span class="n">tree</span><span class="p">)</span>
<span class="n">collector</span><span class="o">.</span><span class="n">functions</span><span class="o">.</span><span class="n">first</span><span class="p">?</span><span class="o">.</span><span class="n">name</span> <span class="c1">// "foo()"</span>
<span class="n">collector</span><span class="o">.</span><span class="n">functions</span><span class="o">.</span><span class="n">first</span><span class="p">?</span><span class="o">.</span><span class="n">returns</span> <span class="c1">// "Widget"</span>
</code></pre>
<p>Combining this syntactic reading with information from compiler,
we can express facts about the code in the form of RDF triples.</p>
<div class="highlight-group">
<div role="tablist" aria-label="Languages">
<button role="tab" id="code-listing-2-json-ld-tab" class="json-ld" aria-label="Languages" aria-controls="code-listing-2-json-ld" aria-selected="true" tabindex="-1">
JSON-LD
</button>
<button role="tab" id="code-listing-2-n-triples-tab" class="n-triples" aria-label="Languages" aria-controls="code-listing-2-n-triples" aria-selected="false" tabindex="-1">
N-Triples
</button>
<button role="tab" id="code-listing-2-turtle-tab" class="turtle" aria-label="Languages" aria-controls="code-listing-2-turtle" aria-selected="false" tabindex="-1">
Turtle
</button>
</div>
<pre class="highlight" data-lang="JSON-LD" id="code-listing-2-json-ld" role="tabpanel" tabindex="0" aria-labelledby="code-listing-2-json-ld-tab"><code><span class="p">{</span><span class="w">
</span><span class="nl">"@context"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.swift.org/#name"</span><span class="p">,</span><span class="w">
</span><span class="nl">"@type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.w3.org/2001/XMLSchema#token"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"returns"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.swift.org/#returns"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"symbols"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"E83C6A28-1E68-406E-8162-D389A04DFB27"</span><span class="p">,</span><span class="w">
</span><span class="nl">"@type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.swift.org/#Structure"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Widget"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"4EAE3E8C-FD96-4664-B7F7-D64D8B75ECEB"</span><span class="p">,</span><span class="w">
</span><span class="nl">"@type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.swift.org/#Function"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"foo()"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="p">{</span><span class="w">
</span><span class="nl">"@id"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2D1F49FE-86DE-4715-BD59-FA70392E41BE"</span><span class="p">,</span><span class="w">
</span><span class="nl">"@type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"http://www.swift.org/#Function"</span><span class="p">,</span><span class="w">
</span><span class="nl">"name"</span><span class="p">:</span><span class="w"> </span><span class="s2">"bar()"</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
<pre class="highlight" data-lang="N-Triples" id="code-listing-2-n-triples" role="tabpanel" tabindex="0" aria-labelledby="code-listing-2-n-triples-tab" hidden="hidden"><code>_:E83C6A28-1E68-406E-8162-D389A04DFB27 <span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/1999/02/22</span><span class="na">-rdf-syntax-ns#type</span><span class="nt">></span> <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#Structure</span><span class="nt">></span> .
_:E83C6A28-1E68-406E-8162-D389A04DFB27 <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#name</span><span class="nt">></span> "Widget"^^<span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/2001/</span><span class="na">XMLSchema#token</span><span class="nt">></span> .
_:4EAE3E8C-FD96-4664-B7F7-D64D8B75ECEB <span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/1999/02/22</span><span class="na">-rdf-syntax-ns#type</span><span class="nt">></span> <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#Function</span><span class="nt">></span> .
_:4EAE3E8C-FD96-4664-B7F7-D64D8B75ECEB <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#name</span><span class="nt">></span> "foo()"^^<span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/2001/</span><span class="na">XMLSchema#token</span><span class="nt">></span> .
_:4EAE3E8C-FD96-4664-B7F7-D64D8B75ECEB <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#returns</span><span class="nt">></span> _:E83C6A28-1E68-406E-8162-D389A04DFB27 .
_:2D1F49FE-86DE-4715-BD59-FA70392E41BE <span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/1999/02/22</span><span class="na">-rdf-syntax-ns#type</span><span class="nt">></span> <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#Function</span><span class="nt">></span> .
_:2D1F49FE-86DE-4715-BD59-FA70392E41BE <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#name</span><span class="nt">></span> "bar()"^^<span class="nt"><http:</span><span class="err">//</span><span class="na">www.w3.org</span><span class="err">/2001/</span><span class="na">XMLSchema#token</span><span class="nt">></span> .
_:2D1F49FE-86DE-4715-BD59-FA70392E41BE <span class="nt"><http:</span><span class="err">//</span><span class="na">www.swift.org</span><span class="err">/</span><span class="na">#returns</span><span class="nt">></span> _:E83C6A28-1E68-406E-8162-D389A04DFB27 .
</code></pre>
<pre class="highlight" data-lang="Turtle" id="code-listing-2-turtle" role="tabpanel" tabindex="0" aria-labelledby="code-listing-2-turtle-tab" hidden="hidden"><code><span class="kd">@prefix</span><span class="w"> </span><span class="nn">swift:</span><span class="w"> </span><span class="nl"><http://www.swift.org/#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">owl:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2002/07/owl#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">rdf:</span><span class="w"> </span><span class="nl"><http://www.w3.org/1999/02/22-rdf-syntax-ns#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">rdfs:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2000/01/rdf-schema#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="kd">@prefix</span><span class="w"> </span><span class="nn">xsd:</span><span class="w"> </span><span class="nl"><http://www.w3.org/2001/XMLSchema#></span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">_:</span><span class="n">Widget</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">:</span><span class="n">Structure</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="n">name</span><span class="w"> </span><span class="s">"Widget"</span><span class="p">^^</span><span class="nn">xsd:</span><span class="n">token</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">_:</span><span class="n">foo</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">:</span><span class="n">Function</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="n">name</span><span class="w"> </span><span class="s">"foo()"</span><span class="p">^^</span><span class="nn">xsd:</span><span class="n">token</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="n">returns</span><span class="w"> </span><span class="nn">_:</span><span class="n">Widget</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nn">_:</span><span class="n">bar</span><span class="w"> </span><span class="nn">rdf:</span><span class="n">type</span><span class="w"> </span><span class="nn">:</span><span class="n">Function</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="n">name</span><span class="w"> </span><span class="s">"bar()"</span><span class="p">^^</span><span class="nn">xsd:</span><span class="n">token</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="n">returns</span><span class="w"> </span><span class="nn">_:</span><span class="n">Widget</span><span class="w"> </span><span class="p">.</span><span class="w">
</span></code></pre>
</div>
<p>Encoding our knowledge into a standard format
lets anyone access that information — however they like.
And because these facts are encoded within an ontology,
they can be validated for coherence and consistency.
It’s totally language agnostic.</p>
<h3>
<a class="anchor" aria-hidden="true" id="querying-the-results" href="#querying-the-results"></a>Querying the Results</h3>
<p>With an RDF graph of facts,
we can query it using <a href="https://en.wikipedia.org/wiki/SPARQL" rel="noopener noreferrer">SPARQL</a>.
Or,
we could load the information into
a graph database like <a href="https://neo4j.com" rel="noopener noreferrer">Neo4j</a> or
a relational database like <a href="https://postgres.app" rel="noopener noreferrer">PostgreSQL</a>
and perform the query in Cypher or SQL, respectively.</p>
<div class="highlight-group">
<div role="tablist" aria-label="Languages">
<button role="tab" id="code-listing-3-sparql-tab" class="sparql" aria-label="Languages" aria-controls="code-listing-3-sparql" aria-selected="true" tabindex="-1">
SPARQL
</button>
<button role="tab" id="code-listing-3-cypher-tab" class="cypher" aria-label="Languages" aria-controls="code-listing-3-cypher" aria-selected="false" tabindex="-1">
Cypher
</button>
<button role="tab" id="code-listing-3-sql-tab" class="sql" aria-label="Languages" aria-controls="code-listing-3-sql" aria-selected="false" tabindex="-1">
SQL
</button>
</div>
<pre class="highlight" data-lang="SPARQL" id="code-listing-3-sparql" role="tabpanel" tabindex="0" aria-labelledby="code-listing-3-sparql-tab"><code><span class="k">PREFIX</span><span class="w">
</span><span class="nn">swift:</span><span class="w"> </span><span class="nn"><http://www.swift.org/#></span><span class="w">
</span><span class="k">SELECT</span><span class="w"> </span><span class="nv">?function</span><span class="w"> </span><span class="nv">?name</span><span class="w">
</span><span class="k">WHERE</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">?function</span><span class="w"> </span><span class="k">a</span><span class="w"> </span><span class="nn">swift:</span><span class="ss">Function</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="ss">returns</span><span class="w"> </span><span class="nv">?type</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="ss">name</span><span class="w"> </span><span class="nv">?name</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nv">?type</span><span class="w"> </span><span class="nn">swift:</span><span class="ss">name</span><span class="w"> </span><span class="s2">"Widget"</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="nv">?function</span><span class="w">
</span></code></pre>
<pre class="highlight" data-lang="Cypher" id="code-listing-3-cypher" role="tabpanel" tabindex="0" aria-labelledby="code-listing-3-cypher-tab" hidden="hidden"><code><span class="k">MATCH</span><span class="w"> </span><span class="ss">(</span><span class="py">function:</span><span class="n">Function</span><span class="ss">)</span><span class="o">-</span><span class="ss">[</span><span class="nc">:RETURNS</span><span class="ss">]</span><span class="o">-></span><span class="ss">(</span><span class="py">symbol:</span><span class="n">Symbol</span> <span class="ss">{</span><span class="py">name:</span> <span class="s1">'Widget'</span><span class="ss">})</span>
<span class="k">RETURN</span> <span class="n">function</span>
</code></pre>
<pre class="highlight" data-lang="SQL" id="code-listing-3-sql" role="tabpanel" tabindex="0" aria-labelledby="code-listing-3-sql-tab" hidden="hidden"><code><span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">symbols</span> <span class="p">(</span>
<span class="n">id</span> <span class="n">UUID</span> <span class="k">PRIMARY</span> <span class="k">KEY</span><span class="p">,</span>
<span class="n">name</span> <span class="nb">TEXT</span><span class="p">,</span>
<span class="p">);</span>
<span class="k">CREATE</span> <span class="k">TABLE</span> <span class="n">functions</span> <span class="p">(</span>
<span class="n">returns_id</span> <span class="n">UUID</span> <span class="k">REFERENCES</span> <span class="n">symbols</span><span class="p">(</span><span class="n">id</span><span class="p">),</span>
<span class="p">)</span> <span class="k">INHERITS</span> <span class="p">(</span><span class="n">symbols</span><span class="p">);</span>
<span class="c1">--</span>
<span class="k">SELECT</span> <span class="n">f</span><span class="p">.</span><span class="n">id</span><span class="p">,</span> <span class="n">f</span><span class="p">.</span><span class="n">name</span>
<span class="k">FROM</span> <span class="n">functions</span> <span class="n">f</span>
<span class="k">INNER</span> <span class="k">JOIN</span> <span class="n">symbols</span> <span class="n">s</span> <span class="k">USING</span> <span class="p">(</span><span class="n">returns_id</span><span class="p">);</span>
<span class="k">WHERE</span> <span class="n">s</span><span class="p">.</span><span class="n">name</span> <span class="o">=</span> <span class="s1">'Widget'</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">name</span>
</code></pre>
</div>
<p>Whichever route we take,
we get the same results:</p>
<table>
<thead>
<tr>
<th>id</th>
<th>name</th>
</tr>
</thead>
<tbody>
<tr>
<td>4EAE3E8C-FD96-4664-B7F7-D64D8B75ECEB</td>
<td>foo()</td>
</tr>
<tr>
<td>2D1F49FE-86DE-4715-BD59-FA70392E41BE</td>
<td>bar()</td>
</tr>
</tbody>
</table>
<aside class="admonition info">
<p>The semantic web suffers from an admittedly weak software ecosystem.
While there are dozens of excellent clients for SQL databases,
you’d be hard-pressed to find much for SPARQL.
So I was quite pleased to come across
<a href="https://github.com/paulovn/sparql-kernel" rel="noopener noreferrer">this kernel</a>
by Paulo Villegas
that adds SPARQL support to
<a href="https://jupyter.org" rel="noopener noreferrer">Jupyter notebooks</a>.</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="answering-questions-about-your-code" href="#answering-questions-about-your-code"></a>Answering Questions About Your Code</h3>
<p><em>“What can you do with a knowledge graph?”</em>
That’s kind of like asking, <em>“What can you do with Swift?”</em>
The answer — <em>“Pretty much anything”</em> — is as true as it is unhelpful.</p>
<p>Perhaps a better framing would be to consider the kinds of questions that
a knowledge graph of code symbols can help answer:</p>
<ul>
<li>Which methods in Foundation produce a <code>Date</code> value?</li>
<li>Which public types in my project <em>don’t</em> conform to <code>Codable</code>?</li>
<li>Which methods does <code>Array</code> inherit default implementations from <code>Random<wbr></wbr>Access<wbr></wbr>Collection</code>?</li>
<li>Which APIs have documentation that includes example code?</li>
<li>What are the most important APIs in <code>Map<wbr></wbr>Kit</code>?</li>
<li>Are there any unused APIs in my project?</li>
<li>What’s the oldest version of iOS that my app could target
based on my current API usage?</li>
<li>What APIs were added to <a href="https://github.com/Alamofire/Alamofire" rel="noopener noreferrer">Alamofire</a> between versions 4.0 and 4.2?</li>
<li>What APIs in our app are affected by a CVE issued for a 3rd-party dependency?</li>
</ul>
<p>The possibilities get even more interesting as you layer additional contexts
by linking Swift APIs to different domains and other programming languages:</p>
<ul>
<li>How is this Swift API exposed in Objective-C?</li>
<li>Who are the developers maintaining the packages
that are pulled in as external dependencies for this project?</li>
<li>What’s the closest functional equivalent to this Swift package
that’s written in Rust?</li>
</ul>
<aside class="admonition info">
<p>My pitch for a
<a href="https://forums.swift.org/t/swift-package-registry-service/37219/2" rel="noopener noreferrer">Swift Package Registry Service</a>
proposes the use of <a href="https://en.wikipedia.org/wiki/JSON-LD" rel="noopener noreferrer">JSON-LD</a> and the
<a href="https://schema.org/SoftwareSourceCode" rel="noopener noreferrer">Schema.org <code>Software<wbr></wbr>Source<wbr></wbr>Code</code></a> vocabulary
as a standard representation for package metadata,
which could be easily combined with and cross-referenced against
semantic representations of code.</p>
</aside>
<h2>
<a class="anchor" aria-hidden="true" id="future-applications-the-promise-of-what-lies-ahead" href="#future-applications-the-promise-of-what-lies-ahead"></a><small>Future Applications</small> The Promise of What Lies Ahead</h2>
<blockquote>
<p>Any fact becomes important when it’s connected to another.</p>
<p><cite>Umberto Eco, <em>Foucault’s Pendulum</em></cite></p>
</blockquote>
<p>Operating on code symbolically is more powerful
than treating it as text.
Once you’ve experienced proper refactoring tools,
you’ll never want to go back to global find-and-replace.</p>
<p>The leap from symbolic to semantic understanding of code
promises to be just as powerful.
What follows are a few examples of potential applications of
the knowledge graph we’ve described.</p>
<h3>
<a class="anchor" aria-hidden="true" id="flexible-search-queries" href="#flexible-search-queries"></a>Flexible Search Queries</h3>
<p>GitHub’s <a href="https://github.com/search/advanced" rel="noopener noreferrer">advanced search</a>
provides an interface to filter results on various
<a href="https://www.elastic.co/guide/en/app-search/current/facets-guide.html" rel="noopener noreferrer">facets</a>,
but they’re limited to metadata about the projects.
You can search for Swift code written by
<a href="https://github.com/kateinoigakukun" rel="noopener noreferrer"><code>@kateinoigakukun</code></a> in 2020,
but you can’t, for example,
filter for code compatible with Swift 5.1.
You can search code for the string “record”,
but you can’t disambiguate between type and function definitions
(<code>class Record</code> vs. <code>func record()</code>).</p>
<p>As we showed earlier,
the kinds of queries we can perform across a knowledge graph
are fundamentally different from what’s possible with
a conventional faceted, full-text search index.</p>
<p>For example,
here’s a SPARQL query to find the urls of repositories
created by <code>@kateinoigakukun</code> and updated this year
that contain Swift functions named <code>record</code>:</p>
<pre class="highlight" data-lang="SPARQL"><code><span class="k">PREFIX</span><span class="w">
</span><span class="nn">swift:</span><span class="w"> </span><span class="nn"><http://www.swift.org/#></span><span class="w">
</span><span class="nn">skos:</span><span class="w"> </span><span class="nn"><http://www.w3.org/2004/02/skos/core/#></span><span class="w">
</span><span class="nn">sdo:</span><span class="w"> </span><span class="nn"><http://schema.org/#></span><span class="w">
</span><span class="k">SELECT</span><span class="w"> </span><span class="nv">?url</span><span class="w">
</span><span class="k">WHERE</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nv">?function</span><span class="w"> </span><span class="k">a</span><span class="w"> </span><span class="nn">swift:</span><span class="ss">Function</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">swift:</span><span class="ss">name</span><span class="w"> </span><span class="s2">"record"</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">skos:</span><span class="ss">member</span><span class="w"> </span><span class="nv">?repository</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nv">?repository</span><span class="w"> </span><span class="k">a</span><span class="w"> </span><span class="nn">sdo:</span><span class="ss">Software<wbr></wbr>Source<wbr></wbr>Code</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">sdo:</span><span class="ss">contributor</span><span class="w"> </span><span class="nv">?contributor</span><span class="p">;</span><span class="w">
</span><span class="nn">sdo:</span><span class="ss">url</span><span class="w"> </span><span class="nv">?url</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">sdo:</span><span class="ss">date<wbr></wbr>Modified</span><span class="w"> </span><span class="nv">?date</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="nv">?contributor</span><span class="w"> </span><span class="k">a</span><span class="w"> </span><span class="nn">sdo:</span><span class="ss">Person</span><span class="w"> </span><span class="p">;</span><span class="w">
</span><span class="nn">sdo:</span><span class="ss">username</span><span class="w"> </span><span class="s2">"kateinoigakukun"</span><span class="w"> </span><span class="p">.</span><span class="w">
</span><span class="k">FILTER</span><span class="w"> </span><span class="p">(</span><span class="nv">?date</span><span class="w"> </span><span class="o">></span><span class="p">=</span><span class="w"> </span><span class="s2">"2020-01-01"</span><span class="p">)</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="k">ORDER</span><span class="w"> </span><span class="k">BY</span><span class="w"> </span><span class="nv">?url</span><span class="w">
</span></code></pre>
<aside class="admonition info">
<p>Looking for a more grounded example of semantic code search?
Check out <a href="https://hoogle.haskell.org" rel="noopener noreferrer">Hoogle</a>:
a Haskell API search engine
that lets you search for functions by approximate type signature.
For instance, you can search for
<a href="https://hoogle.haskell.org/?hoogle=Ord%20a%20%3D%3E%20%5Ba%5D%20-%3E%20%5Ba%5D" rel="noopener noreferrer"><code>Ord a => [a] -> [a]</code></a>,
(roughly, <code>([T]) -> [T] where T: Comparable</code> in Swift)
to find various <code>sort</code> methods available in the ecosystem.</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="linked-documentation" href="#linked-documentation"></a>Linked Documentation</h3>
<p>When faced with
<a href="https://nooverviewavailable.com" rel="noopener noreferrer">missing or incomplete documentation</a>,
developers are left to search Google for
blog posts, tutorials, conference videos, and sample code
to fill in the gaps.
Often, this means sifting through pages of irrelevant results —
to say nothing of outdated and incorrect information.</p>
<p>A knowledge graph can improve search for documentation
much the same as it can for code,
but we can go even further.
Similar to how academic papers contain citations,
example code can be annotated to include references to
the canonical APIs it interacts with.
Strong connections between references and its source material
make for easy retrieval later on.</p>
<p>Imagine if,
when you option-click on an API in Xcode
to get its documentation,
you also saw a list of sample code and WWDC session videos?
Or what if we could generate sample code automatically from test cases?
Wouldn’t that be nice?</p>
<p>All of that information is out there,
just waiting for us to connect the dots.</p>
<h3>
<a class="anchor" aria-hidden="true" id="automatic-dependencies" href="#automatic-dependencies"></a>Automatic µDependencies</h3>
<p>John D. Cook once
<a href="https://www.johndcook.com/blog/2011/02/03/lego-blocks-and-organ-transplants/" rel="noopener noreferrer">observed</a>,
code reuse is more like an organ transplant
than snapping LEGO blocks together.
Fred Brooks similarly analogized software developers to surgeons in
<a href="https://en.wikipedia.org/wiki/The_Mythical_Man-Month" rel="noopener noreferrer"><em>The Mythical Man-Month</em></a>.</p>
<p>But that’s not to say that things can’t get better —
it’d be hard to argue that they haven’t.</p>
<p>Web applications were once described in similar, organic terms,
but that came to an end with the advent of
<a href="https://en.wikipedia.org/wiki/OS-level_virtualization" rel="noopener noreferrer">containerization</a>.
Now you can orchestrate entire multi-cloud deployments automatically
via declarative configuration files.</p>
<p>Before <abbr title="Comprehensive Perl Archive Network"><a href="https://www.cpan.org/" rel="noopener noreferrer">CPAN</a></abbr>,
the state of the art for dependency management
was copy-pasting chunks of code
<a href="https://en.wikipedia.org/wiki/Matt%27s_Script_Archive" rel="noopener noreferrer">you found on a web page</a>.
But today, package managers are essential infrastructure for projects.</p>
<hr>
<p>What if,
instead of organizing code into self-contained, modular chunks ourselves,
we let software do it for us?
Call it
<abbr title="Functions as a Dependency">FaaD</abbr> (Functions as a Dependency).</p>
<p>Say you want an implementation of
<a href="https://en.wikipedia.org/wiki/K-means_clustering" rel="noopener noreferrer"><em>k</em>-means clustering</a>.
You might search around for “k-means” or “clustering” on GitHub
and find a package named “SwiftyClusterAlgorithms” (😒),
only to discover that it includes a bunch of functionality that you don’t need —
and to add insult to injury,
some of those extra bits happen to generate compiler warnings.
Super annoying.</p>
<aside class="parenthetical">
<p>For the record,
<a href="https://github.com/NSHipster/DBSCAN" rel="noopener noreferrer"><abbr title="Density-Based Spatial Clustering of Applications with Noise">DBSCAN</abbr></a>
is way better than <em>k</em>-means for most distributions.</p>
</aside>
<p>Today, there’s no automatic way to pick and choose what you need.
(<a href="/import/">Swift <code>import</code> syntax</a> (<code>import func k<wbr></wbr>Means</code>) is a lie)
But there’s no inherent reason why the compiler couldn’t do this for you.</p>
<p>Or to go even further:
If everything compiles down to <a href="https://swiftwasm.org" rel="noopener noreferrer">web assembly</a>,
there’s no inherent requirement for that implementation of <em>k</em>-means —
it could be written in Rust or JavaScript,
and you’d be none the wiser.</p>
<p>At a certain point,
you start to question the inherent necessity of software packaging
as we know it today.
Take it far enough,
and you may wonder how much code we’ll write ourselves in the future.</p>
<h3>
<a class="anchor" aria-hidden="true" id="code-generation" href="#code-generation"></a>Code Generation</h3>
<p>A few months ago,
Microsoft hosted its <a href="https://mybuild.microsoft.com" rel="noopener noreferrer">Build</a> conference.
And among the videos presented was an interview with
<a href="https://en.wikipedia.org/wiki/Sam_Altman" rel="noopener noreferrer">Sam Altman</a>,
CEO of <a href="https://openai.com/" rel="noopener noreferrer">OpenAI</a>.
A few minutes in,
the interview cut to a video of Sam using
a fine-tuned version of
<a href="https://openai.com/blog/gpt-2-1-5b-release/" rel="noopener noreferrer">GPT-2</a>
to
<a href="https://www.pscp.tv/Microsoft/1OyKAYWPRrWKb?t=27m1s" rel="noopener noreferrer">write Python code from docstrings</a>.</p>
<pre class="highlight" data-lang="Python"><code><span class="k">def</span> <span class="nf">is_palindrome</span><span class="p">(</span><span class="n">s</span><span class="p">):</span>
<span class="s">"""Check whether a string is a palindrome"""</span>
<span class="k">return</span> <span class="n">s</span> <span class="o">==</span> <span class="n">s</span><span class="p">[::</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="c1"># ← Generated by AI model from docstring!
</span></code></pre>
<p>And that’s using a model that treats code as text.
Imagine how far you could go with <em>a priori</em> knowledge of programming languages!
Unlike English, the rules of code are, well, codified.
You can check to see if code compiles —
and if it does compile,
you can run it to see the results.</p>
<aside class="admonition info">
<p>And that’s GPT-2.
<a href="https://www.gwern.net/GPT-3" rel="noopener noreferrer">GPT-3</a> is even more impressive.
For your consideration,
here’s what the model generated
when prompted to write a parody of the
<a href="https://knowyourmeme.com/memes/navy-seal-copypasta" rel="noopener noreferrer">Navy Seal copypasta meme</a>
relating to
<a href="https://en.wikipedia.org/wiki/Philosophy_of_mathematics#Platonism" rel="noopener noreferrer">mathematical platonism</a>:</p>
<blockquote>
<p>What in set theory did you just write about me,
you ignorant little inductivist?
I’ll have you know I am a professor at the University of Chicago
and I have been involved in numerous secret raids on the office of Quine,
and I have over 300 confirmed set theoreticians. […]</p>
</blockquote>
</aside>
<p>At this point,
you should feel either very worried or very excited. <br>
If you don’t, then you’re not paying attention.</p>
<h2>
<a class="anchor" aria-hidden="true" id="taking-ideas-seriously-the-shoemakers-children" href="#taking-ideas-seriously-the-shoemakers-children"></a><small>Taking Ideas Seriously</small> The Shoemaker’s Children</h2>
<blockquote>
<p>The use of <abbr>FORTRAN</abbr>,
like the earlier symbolic programming,
was very slow to be taken up by the professionals.
And this is typical of almost all professional groups.
Doctors clearly do not follow the advice they give to others,
and they also have a high proportion of drug addicts.
Lawyers often do not leave decent wills when they die.
Almost all professionals are slow to use their own expertise for their own work.
The situation is nicely summarized by the old saying,
“The shoe maker’s children go without shoes”.
Consider how in the future, when you are a great expert,
you will avoid this typical error!</p>
<p><cite>Richard W. Hamming, <a href="https://press.stripe.com/#the-art-of-doing-science-and-engineering" rel="noopener noreferrer"><em>“The Art of Doing Science and Engineering”</em></a></cite></p>
</blockquote>
<p>Today,
lawyers delegate many paralegal tasks like document discovery to computers
and
doctors routinely use machine learning models to help diagnose patients.</p>
<p>So why aren’t we —
<em>ostensibly the people writing software</em> —
doing more with AI in our day-to-day?
Why are things like
<a href="https://www.tabnine.com" rel="noopener noreferrer">TabNine</a> and
<a href="https://kite.com" rel="noopener noreferrer">Kite</a>
so often seen as curiosities instead of game-changers?</p>
<p>If you take seriously the idea that
<abbr title="artificial intelligence">AI</abbr>
will fundamentally change the nature of many occupations in the coming decade,
what reason do you have to believe that you’ll be immune from that
because you work in software?
Looking at the code you’ve been paid to write over the past few years,
how much of that can you honestly say is truly novel?</p>
<p>We’re really not as clever as we think we are.</p>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="postscript-reflection-and-metaprogramming" href="#postscript-reflection-and-metaprogramming"></a><small>Postscript</small> Reflection and Metaprogramming</h2>
<p>Today marks 8 years since I started NSHipster.</p>
<p>You might’ve noticed that I don’t write here as much as I once did.
And on the occasions that I do publish an article,
it’s more likely to include obscure
<a href="/swift-log/">historical facts</a> and
<a href="/timeinterval-date-dateinterval/">cultural references</a>
than to the <a href="/cfbag/">obscure APIs</a> promised by this blog’s tagline.</p>
<p>A few weeks out now from <a href="/wwdc-2020">WWDC</a>,
I <em>should</em> be writing about
<a href="https://developer.apple.com/documentation/devicecheck/dcappattestservice" rel="noopener noreferrer"><code>DCApp<wbr></wbr>Attest<wbr></wbr>Service</code></a>,
<a href="https://developer.apple.com/documentation/storekittest/sktestsession" rel="noopener noreferrer"><code>SKTest<wbr></wbr>Session</code></a>,
SwiftUI <a href="https://developer.apple.com/documentation/swiftui/namespace" rel="noopener noreferrer"><code>Namespace</code></a>
and
<a href="https://developer.apple.com/documentation/uniformtypeidentifiers/uttype" rel="noopener noreferrer"><code>UTType</code></a>.
But here we are,
at the end of an article about the semantic web, of all things…</p>
<hr>
<p>The truth is,
I’ve come around to thinking that
programming isn’t the most important thing
for programmers to pay attention to right now.</p>
<hr>
<p>Anyway,
I’d like to take this opportunity to extend my sincere gratitude
to everyone who reads the words I write.
Thank you.
It may be a while before I get back into a regular cadence,
so apologies in advance.</p>
<p>Until next time,
<em>May your code continue to compile and inspire.</em></p>
<link rel="stylesheet" type="text/css" href="/assets/articles/as-we-may-code-a97159d31c2433baae69c5a7df23d0ee88baafddda1583f6b487850b17c4e6596b831fefad9428fb2b5dda11eb3a98fc8d68809c3ac3f7706f6bf584503ff294.css" integrity="sha512-qXFZ0xwkM7quacWn3yPQ7oi6r93aFYP2tIeFCxfE5llrgx/vrZQo+ytd2hHrOpj8jWiAnDrD93Bva/WEUD/ylA==" crossorigin="anonymous">
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>What if, instead of lowering source code down for the purpose of execution, we raised it for the purpose of understanding?</p>WWDC 20202020-06-26T00:00:00-07:002020-06-26T00:00:00-07:00https://nshipster.com/wwdc-2020
<p>Like everything else in 2020,
this year’s WWDC had to be a little different
if it was going to happen at all.</p>
<p>When Apple first announced that the conference would be fully remote,
nobody knew what that would look like, exactly.
What parts of the dubdub experience would be kept in this new format?
What details would be lost in translation?
Could they actually pull it off?</p>
<aside class="admonition info">
<p>For context:
Apple live-streamed its first keynote in 2013,
and technical sessions in 2015.
Attendees of <a href="http://bslabs.net/2018/05/28/wwdc-1997-videos/" rel="noopener noreferrer">WWDC 1997</a> could obtain a collection of CDs
with video recordings of sessions —
a far cry from the VHS tape for <a href="http://bslabs.net/2020/06/19/wwdc-1990/" rel="noopener noreferrer">WWDC 1990</a>.</p>
</aside>
<p>As it turns out,
going fully remote wasn’t merely good enough —
it was, in many ways, superior to the original thing.
There’s a lot to like about the new format.</p>
<p>The videos are well-produced,
and let each presenter’s personality really shine.
Everybody looks and sounds great.</p>
<p>Sessions are tight and well-paced.
Rather than stretching or cramming content into a fixed time slot,
they’re as long as they need to be.
And thanks to this more digestible format,
we’re starting to see WWDC clips being shared around,
which is new and refreshing.</p>
<p>To be honest,
it’s hard to imagine ever going back to a physical conference.</p>
<p>However,
as someone who had the privilege of attending WWDC in years past,
there are things I’m going to miss
(and some that I decidedly won’t).</p>
<table>
<thead>
<tr>
<th>🥰</th>
<th>😫</th>
</tr>
</thead>
<tbody>
<tr>
<td>Refrigerators stocked with Odwalla smoothies</td>
<td>Trying to download the latest Xcode beta over hotel internet</td>
</tr>
<tr>
<td>Lunchtime sessions</td>
<td>Eating lunch at or around Moscone</td>
</tr>
<tr>
<td>WWDC track jackets saving the lives of first-time attendees from the cold of San Francisco summer</td>
<td>Being in San Francisco, generally</td>
</tr>
<tr>
<td>Eating burritos on the terrace of McEnery Convention Center during WWDC check-in</td>
<td>Being in San Jose, generally</td>
</tr>
<tr>
<td>Guessing who would be playing at Bash this year</td>
<td>Hearing the same handful of songs on repeat before and after every session
(<a href="https://music.apple.com/us/album/animal/1471689800?i=1471689803" rel="noopener noreferrer">this song</a> in particular) </td>
</tr>
<tr>
<td colspan="2">
<details>
<summary>Watching Apple executives dance at Bash</summary>
<video preload="none" width="636" height="290" controls>
<source src="/assets/wwdc-2020-apple-executives-dancing-0c9034cf315cc9c4db419df4f1320c78b4711b10bd537eb8654aa3a1b4b93a9e364eb4967f4d20ad5ff5ccdea013421d86a0d515914c373ec3f5a99e5701f7a2.mp4" type="video/mp4"></source>
</video>
</details>
</td>
</tr>
<tr>
<td>Talking to people as you wait in line for the keynote on Monday morning</td>
<td>Waking up late and having to settle for watching from the overflow room</td>
</tr>
<tr>
<td>Leaving at the end of the week with a mix of hope, fear, and inspiration <sup>*</sup>
</td>
<td>Being sick for the next week with dubdub flu</td>
</tr>
</tbody>
</table>
<p><sup>*</sup> I’d like to hold on this last point for a moment.</p>
<p><br></p>
<p>In the <em>Before Times</em>,
many of us traveled far from home to attend WWDC.
There was a physical and temporal delineation
between life before, during, and after the conference.
Flying out of <abbr>SFO</abbr>, <abbr>SJC</abbr>, or <abbr>OAK</abbr>,
you escaped Apple’s <a href="https://www.folklore.org/StoryView.py?story=Reality_Distortion_Field.txt" rel="noopener noreferrer">“reality distortion field”</a>
and its surrounding echo chamber.
You returned to your normal life.</p>
<p>This year? Not so much.</p>
<p>WWDC 2020 was just another week in this bizarre existence amidst this pandemic.
Not only is there no escape from the “reality distortion field”,
there isn’t even a “normal life” for us to leave or return to.</p>
<p>So here we are,
filled with anxious excitement and fear;
our corporeal forms replaced by
Memoji floating in a black, digital void
lit only by the screens of our soon-to-be-obsolete MacBooks Pro.</p>
<p><img src="/assets/wwdc-2020-banner-236757637b3c0e31a0145cd70875e03b7fe33f91408dc67975392ea98e42454eebf13eb27c163de42d089b0694a7fccbde6da0b9230858e6ccc46282e51cbf90.jpg" integrity="sha512-I2dXY3s8DjGgFFzXCHXgO3/jP5FAjcZ5dTkuqY5CRU7r8T6yfBY95C0ImwaUp/zL3m2guSMIWObMxGKC5Ry/kA==" crossorigin="anonymous" alt=""></p>
<hr><a id="get-on-with-it"></a>
<h2>
<a class="anchor" aria-hidden="true" id="excitement" href="#excitement"></a>Excitement</h2>
<p>I don’t have a real sense of how everything went over this year.
There wasn’t any applause (or heckling) at this year’s keynote
to gauge the temperature in the room.
There were no parties to overhear shop talk and hot takes.
There was no line for lunch
to make small talk with a fellow attendee.</p>
<p>But if <a href="https://twitter.com/hashtag/WWDC20" rel="noopener noreferrer">Twitter</a> is anything to go on,
my overall impression is that everyone is really <em>excited</em>.</p>
<p>Which is fine. I get it.</p>
<p>But it should come as no surprise that things announced at WWDC are exciting —
that’s the whole point of having a developer conference in the first place.
Apple has the best marketing in the world,
and WWDC is Apple’s way of marketing to us.</p>
<p>Here’s the thing about excitement:
It’s kryptonite to developers.</p>
<p>Excitement messes with our ability to focus on one thing,
which is already a big struggle for a lot of us (myself included).
When you’re excited,
it’s almost impossible to get anything done.</p>
<p>There are plenty of voices in the community who are echoing this excitement.
I can’t add anything to that discussion.
And besides,
that’s not really where my head’s at right now.</p>
<h3>
<a class="anchor" aria-hidden="true" id="trivial-pursuit" href="#trivial-pursuit"></a>Trivial Pursuit</h3>
<p>I briefly considered reviving the <a href="/nshipster-quiz-2/">NSHipster Quiz</a>
for WWDC 2020,
but it didn’t feel right.
With everything going on in the world,
Apple trivia just isn’t where my head or heart are right now.</p>
<p>To give you a sense of what I mean, here’s what I had for Round 3,
whose theme was inspired by <a href="https://www.cs.virginia.edu/~robins/YouAndYourResearch.html" rel="noopener noreferrer">Richard Hamming</a>:</p>
<dl>
<dt><strong>Question 1.</strong></dt>
<dd>What are the important problems of your field?</dd>
<dt><strong>Question 2.</strong></dt>
<dd>What important problems are you working on?</dd>
<dt><strong>Question 3.</strong></dt>
<dd>If what you are doing is not important,
why are working on it?</dd>
</dl>
<aside class="parenthetical">
<p>I think I made the right call by not doing a quiz this year.</p>
</aside>
<h2>
<a class="anchor" aria-hidden="true" id="temperance" href="#temperance"></a>Temperance</h2>
<p>If you’re serious about solving a problem,
you owe it to yourself to temper any excitement
that distracts you from making real progress.</p>
<p>In last year’s write-up for <a href="/wwdc-2019/">WWDC 2019</a>,
I concluded with the following,
as a counterpoint to the conference’s theme of <code>#mindblown</code> 🤯:</p>
<blockquote>
<p>Taking care of yourself —
sleeping enough, eating right, exercising regularly —
will do more to improve your productivity
than any language or framework out there.
Your ability to communicate and collaborate with others
will always be a better predictor of success
than your choice of technology stack.
Your relationships with others
are the most significant factors of success and happiness in life.</p>
</blockquote>
<p>I stand by this advice, boring as it may be.</p>
<p>It’s been an exciting week,
so take a moment to collect yourself.
Go on a walk. Take a hike. (Be safe about it.)
Do whatever you need to break free of the “reality distortion field”.
Once you do, you’ll have the necessary distance to determine
what new technologies you should pay attention to
and what you can ignore for now.</p>
<p>We have a lot of work ahead of us.</p>
<script src="/assets/articles/wwdc-2020-94bd3c6f2273e24e8a0b33b2d45588e317f33058150a9c34d909ae205d4446df32b33fc141116541e0c58d114193b305c31e3f7eb87a91e8c5bd36b825702bfa.js" integrity="sha512-lL08byJz4k6KCzOy1FWI4xfzMFgVCpw02QmuIF1ERt8ysz/BQRFlQeDFjRFBk7MFwx4/frh6kejFvTa4JXAr+g==" crossorigin="anonymous" type="text/javascript"></script>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>A brief remark about the excitement of Apple’s annual developer conference.</p>Language Server Protocol2018-11-05T00:00:00-08:002020-05-07T00:00:00-07:00https://nshipster.com/language-server-protocol
<p>In October 2018,
Apple <a href="https://forums.swift.org/t/new-lsp-language-service-supporting-swift-and-c-family-languages-for-any-editor-and-platform/17024" rel="noopener noreferrer">announced on the Swift.org forums</a>
that it was starting work to adopt
the <a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer">Language Server Protocol</a>
(<abbr title="Language Server Protocol">LSP</abbr>)
for Swift and C languages.</p>
<blockquote>
<p>At Apple we are making it a priority
to support high-quality tooling for all Swift developers,
including those working on non-Apple platforms.
We want to collaborate with the open-source community
and focus our efforts on building common infrastructure
that can be shared by Xcode and other editors and platforms.
To that end, [ … ] we’ve chosen to adopt LSP.</p>
<p><cite>Argyrios Kyrtzidis, October 15<sup>th</sup>, 2018</cite></p>
</blockquote>
<p><strong>This is arguably the most important decision Apple has made for Swift
since releasing the language as open source in 2014.</strong>
It’s a big deal for app developers,
and it’s an even bigger deal for Swift developers on other platforms.</p>
<p>To understand why,
this week’s article will take a look at
what problem the Language Server Protocol solves,
how it works,
and what its long-term impacts may be.</p>
<aside class="admonition info">
<p><strong>Update</strong>:
GitHub recently announced
<a href="https://github.com/features/codespaces/" rel="noopener noreferrer">Codespaces</a>,
an upcoming feature that promises
<em>“the full Visual Studio Code experience without leaving GitHub”</em>.
Thanks to Swift’s support for LSP,
we’ll soon be able to edit Swift code —
syntax highlighting, autocompletion, and all —
directly from the browser.</p>
<p>Why wait for the
<a href="https://twitter.com/jon_prosser/status/1252187152831692800" rel="noopener noreferrer">rumored</a>
announcement of Xcode for iPad at <a href="https://developer.apple.com/wwdc20/" rel="noopener noreferrer">WWDC</a>?
Codespaces turns any iPad into a
<a href="https://twitter.com/notdetails/status/1258120708212785154" rel="noopener noreferrer">full-fledged development environment</a>!</p>
</aside>
<hr><a id="get-on-with-it"></a>
<p>Imagine a grid
with each row representing a different programming language
(Swift, JavaScript, Ruby, Python, etc.)
and each column representing a different code editor
(Xcode, Visual Studio, Vim, Atom, etc.),
such that each cell represents
the level of support that a particular editor has for a language.</p>
<p><img src="/assets/lsp-languages-times-editors-e30cf1a62ea5dbad8145723e17e8a17716f325e58fa543c559c5e6d8c25487dd56a1f8a0e0a67299c6927fb4f097dc0f8f803aa90891454f8e9aa1a92386f992.svg" integrity="sha512-4wzxpi6l262BRXI+F+ihdxbzJeWPpUPFWcXm2MJUh91Wofig4KZymcaSf7Twl9wPj4A6qQiRRU+OmqGpI4b5kg==" crossorigin="anonymous" role="img" alt=""></p>
<p>Up until recently,
what you’d find was a patchwork of compatibility
across the various combinations.
Some editors offered deep integration with a few languages
and little to no support for anything else,
whereas other editors aimed to be general-purpose
with at least a modicum of support for many languages.
(The term <abbr title="Integrated Development Environment">IDE</abbr>
is often used to describe the former.)</p>
<p>Case in point:
<em>You’d be stubborn not to use Xcode for app development
and foolish to use it for anything else.</em></p>
<p>For an editor to have better support for a particular language,
it needs to write integration code —
either directly in the code base or via a plugin system.
Due to implementation differences across languages and editors,
improvements to, say,
Ruby support in Vim
wouldn’t translate into better support for Python,
nor could they be applied to make Ruby work better in Atom.
The end result: inconsistent support across technologies
and a lot of wasted effort.</p>
<p>The situation we described
is often referred to as an <dfn>M × N problem</dfn>,
where the number of integrations is the <em>product</em> of
<code>M</code> editors and <code>N</code> languages.
What the Language Server Protocol does is change this M × N problem
into a <dfn>M + N problem</dfn>.</p>
<p>Rather than an editor having to implement support for each language,
it only needs to support the LSP.
And in doing so, it gets the same level of functionality
for all languages that support the LSP.</p>
<p><img src="/assets/lsp-languages-plus-editors-0bfe50ed918be033d10d4837c90d2f697a56395950188acbdccdde68f42d67f126828a695fce31b50f41fb92ddbd991422f93bee447e97c5f9214531c2e78089.svg" integrity="sha512-C/5Q7ZGL4DPRDUg3yQ0vaXpWOVlQGIrL3M3eaPQtZ/EmgoppX84xtQ9B+5LdvZkUIvk77kR+l8X5IUUxwueAiQ==" crossorigin="anonymous" role="img" alt=""></p>
<aside class="admonition info">
<p>An essay from 2010 by Tomohiro Matsuyama
entitled <a href="https://tkf.github.io/2013/06/04/Emacs-is-dead.html" rel="noopener noreferrer">“Emacs は死んだ” (<em>“Emacs is Dead”</em>)</a>
offers a nice encapsulation of this problem.
Describing the limitations of Emacs’ scripting language
(no multi-threading, few low-level APIs, and a small user base)
Matsuyama argues that the preferred approach to writing a plugin
should be to interface with an external program
rather than implement something natively.</p>
</aside>
<p>Language Server Protocol provides a common set of functionality
for supported languages, including:</p>
<ul>
<li>Syntax Highlighting</li>
<li>Automatic Formatting</li>
<li>Autocomplete</li>
<li>Syntax</li>
<li>Tooltips</li>
<li>Inline Diagnostics</li>
<li>Jump to Definition</li>
<li>Find References in Project</li>
<li>Advanced Text and Symbol Search</li>
</ul>
<p>Rather than reinventing the wheel for each new technology,
tools and editors can invest in better usability
and more advanced functionality.</p>
<h2>
<a class="anchor" aria-hidden="true" id="how-language-server-protocol-works" href="#how-language-server-protocol-works"></a>How Language Server Protocol Works</h2>
<p>If you’re an iOS developer,
you may be most familiar with
the terms <dfn>server</dfn> and <dfn>protocol</dfn>
in the sense of communicating with web applications
in JSON format via HTTP.
This actually isn’t too far off from how the Language Server Protocol works.</p>
<p>In the case of LSP,
the <em>client</em> refers to the editor —
or more generally, the tool —
and the <em>server</em> refers to
an external program run locally in a separate process.</p>
<p>As for the <em>protocol</em> itself,
LSP resembles a simplified version of HTTP:</p>
<ul>
<li>Each message consists of
a header part and a content part.</li>
<li>The header part has a required <code>Content-Length</code> field
containing the size of the content part in bytes,
and an optional <code>Content-Type</code> field
(<code>application/vscode-jsonrpc; charset=utf-8</code> by default)</li>
<li>The content part uses <a href="https://www.jsonrpc.org/specification" rel="noopener noreferrer">JSON-RPC</a>
to describe the structure of requests, responses, and notifications.</li>
</ul>
<p>Whenever something happens in the tool,
such as the user jumping to the definition of a symbol,
the tool sends a request to the server.
The server receives that request
and then returns an appropriate response.</p>
<p>For example,
imagine that a user opens the following Swift code
in an Xcode-like editor that supported the Language Server Protocol:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">class</span> <span class="kt">Parent</span> <span class="p">{}</span>
<span class="kd">class</span> <span class="kt">Child</span><span class="p">:</span> <span class="kt">Parent</span> <span class="p">{}</span>
</code></pre>
<p>When the user <kbd>⌘</kbd>-clicks the symbol <code>Parent</code>
in the inheritance clause on line 2,
the editor jumps to the definition of the <code>Parent</code> class on line 1.</p>
<p><img src="/assets/lsp-jump-to-definition-82b4d11d43842656e4143254034bcb34d0d06645c826b5da833b3091ee7c985d430af313ead57060ddf3a0c27a425055dca926d27040d473d6cb2f8a7a80ee9b.gif" integrity="sha512-grTRHUOEJlbkFDJUA0vLNNDQZkXIJrXagzswke58mF1DCvMT6tVwYN3zoMJ6QlBV3Kkm0nBA1HPWyy+KeoDumw==" crossorigin="anonymous" alt=""></p>
<p>Here’s how LSP enables this interaction behind the scenes:</p>
<p>First,
when the user opens the Swift code,
the editor launches its Swift language server in a separate process,
if it isn’t running already,
and performs any additional setup.</p>
<p>When the user executes the “jump to definition” command,
the editor sends the following request to its Swift language server:</p>
<pre class="highlight" data-lang="JSON"><code><span class="p">{</span><span class="w">
</span><span class="nl">"jsonrpc"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2.0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
</span><span class="nl">"method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"text<wbr></wbr>Document/definition"</span><span class="p">,</span><span class="w">
</span><span class="nl">"params"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"text<wbr></wbr>Document"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"uri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:///Users/NSHipster/Example.swift"</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"position"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"line"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
</span><span class="nl">"character"</span><span class="p">:</span><span class="w"> </span><span class="mi">13</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
<p>Upon receiving this request,
the Swift language server uses a compiler tool like
<a href="https://github.com/apple/swift/tree/master/tools/SourceKit" rel="noopener noreferrer">SourceKit</a>
to identify the corresponding code entity
and find the location of its declaration on the preceding line.
The language server then responds with the following message:</p>
<pre class="highlight" data-lang="JSON"><code><span class="p">{</span><span class="w">
</span><span class="nl">"jsonrpc"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2.0"</span><span class="p">,</span><span class="w">
</span><span class="nl">"id"</span><span class="p">:</span><span class="w"> </span><span class="mi">1</span><span class="p">,</span><span class="w">
</span><span class="nl">"result"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"uri"</span><span class="p">:</span><span class="w"> </span><span class="s2">"file:///Users/NSHipster/Example.swift"</span><span class="p">,</span><span class="w">
</span><span class="nl">"range"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"start"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"line"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"character"</span><span class="p">:</span><span class="w"> </span><span class="mi">6</span><span class="w">
</span><span class="p">},</span><span class="w">
</span><span class="nl">"end"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
</span><span class="nl">"line"</span><span class="p">:</span><span class="w"> </span><span class="mi">0</span><span class="p">,</span><span class="w">
</span><span class="nl">"character"</span><span class="p">:</span><span class="w"> </span><span class="mi">12</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre>
<p>Finally,
the editor navigates to the file
(which, in this case, is already open),
moves the cursor to that range,
and highlights the token.</p>
<p>The beauty of this approach is that the editor did all of this
without knowing anything about the Swift programming language
other than that <code>.swift</code> files are associated with Swift code.
All the editor needs to do
is talk to the language server and update the UI.
And knowing how to do that,
the editor can follow the same procedure
to facilitate this interaction
for code written in any language with a language server implementation.</p>
<h2>
<a class="anchor" aria-hidden="true" id="language-server-protocol-support-in-clang-llvm" href="#language-server-protocol-support-in-clang-llvm"></a>Language Server Protocol Support in Clang / LLVM</h2>
<p>If the <em>M + N</em> diagram from before looks familiar,
it might be because it’s the same approach taken by LLVM.</p>
<p>At the core of LLVM is an intermediate representation (IR).
Supported languages generate IR using a <dfn>compiler frontend</dfn>,
and that IR can generate machine code
for any platform supported by a <dfn>compiler backend</dfn>.</p>
<p><img src="/assets/lsp-llvm-ir-51a7a3a7bdebecfd02ac7c2b25172b91005e9779b458f2d01f48b30859ef20bc83b90ec9fbfb0c048714b40bdab6a47d5ef0bc08e9fe4681f92e0038990f81c0.svg" integrity="sha512-Uaejp73r7P0CrHwrJRcrkQBel3m0WPLQH0izCFnvILyDuQ7J+/sMBIcUtAvatqR9XvC8COn+RoH5LgA4mQ+BwA==" crossorigin="anonymous" role="img" alt=""></p>
<aside class="admonition info">
<p>If you’re curious to learn more about how Swift code is compiled,
check out <a href="https://nshipster.com/swiftsyntax/">our article about SwiftSyntax</a>.</p>
</aside>
<p>The LLVM compiler frontend for C languages
is called <a href="https://clang.llvm.org" rel="noopener noreferrer">Clang</a>.
It’s also used by Swift for inter-operability with Objective-C.
In its recent 5.0.0 release,
Clang added a new tool called
<a href="https://clang.llvm.org/extra/clangd.html" rel="noopener noreferrer">Clangd</a>,
LLVM’s implementation for the Language Server Protocol.</p>
<p>In April 2018,
<a href="http://lists.llvm.org/pipermail/cfe-dev/2018-April/057668.html" rel="noopener noreferrer">Apple announced to the LLVM mailing list</a>
that it was switching the focus of its development efforts from
<a href="https://clang.llvm.org/doxygen/group__CINDEX.html" rel="noopener noreferrer">libclang</a>
to Clangd as the primary way to create interactive tooling.</p>
<p>Now you might think, <em>“So what?”</em>
Apple is among the most prominent supporters of the LLVM project —
having, among other things,
employed the project’s founder, Chris Lattner, for over a decade.
Apple’s decision to switch from one obscure Clang tool to another
would seem to be an implementation detail (so to speak).</p>
<p>What makes this announcement quite interesting
is that Clangd appears to have been created entirely outside of Apple,
with significant contributions from Google and other companies.
This announcement signals a significant shift
in the direction of tooling development going forward —
something that would be confirmed 6 months later on the Swift.org forums.</p>
<h2>
<a class="anchor" aria-hidden="true" id="getting-started-with-language-server-protocol" href="#getting-started-with-language-server-protocol"></a>Getting Started with Language Server Protocol</h2>
<p>Xcode 11.4 includes <code>sourcekit-lsp</code> in its default toolchain.
You can use the <code>xcrun</code> command
to get the path to the language server executable:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>xcrun <span class="nt">-f</span> sourcekit-lsp
<span class="go">/Applications/Xcode.app/Contents/Developer/Toolchains/Xcode<wbr></wbr>Default.xctoolchain/usr/bin/sourcekit-lsp
</span></code></pre>
<p>Check out <a href="/vscode/">our article about Visual Studio Code</a>
to get started with our go-to editors.
Beyond that,
the sourcekit-lsp project on GitHub has
<a href="https://github.com/NSHipster/sourcekit-lsp/tree/master/Editors#editor-integration" rel="noopener noreferrer">instructions for integrating with Sublime Text, Vim, Emacs, and others.</a>.</p>
<h2>
<a class="anchor" aria-hidden="true" id="potential-consequences-of-apples-support-of-language-server-protocol" href="#potential-consequences-of-apples-support-of-language-server-protocol"></a>Potential Consequences of Apple’s Support of Language Server Protocol</h2>
<p>It’ll take some time to feel the full impact of these developments,
but believe me: your patience will be rewarded.
Here are just a few of what I believe will happen as a result of LSP
in the coming months and years.</p>
<h3>
<a class="anchor" aria-hidden="true" id="swift-becomes-more-appealing-as-a-general-purpose-programming-language" href="#swift-becomes-more-appealing-as-a-general-purpose-programming-language"></a>Swift Becomes More Appealing as a General-Purpose Programming Language</h3>
<p>Although Swift is used primarily for app development,
it was designed from the start to be
a capable general-purpose programming language.
Between
<a href="https://www.tensorflow.org/swift/" rel="noopener noreferrer">Swift for TensorFlow</a>,
<a href="https://github.com/apple/swift-nio" rel="noopener noreferrer">SwiftNIO</a>,
and other projects,
we’re just starting to see the promise of
what Swift can do beyond the App Store.</p>
<p>Among the biggest factors holding Swift back from
mainstream adoption up to this point
has been its reliance on Xcode.</p>
<p>It’s a lot to ask, say, a web developer or machine learning engineer
to download Xcode just to try Swift
when there are so many great alternatives
with a much lower barrier to entry.
Support for the Language Server Protocol
should make it significantly easier for folks outside the Apple ecosystem
to evaluate Swift with the same, familiar tools they use for everything else.</p>
<h3>
<a class="anchor" aria-hidden="true" id="xcode-gets-better" href="#xcode-gets-better"></a>Xcode Gets Better</h3>
<p>Adopting LSP isn’t just about making Swift work better in other editors;
Xcode stands to benefit immensely, as well.</p>
<p>Consider <a href="https://forums.swift.org/t/new-lsp-language-service-supporting-swift-and-c-family-languages-for-any-editor-and-platform/17024/29" rel="noopener noreferrer">this forum post</a>
from Project Lead for Swift at Apple, Ted Kremenek:</p>
<blockquote>
<p>The LSP service [Argyrios] is describing
will be functionally more powerful than SourceKit is today.</p>
</blockquote>
<p>LSP is an opportunity for the Xcode team to take a fresh approach to
Swift integration,
and to capitalize on all of the improvements to the language and tooling
in the four years since its 1.0 release.</p>
<p>Our first glimpse into this overhauled infrastructure comes by way of
<a href="https://github.com/apple/indexstore-db" rel="noopener noreferrer">IndexStoreDB</a>:
a powerful new API for querying code symbols in Swift projects
from a <a href="https://docs.google.com/document/d/1cH2sTpgSnJZCkZtJl1aY-rzy4uGPcrI-6RrUpdATO2Q/" rel="noopener noreferrer">Clang index</a>.</p>
<h3>
<a class="anchor" aria-hidden="true" id="xcode-eventually-becomes-more-capable" href="#xcode-eventually-becomes-more-capable"></a>Xcode (Eventually) Becomes More Capable</h3>
<p>The benefit of LSP isn’t limited to Swift and Objective-C;
<a href="https://forums.swift.org/t/new-lsp-language-service-supporting-swift-and-c-family-languages-for-any-editor-and-platform/17024/33" rel="noopener noreferrer">from another post by Argyrios in that thread</a>:</p>
<blockquote>
<p>Getting Xcode to use our new LSP service
should make it viable to use other LSP services as well,
and it’s something that we are interested in,
but we don’t have specific plans to announce at this moment.</p>
</blockquote>
<p>The main focus for the current efforts are to improve the story for Swift.
But once that’s done, it should be relatively straightforward
to have those benefits cascade down to other languages with LSP support.</p>
<hr>
<p>The architecture of software
reflects the structure and values of the organizations that create it.
The converse is true as well, to some extent.</p>
<p>By adopting the open Language Server Protocol standard for Xcode,
Apple is making good on its commitment to the success of Swift
on platforms outside the Apple ecosystem.
And I think it’ll work:
tooling (or lack thereof) is often the key decider
in which technologies gain mindshare.
But perhaps more importantly,
I believe this decision demonstrates an increased willingness within
(at least some small part of) the company
for collaboration and transparency.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>Apple’s adoption of LSP is arguably the most important decision they’ve made for Swift since releasing the language as open source in 2014. It’s a big deal for app developers, and it’s an even bigger deal for Swift developers on other platforms.</p>Swift Development with Visual Studio Code2018-11-19T00:00:00-08:002020-05-06T00:00:00-07:00https://nshipster.com/vscode
<p><a href="https://code.visualstudio.com" rel="noopener noreferrer">Visual Studio Code (VSCode)</a>
is a cross-platform text and source code editor from Microsoft.
It’s one of the most exciting open source projects today,
with regular updates from hundreds of contributors.
VSCode was among the first tools to support
<a href="https://microsoft.github.io/language-server-protocol/" rel="noopener noreferrer">Language Server Protocol (LSP)</a>,
which has played a large part in providing a great developer experience,
in a variety of languages and technologies.</p>
<p>With the <a href="/language-server-protocol/">previously announced</a>
<a href="https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_beta_release_notes" rel="noopener noreferrer">now shipping in Xcode</a>,
it’s a great time to see how this integration works for yourself.</p>
<p>This week,
we’ll walk through the process of how to get started with
Swift’s new Language Server Protocol support in Visual Studio Code on macOS.
If you haven’t tried writing Swift outside Xcode,
or are already a VSCode user and new to the language entirely,
this article will tell you everything you need to know.</p>
<hr><a id="get-on-with-it"></a>
<p><img src="/assets/vscode-banner-2f6618b018729b639085bf3144354c51423c30a30f9b4b3c6806a95ae2e9c8ce3e5f1b9ac05a40071846112b0757e20f67ccd946bd874e9b6dba7ba8bb9a547b.png" integrity="sha512-L2YYsBhym2OQhb8xRDVMUUI8MKMPm0s8aAapWuLpyM4+XxuawFpABxhGESsHV+IPZ8zZRr2HTpttunuou5pUew==" crossorigin="anonymous" alt=""></p>
<h2>
<a class="anchor" aria-hidden="true" id="step-0-install-xcode" href="#step-0-install-xcode"></a>Step 0: Install Xcode</h2>
<p>If you don’t already have Xcode installed on your machine,
open the Terminal app and run the following command:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>xcode-select <span class="nt">--install</span>
</code></pre>
<p>Running this command presents a system prompt.</p>
<p><img src="/assets/xcode-select-window-4009aaac50fc3fe10ad7811886fab013771b6ca9f62c33c3afaf95c7cc62e4e4cecf90a1702bee0d4763dc5c768950e90ae0b96bb731b57ce83e3d584121c57a.png" integrity="sha512-QAmqrFD8P+EK14EYhvqwE3cbbKn2LDPDr6+Vx8xi5OTOz5ChcCvuDUdj3Fx2iVDpCuC5a7cxtXzoPj1YQSHFeg==" crossorigin="anonymous" alt=""></p>
<p>Click the “Get Xcode” button
and continue installation on the App Store.</p>
<p>You can verify that everything is working as expected
by running the <code>sourcekit-lsp</code> command:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>xcrun sourcekit-lsp
</code></pre>
<p>This command launches a new language server process,
but don’t worry if it doesn’t provide any feedback to <code>STDOUT</code> —
that means it’s working as intended.
Exit the process with an ETX signal (<kbd>^</kbd><kbd>C</kbd>).</p>
<h2>
<a class="anchor" aria-hidden="true" id="step-1-install-visual-studio-code" href="#step-1-install-visual-studio-code"></a>Step 1: Install Visual Studio Code</h2>
<p><a href="https://code.visualstudio.com" rel="noopener noreferrer">Download Visual Studio Code</a>
and install it to your system Applications folder.
Open the app and
<a href="https://code.visualstudio.com/docs/setup/mac#_launching-from-the-command-line" rel="noopener noreferrer">follow the instructions for launching from the command line</a>.
You’ll need to have the <code>code</code> command accessible from <code>$PATH</code>
in order to install the SourceKit-LSP extension later on.</p>
<aside class="admonition info">
<p><a href="https://electronjs.org" rel="noopener noreferrer">Electron</a> apps
have a reputation for being big and slow,
but don’t let that stop you from giving VSCode a try —
its performance and memory footprint are comparable to a native app.</p>
</aside>
<h2>
<a class="anchor" aria-hidden="true" id="step-2-install-node-and-npm" href="#step-2-install-node-and-npm"></a>Step 2: Install Node and NPM</h2>
<p>VSCode extensions are written in JavaScript / TypeScript.
If you’re not already set up for JS development,
you can download Node (a JavaScript run-time for outside the browser)<br>
and npm (a package manager for Node)
with <a href="https://brew.sh" rel="noopener noreferrer">Homebrew</a> using the following commands
or manually by <a href="https://www.npmjs.com/get-npm" rel="noopener noreferrer">following these instructions</a>:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>brew <span class="nb">install </span>node
</code></pre>
<p>To verify that you have a working installation,
run the following command:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>npm <span class="nt">--version</span>
<span class="go">6.13.4
</span></code></pre>
<h2>
<a class="anchor" aria-hidden="true" id="step-3-build-and-install-sourcekit-lsp-extension-for-visual-studio-code" href="#step-3-build-and-install-sourcekit-lsp-extension-for-visual-studio-code"></a>Step 3: Build and Install SourceKit-LSP Extension for Visual Studio Code</h2>
<p>From the command line,
clone the <a href="https://github.com/apple/sourcekit-lsp" rel="noopener noreferrer">sourcekit-lsp repository</a>
and navigate to <code>Editors/vscode</code> in the resulting directory.
Use <code>npm</code> to build the extension
and then use the <code>code</code> command to install it:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>git clone https://github.com/apple/sourcekit-lsp.git
<span class="gp">$</span><span class="w"> </span><span class="nb">cd </span>sourcekit-lsp/Editors/vscode/
<span class="gp">$</span><span class="w"> </span>npm run create<wbr></wbr>Dev<wbr></wbr>Package
<span class="gp">$</span><span class="w"> </span>code <span class="nt">--install-extension</span> out/sourcekit-lsp-vscode-dev.vsix
</code></pre>
<p>Now launch (or relaunch) VSCode and open a Swift project,
such as <a href="https://github.com/flight-school/money" rel="noopener noreferrer">this one</a>,
and test out Language Server Protocol support for Swift.</p>
<p><img src="/assets/vscode-swift-lsp-screenshot-6852df25f683c5f0c7f751aaf31b8cb32db1fe16b85d44540dec7a63dfd21fea5c1dded771e0a9bc21b110e66d31c5d45f03dc8c2ea209798be83eb730e0b7fb.png" integrity="sha512-aFLfJfaDxfDH91Gq8xuMsy2x/ha4XURUDex6Y9/SH+pcHd7XceCpvCGxEOZtMcXUXwPcjC6iCXmL6D63MOC3+w==" crossorigin="anonymous" alt=""></p>
<aside class="admonition warning">
<p>If you get an error stating <code>Couldn't start client Source<wbr></wbr>Kit Language Server</code>,
you may also need to specify the sourcekit-lsp executable path,
which you can find using <code>xcrun</code>:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>xcrun <span class="nt">--find</span> sourcekit-lsp
<span class="go">/Library/Developer/Command<wbr></wbr>Line<wbr></wbr>Tools/usr/bin/sourcekit-lsp
</span></code></pre>
<p>Copy the printed value and enter it into the setting for
<strong>Server Path</strong> under Preferences > Settings, Extensions > SourceKit-LSP,
and then Reload Window.</p>
</aside>
<aside class="admonition info">
<p>To get the full experience of working with Swift from VSCode,
we recommend that you also check out
the <a href="https://marketplace.visualstudio.com/items?itemName=vknabel.vscode-swiftlint" rel="noopener noreferrer">Swift Lint extension</a>
(for real-time style and convention diagnostics).</p>
</aside>
<hr>
<p>So there you have it —
the makings of a first-class Swift development experience outside of Xcode.</p>
<p>And with GitHub’s recent announcement of
<a href="https://github.com/features/codespaces/" rel="noopener noreferrer">Codespaces</a>,
that future may be coming sooner than we once thought.
Thanks to Swift’s support for
<a href="/language-server-protocol/">Language Server Protocol</a>,
we’ll soon be able to edit Swift code —
syntax highlighting, autocompletion, and all —
directly from the browser.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>VSCode is a cross-platform text and source code editor from Microsoft, and among the first tools to support Language Server Protocol. With LSP for Swift now shipping in Xcode, it’s a great time to see how this integration works for yourself.</p>Contact Tracing2020-04-13T00:00:00-07:002020-04-29T00:00:00-07:00https://nshipster.com/contact-tracing
<blockquote>
<p>An ounce of prevention is worth a pound of cure.</p>
</blockquote>
<p>Early intervention is among the most effective strategies for treating illnesses.
This is true not only for the human body, for society as a whole.
That’s why public health officials use contact tracing
as their first line of defense against
the spread of infectious disease in a population.</p>
<p>We’re hearing a lot about contact tracing these days,
but the technique has been used for decades.
What’s changed is that
thanks to the ubiquity of personal electronic devices,
we can automate what was — up until now — a labor-intensive, manual process.
Much like how “computer” used to be a job title held by humans,
the role of “contact tracer” may soon be filled primarily by apps.</p>
<p>On April 10th,
Apple and Google <a href="https://www.apple.com/newsroom/2020/04/apple-and-google-partner-on-covid-19-contact-tracing-technology/" rel="noopener noreferrer">announced</a> a joint initiative
to deploy contact tracing functionality
to the billions of devices running iOS or Android
in the coming months.
As part of this announcement,
the companies shared draft specifications for the
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf" rel="noopener noreferrer">cryptography</a>,
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf" rel="noopener noreferrer">hardware</a>,
and
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-FrameworkDocumentationv1.2.pdf" rel="noopener noreferrer">software</a>
involved in their proposed solution.</p>
<p>In this article,
we’ll take a first look at these specifications —
particularly Apple’s proposed <code>Exposure<wbr></wbr>Notification</code> framework —
and use what we’ve learned to anticipate what
this will all look like in practice.</p>
<aside class="admonition warning">
<p>On April 29th,
Apple released iOS 13.5 beta 1,
which includes the first public release of the
<code>Exposure<wbr></wbr>Notification</code> (previously <code>Contact<wbr></wbr>Tracing</code>) framework.
The content in this article has been updated to reflect these changes.</p>
</aside>
<hr><a id="get-on-with-it"></a>
<h2>
<a class="anchor" aria-hidden="true" id="what-is-contact-tracing" href="#what-is-contact-tracing"></a>What is contact tracing?</h2>
<p><dfn>Contact tracing</dfn> is a technique used by public health officials
to identify people who are exposed to an infectious disease
in order to slow the spread of that illness within a population.</p>
<p>When a patient is admitted to a hospital
and diagnosed with a new, communicable disease,
they’re interviewed by health workers
to learn who they’ve interacted recently.
Any contacts whose interactions with the patient are then evaluated,
and if they’re diagnosed with the disease,
the process repeats with their known, recent contacts.</p>
<p>Contact tracing disrupts the chain of transmission.
It gives people the opportunity to isolate themselves before infecting others
and to seek treatment before they present symptoms.
It also allows decision-makers to make more informed
recommendations and policy decisions about additional measures to take.</p>
<p>If you start early and act quickly,
contact tracing gives you a fighting chance of containing an outbreak
before it gets out of hand.</p>
<p>Unfortunately, we weren’t so lucky this time around.</p>
<p>With over a million confirmed cases of <abbr>COVID-19</abbr> worldwide,
many regions are well past the point where contact tracing is practical.
But that’s not to say that it can’t play an essential role
in the coming weeks and months.</p>
<h2>
<a class="anchor" aria-hidden="true" id="only-apple-and-google-can-do-this" href="#only-apple-and-google-can-do-this"></a>“Only Apple <ins>(and Google)</ins> can do this.”</h2>
<p>Since the outbreak,
various <a href="https://www.pepp-pt.org" rel="noopener noreferrer">governments</a>
and <a href="https://github.com/DP-3T/documents" rel="noopener noreferrer">academics</a>
have proposed standards for contact tracing.
But the most significant development so far came yesterday
with Apple and Google’s announcement of a joint initiative.</p>
<p>According to the
<abbr title="United Kingdom National Health Service">NHS</abbr>,
around 60% of adults in a population
would need to participate in order for digital contact tracing to be effective.
Researchers from the aforementioned institutions have noted
that the limits imposed by iOS on 3rd-party apps
make this level of participation unlikely.</p>
<p>On the one hand,
it feels weird to congratulate Apple for stepping in
to solve a problem it created in the first place.
But we can all agree that this announcement
is something to celebrate.
It’s no exaggeration to say that
this wouldn’t be possible without their help.</p>
<h2>
<a class="anchor" aria-hidden="true" id="what-are-apple-and-google-proposing-as-a-solution" href="#what-are-apple-and-google-proposing-as-a-solution"></a>What are Apple and Google proposing as a solution?</h2>
<p>At a high level,
Apple and Google are proposing a common standard
for how personal electronic devices (phones, tablets, watches)
can automate the process of contact tracing.</p>
<p>Instead of health workers chasing down contacts on the phone —
a process that can take hours, or even days —
the proposed system could identify every recent contact
and notify all of them within moments of a confirmed, positive diagnosis.</p>
<aside class="admonition info">
<p><a href="https://blog.google/documents/57/Overview_of_COVID-19_Contact_Tracing_Using_BLE.pdf" rel="noopener noreferrer">This infographic</a>
from Google’s blog post announcing the partnership
provides a nice explanation of the technologies involved.</p>
</aside>
<p>Apple’s CEO, Tim Cook, promises that
<a href="https://twitter.com/tim_cook/status/1248657931433693184" rel="noopener noreferrer">“Contact tracing can help slow the spread of COVID-19 and can be done without compromising user privacy.”</a>.
The specifications accompanying the announcement
show how that’s possible.</p>
<p>Let’s take them in turn,
starting with
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf" rel="noopener noreferrer">cryptography</a> (key derivation & rotation),
followed by
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-BluetoothSpecificationv1.2.pdf" rel="noopener noreferrer">hardware</a> (Bluetooth),
and
<a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-FrameworkDocumentationv1.2.pdf" rel="noopener noreferrer">software</a> (app)
components.</p>
<h3>
<a class="anchor" aria-hidden="true" id="cryptography" href="#cryptography"></a>Cryptography</h3>
<p>When you install an app and open it for the first time,
the Exposure Notification framework displays
a dialog requesting permission
to enable contact tracing on the device.</p>
<p>If the user accepts,
the framework generates a 32-byte cryptographic random number
to serve as the device’s <dfn>Tracing Key</dfn>.
The Tracing Key is kept secret, never leaving the device.</p>
<aside class="admonition info">
<p>If the concept of “binary data” seems daunting or meaningless to you,
it can help to see a few examples of how that information
can be encoded into a human-readable form.</p>
<p>32 bytes of binary data can be represented by
44-character-long <a href="https://en.wikipedia.org/wiki/Base64" rel="noopener noreferrer">Base64-encoded</a> string
or a string of 64 <a href="https://en.wikipedia.org/wiki/Hexadecimal#Binary_conversion" rel="noopener noreferrer">hexadecimal</a> digits.
You can generate these for yourself from the command line
with the following commands:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span><span class="nb">head</span> <span class="nt">-c32</span> < /dev/urandom | xxd <span class="nt">-p</span> <span class="nt">-c</span> 64
<span class="go">211ad682549d92fbb6cd5dc42be5121b22f8864b3a7e93cedb9c43c83332440d
</span><span class="gp">$</span><span class="w"> </span><span class="nb">head</span> <span class="nt">-c32</span> < /dev/urandom | <span class="nb">base64</span>
<span class="go">2p<wbr></wbr>NDyj5LSr0GGi1IL2VOvsov<wbr></wbr>Bwm<wbr></wbr>G4Yp5YYP7leg928Y=
</span></code></pre>
<p>16 bytes of binary data can also be represented in Base64 or hexadecimal,
but it’s more common and convenient to use a
<a href="https://tools.ietf.org/html/rfc4122" title="A Universally Unique IDentifier (UUID) URN Namespace" rel="noopener noreferrer"><abbr title="Universally Unique Identifier">UUID</abbr></a>.</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>uuidgen
<span class="go">33F1C4D5-3F1C-4FF0-A05E-A267FAB237CB
</span></code></pre>
</aside>
<p>Every 24 hours,
the device takes the Tracing Key and the day number (0, 1, 2, …)
and uses
<a href="https://tools.ietf.org/html/rfc5869" title="HMAC-based Extract-and-Expand Key Derivation Function (HKDF)" rel="noopener noreferrer"><abbr title="HMAC-based Extract-and-Expand Key Derivation Function">HKDF</abbr></a>
to derive a 16-byte <dfn><del>Daily Tracing Key</del><ins>Temporary Exposure Key</ins></dfn>.
These keys stay on the device,
unless you consent to share them.</p>
<p>Every 15 minutes,
the device takes the Temporary Exposure Key and
the number of 10-minute intervals since the beginning of the day (0 – 143),
and uses
<a href="https://tools.ietf.org/html/rfc2104" title="HMAC: Keyed-Hashing for Message Authentication" rel="noopener noreferrer"><abbr title="Keyed-Hashing for Message Authentication">HMAC</abbr></a>
to generate a new 16-byte <dfn>Rolling Proximity Identifier</dfn>.
This identifier is broadcast from the device using
<a href="https://en.wikipedia.org/wiki/Bluetooth_Low_Energy" rel="noopener noreferrer">Bluetooth <abbr title="Low Energy">LE</abbr></a>.</p>
<p>If someone using a contact tracing app gets a positive diagnosis,
the central health authority requests their Temporary Exposure Keys
for the period of time that they were contagious.
If the patient consents,
those keys are then added to the health authority’s database as
<dfn>Positive Diagnosis Keys</dfn>.
Those keys are shared with other devices
to determine if they’ve had any contact over that time period.</p>
<aside class="admonition info">
<p>The <a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-CryptographySpecificationv1.2.pdf" rel="noopener noreferrer">Contact Tracing Cryptography Specification</a>
is concise, clearly written, and remarkably accessible.
Anyone for whom the name <em><a href="https://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" rel="noopener noreferrer">Diffie–Hellman</a></em> even rings a bell
are encouraged to give it a quick read.</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="hardware" href="#hardware"></a>Hardware</h3>
<p>Bluetooth organizes communications between devices
around the concept of <dfn>services</dfn>.</p>
<p>A service describes a set of characteristics for accomplishing a particular task.
A device may communicate with multiple services
in the course of its operation.
Many service definitions are <a href="https://www.bluetooth.com/specifications/gatt/" rel="noopener noreferrer">standardized</a>
so that devices that do the same kinds of things communicate in the same way.</p>
<p>For example,
a wireless heart rate monitor
that uses Bluetooth to communicate to your phone
would have a profile containing two services:
a primary Heart Rate service and
a secondary Battery service.</p>
<p>Apple and Google’s Contact Tracing standard
defines a new Contact Detection service.</p>
<p>When a contact tracing app is running (either in the foreground or background),
it acts as a <dfn>peripheral</dfn>,
advertising its support for the Contact Detection service
to any other device within range.
The Rolling Proximity Identifier generated every 15 minutes
is sent in the advertising packet along with the 16-bit service UUID.</p>
<p>Here’s some code for doing this from an iOS device using
the <a href="https://developer.apple.com/documentation/corebluetooth" rel="noopener noreferrer">Core Bluetooth framework</a>:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Core<wbr></wbr>Bluetooth</span>
<span class="c1">// Contact Detection service UUID</span>
<span class="k">let</span> <span class="nv">service<wbr></wbr>UUID</span> <span class="o">=</span> <span class="kt">CBUUID</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"FD6F"</span><span class="p">)</span>
<span class="c1">// Rolling Proximity Identifier</span>
<span class="k">let</span> <span class="nv">identifier</span><span class="p">:</span> <span class="kt">Data</span> <span class="o">=</span> <span class="err"><var class="placeholder">…</var></span> <span class="c1">// 16 bytes</span>
<span class="k">let</span> <span class="nv">peripheral<wbr></wbr>Manager</span> <span class="o">=</span> <span class="kt">CBPeripheral<wbr></wbr>Manager</span><span class="p">()</span>
<span class="k">let</span> <span class="nv">advertisement<wbr></wbr>Data</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">:</span> <span class="kt">Any</span><span class="p">]</span> <span class="o">=</span> <span class="p">[</span>
<span class="kt">CBAdvertisement<wbr></wbr>Data<wbr></wbr>Service<wbr></wbr>UUIDs<wbr></wbr>Key</span><span class="p">:</span> <span class="p">[</span><span class="n">service<wbr></wbr>UUID</span><span class="p">]</span>
<span class="kt">CBAdvertisement<wbr></wbr>Data<wbr></wbr>Service<wbr></wbr>Data<wbr></wbr>Key</span><span class="p">:</span> <span class="n">identifier</span>
<span class="p">]</span>
<span class="n">peripheral<wbr></wbr>Manager</span><span class="o">.</span><span class="nf">start<wbr></wbr>Advertising</span><span class="p">(</span><span class="n">advertisement<wbr></wbr>Data</span><span class="p">)</span>
</code></pre>
<p>At the same time that the device broadcasts as a peripheral,
it’s also scanning for other devices’ Rolling Proximity Identifiers.
Again, here’s how you might do that on iOS using Core Bluetooth:</p>
<aside class="parenthetical">
<p>Conditionally, based on what operations are allowed by the system.</p>
</aside>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">delegate</span><span class="p">:</span> <span class="kt">CBCentral<wbr></wbr>Manager<wbr></wbr>Delegate</span> <span class="o">=</span> <span class="err"><var class="placeholder">…</var></span>
<span class="k">let</span> <span class="nv">central<wbr></wbr>Manager</span> <span class="o">=</span> <span class="kt">CBCentral<wbr></wbr>Manager</span><span class="p">(</span><span class="nv">delegate</span><span class="p">:</span> <span class="n">delegate</span><span class="p">,</span> <span class="nv">queue</span><span class="p">:</span> <span class="o">.</span><span class="n">main</span><span class="p">)</span>
<span class="n">central<wbr></wbr>Manager</span><span class="o">.</span><span class="nf">scan<wbr></wbr>For<wbr></wbr>Peripherals</span><span class="p">(</span><span class="nv">with<wbr></wbr>Services</span><span class="p">:</span> <span class="p">[</span><span class="n">service<wbr></wbr>UUID</span><span class="p">],</span> <span class="nv">options</span><span class="p">:</span> <span class="p">[:])</span>
<span class="kd">extension</span> <var class="placeholder">Delegate<wbr></wbr>Class</var><span class="p">:</span> <span class="kt">CBCentral<wbr></wbr>Manager<wbr></wbr>Delegate</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">central<wbr></wbr>Manager</span><span class="p">(</span><span class="n">_</span> <span class="nv">central</span><span class="p">:</span> <span class="kt">CBCentral<wbr></wbr>Manager</span><span class="p">,</span>
<span class="n">did<wbr></wbr>Discover</span> <span class="nv">peripheral</span><span class="p">:</span> <span class="kt">CBPeripheral</span><span class="p">,</span>
<span class="nv">advertisement<wbr></wbr>Data</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span> <span class="p">:</span> <span class="kt">Any</span><span class="p">],</span>
<span class="n">rssi</span> <span class="kt">RSSI</span><span class="p">:</span> <span class="kt">NSNumber</span><span class="p">)</span>
<span class="p">{</span>
<span class="k">let</span> <span class="nv">identifier</span> <span class="o">=</span> <span class="n">advertisement<wbr></wbr>Data</span><span class="p">[</span><span class="kt">CBAdvertisement<wbr></wbr>Data<wbr></wbr>Service<wbr></wbr>Data<wbr></wbr>Key</span><span class="p">]</span> <span class="k">as!</span> <span class="kt">Data</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>Bluetooth is an almost ideal technology for contact tracing.
It’s on every consumer smart phone.
It operates with low power requirement,
which lets it run continuously without draining your battery.
And it <em>just</em> so happens to have a transmission range
that approximates the physical proximity required
for the airborne transmission of infectious disease.
This last quality is what allows contact tracing to be done
without resorting to location data.</p>
<aside class="parenthetical">
<p>As we noted in <a href="/device-identifiers/#fingerprinting-in-todays-ios">a previous article</a>,
individuals within a population
can be singled out by as few as four timestamped coordinates.</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="software" href="#software"></a>Software</h3>
<p>Your device stores any Rolling Proximity Identifiers it discovers,
and periodically checks them against
a list of Positive Diagnosis Keys sent from the central health authority.</p>
<p>Each Positive Diagnosis Key corresponds to someone else’s Temporary Exposure Key.
We can derive all of the possible Rolling Proximity Identifiers
that it could advertise over the course of that day
(using the same <abbr title="Keyed-Hashing for Message Authentication">HMAC</abbr> algorithm
that we used to derive our own Rolling Proximity Identifiers).
If any matches were found among
your device’s list of Rolling Proximity Identifiers,
it means that you may have been in contact with an infected individual.</p>
<p>Suffice to say that digital contact tracing is really hard to get right.
Given the importance of getting it right,
both in terms of yielding accurate results and preserving privacy,
Apple and Google are providing SDKs for app developers to use
for iOS and Android, respectively.</p>
<p>All of the details we discussed about cryptography and Bluetooth
are managed by the framework.
The only thing we need to do as developers
is communicate with the user —
specifically, requesting their permission to start contact tracing
and notifying them about a positive diagnosis.</p>
<h2>
<a class="anchor" aria-hidden="true" id="exposurenotification" href="#exposurenotification"></a>ExposureNotification</h2>
<p>When Apple announced the <code>Contact<wbr></wbr>Tracing</code> framework on April 10th,
all we had to go on were some annotated Objective-C headers.
But as of the first public beta of iOS 13.5,
we now have <a href="https://developer.apple.com/documentation/exposurenotification" rel="noopener noreferrer">official documentation</a>
under its name: <code>Exposure<wbr></wbr>Notification</code>.</p>
<h3>
<a class="anchor" aria-hidden="true" id="calculating-risk-of-exposure" href="#calculating-risk-of-exposure"></a>Calculating Risk of Exposure</h3>
<p>A contact tracing app regularly
fetches new Positive Diagnosis Keys from the central health authority.
It then checks those keys
against the device’s Rolling Proximity Identifiers.
Any matches would indicate a possible risk of exposure.</p>
<p>In the first version of <code>Contact<wbr></wbr>Tracing</code>,
all you could learn about a positive match was
how long you were exposed <em>(in 5 minute increments)</em>
and when contact occurred <em>(with an unspecified level of precision)</em>.
While we might applaud the level of privacy protections here,
that doesn’t offer much in the way of actionable information.
Depending on the individual,
a push notification saying
“You were in exposed for 5–10 minutes sometime 3 days ago”
could warrant a visit to the hospital
or elicit no more concern than a missed call.</p>
<p>With <code>Exposure<wbr></wbr>Notification</code>,
you get a lot more information, including:</p>
<ul>
<li>Days since last exposure incident</li>
<li>Cumulative duration of the exposure (capped at 30 minutes)</li>
<li>Minimum Bluetooth signal strength attenuation
<em>(Transmission Power - RSSI)</em>,
which can tell you how close they got</li>
<li>Transmission risk,
which is an app-definied value that may be based on
symptoms, level of diagnosis verification,
or other determination from the app or a health authority</li>
</ul>
<p>For each instance of exposure,
an <a href="https://developer.apple.com/documentation/exposurenotification/enexposureinfo" rel="noopener noreferrer"><code>ENExposure<wbr></wbr>Info</code></a>
object provides all of the aforementioned information
plus an overall risk score
<em>(<a href="https://developer.apple.com/documentation/exposurenotification/enrisklevel" rel="noopener noreferrer">from 1 to 8</a>)</em>,
which is calculated from
<a href="https://developer.apple.com/documentation/exposurenotification/enexposureconfiguration" rel="noopener noreferrer">the app’s assigned weights for each factor</a>,
according to this equation:</p>
<figure>
<p><img width="100%" src="/assets/contact-tracing-equation-22e0c96a5a6d0814d0abbd7dc4dbd99dbbb8f66e673b89e2a2d20930595c8bfc738d842c9dac13e20f85c4ab76716dee65ad2ab150b9512747a44d5d09578141.svg" integrity="sha512-IuDJalptCBTQq719xNvZnbu49m5nO4niotIJMFlci/xzjYQsnawT4g+FxKt2cW3uZa0qsVC5USdHpE1dCVeBQQ==" crossorigin="anonymous" role="img" alt=""></p>
<figcaption hidden="">
<p><em>S</em> is a score,
<em>W</em> is a weighting,
<em>r</em> is risk,
<em>d</em> is days since exposure,
<em>t</em> is duration of exposure,
<em>ɑ</em> is Bluetooth signal strength attenuation</em></p>
</figcaption>
</figure>
<p>Apple provides this example in their <a href="https://covid19-static.cdn-apple.com/applications/covid19/current/static/contact-tracing/pdf/ExposureNotification-FrameworkDocumentationv1.2.pdf" rel="noopener noreferrer">framework documentation PDF</a>:</p>
<p><img src="/assets/contact-tracing-example-equation-7c287507a5e6dc3ce2b17078e408283d19a4bc64f69fbd08ce8f6092838eb5022e546a6560425f22a44a512d410058ebaa836ba689eb4d1508fb96e39d1a9037.png" integrity="sha512-fCh1B6Xm3DzisXB45AgoPRmkvGT2n70Izo9gkoOOtQIuVGplYEJfIqRKUS1BAFjrqoNrponrTRUI+5bjnRqQNw==" crossorigin="anonymous" alt=""></p>
<h3>
<a class="anchor" aria-hidden="true" id="managing-permissions-and-disclosures" href="#managing-permissions-and-disclosures"></a>Managing Permissions and Disclosures</h3>
<p>The biggest challenge we found with the original Contact Tracing framework API
was dealing with all of its completion handlers.
Most of the functionality was provided through asynchronous APIs;
without a way to <a href="/optional-throws-result-async-await/">compose</a> these operations,
you can easily find yourself nested 4 or 5 closures deep,
indented to the far side of your editor.</p>
<aside class="parenthetical">
<p>If ever there was a need for
<a href="https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619" rel="noopener noreferrer">async/await</a>
in Swift,
this was it.</p>
</aside>
<p>Fortunately,
the latest release of Exposure Notification includes a new
<a href="https://developer.apple.com/documentation/exposurenotification/enmanager" rel="noopener noreferrer"><code>ENManager</code></a> class,
which simplifies much of that asynchronous state management.</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">manager</span> <span class="o">=</span> <span class="kt">ENManager</span><span class="p">()</span>
<span class="n">manager</span><span class="o">.</span><span class="n">activate</span> <span class="p">{</span> <span class="n">error</span> <span class="k">in</span>
<span class="k">guard</span> <span class="n">error</span> <span class="o">==</span> <span class="kc">nil</span> <span class="k">else</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="n">manager</span><span class="o">.</span><span class="nf">set<wbr></wbr>Exposure<wbr></wbr>Notification<wbr></wbr>Enabled</span><span class="p">(</span><span class="kc">true</span><span class="p">)</span> <span class="p">{</span> <span class="n">error</span> <span class="k">in</span>
<span class="k">guard</span> <span class="n">error</span> <span class="o">==</span> <span class="kc">nil</span> <span class="k">else</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="c1">// app is now advertising and monitoring for tracing identifiers</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="tracing-a-path-back-to-normal-life" href="#tracing-a-path-back-to-normal-life"></a>Tracing a path back to normal life</h2>
<p>Many of us have been sheltering in place for weeks, if not months.
Until a vaccine is developed and made widely available,
this is the most effective strategy we have for stopping the spread of the disease.</p>
<p>But experts are saying that a vaccine
could be anywhere from 9 to 18 months away.
<em>“What will we do until then?”</em></p>
<p>At least here in the United States,
we don’t yet have a national plan for getting back to normal,
so it’s hard to say.
What we do know is that
it’s not going to be easy,
and it’s not going to come all at once.</p>
<p>Once the rate of new infections stabilizes,
our focus will become containing new outbreaks in communities.
And to that end,
technology-backed contact tracing can play a crucial role.</p>
<p>From a technical perspective,
Apple and Google’s proposal gives us every reason to believe that
we <em>can</em> do contact tracing without compromising privacy.
However,
the amount of faith you put into this solution
depends on how much you trust
these companies and our governments in the first place.</p>
<p>Personally,
I remain cautiously optimistic.
Apple’s commitment to privacy has long been one of its greatest assets,
and it’s now more important than ever.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>Apple and Google announced a joint initiative to deploy contact tracing functionality to the billions of devices running iOS or Android in the coming months. In this article, we’ll take a first look at these specifications — particularly, Apple’s proposed ExposureNotification framework — in an effort to anticipate what this will all look like in practice.</p>Cross-Pollination2020-04-22T00:00:00-07:002020-04-22T00:00:00-07:00https://nshipster.com/cross-pollination
<p>April is the month when apple trees start to bloom
up here in the Pacific Northwest.
All across Oregon’s Willamette Valley,
from Portland stretching south to Eugene,
long-barren branches sprout white, 5-petaled blossoms tinged with pink.
Any other year,
our family would be taking weekend trips
southwest to Sherwood or east towards Hood River
to visit their orchards.</p>
<p>Like the Fuji and Gala varieties that predominate in this region,
most apple cultivars are <dfn>self-unfruitful</dfn> —
which is to say that they require cross-pollination
to produce a good crop consistently.</p>
<aside class="parenthetical">
<p>There are a few cultivars that are partially self-fruitful
and may produce a good crop without the help of another variety.
But even they would typically benefit from cross-pollination.</p>
</aside>
<!-- diagram -->
<p>When fertilized by the pollen of Fuji apple blossoms
(or those of Braeburn, Honey Crisp, or McIntosh varieties),
a Gala apple tree can yield 20 kilograms of fruit each season.
Those Gala trees, in return, endow their pollen on the Fuji apple trees
so that they too may blossom and bear one or two bushels of fruit, each.</p>
<h2>
<a class="anchor" aria-hidden="true" id="the-dance-of-the-honey-bee" href="#the-dance-of-the-honey-bee"></a>The Dance of the Honey Bee</h2>
<p>Appletree pollen is sticky.
In contrast with the windborne pollen of Alder, Birch, and Ash trees
(whose allergenic quality gave the Willamette its name,
meaning <em>“valley of sickness”</em> in the indigenous Kalapuya dialect),
appletrees rely on insects to transfer pollen —
particularly the <dfn>honey bee</dfn>.</p>
<p>Honey bees eat the pollen of flowers and convert their nectar into honey.
Some of the pollen sticks to their furry bodies,
which is inadvertently spread as they move from plant to plant.</p>
<p>When a scout bee encounters a food source,
she flies back to the hive
and communicates the location of that food source to male worker bees
by performing what’s called a <dfn>waggle dance</dfn>.
Performed in darkness on the vertical honeycomb surface in the hive,
she’s able to convey the precise location of new food sources to them
by flying a coffee bean-shaped pattern oriented in the direction of the sun.
It’s an incredible feat,
made all the more remarkable by the fact that bees are not, individually,
very intelligent.
Bees have brains on the order of 1 million neurons,
compared to the 100 billion neurons of a human brain.</p>
<p>If you move a food source closer and farther away from a hive,
you can see how the dance changes to convey this new information.
But move it <em>just</em> past some critical point,
and the dance becomes something entirely different:
instead of the waggle dance,
the bee performs a <dfn>round dance</dfn>
with a totally different cadence and flight path.</p>
<!-- diagram -->
<p>For many years,
the dance language of the bumblebee eluded all those who studied it.
That is until
a mathematician named Barbara Shipman
made the connection between a bee’s dance language
and the six-dimensional geometry of flag manifolds,
of all things.
What was the unique insight that allowed her to see what others couldn’t?
She grew up in a family of beekeepers
and cultivated an interest in mathematics and biology
that carried throughout her studies.</p>
<p>The leap from furry, buzzing insects to abstract geometry is inconceivable
unless you’re accustomed to looking at the world in that particular way.</p>
<h2>
<a class="anchor" aria-hidden="true" id="the-rose-that-grows-from-the-dunghill" href="#the-rose-that-grows-from-the-dunghill"></a>The Rose that Grows From the Dunghill</h2>
<p>When Apple first announced the Swift programming language in 2014,
it generated a flurry of excitement as we all tried to understand it.
One of the most powerful tools at our disposal for understanding is <em>analogy</em>:</p>
<p><code><var class="placeholder">New Thing</var></code> is like <code><var class="placeholder">Familiar Thing</var></code> crossed with <code><var class="placeholder">Another Thing</var></code>.</p>
<p>So in those early days,
there was a lot of discussion within the community
attempting to compare and contrast Swift with
<a href="https://en.wikipedia.org/wiki/Haskell_(programming_language)" rel="noopener noreferrer">Haskell</a> or <a href="https://en.wikipedia.org/wiki/Go_(programming_language)" rel="noopener noreferrer">Go</a> or <a href="https://en.wikipedia.org/wiki/Python_(programming_language)" rel="noopener noreferrer">Python</a> or <a href="https://en.wikipedia.org/wiki/Scheme_(programming_language)" rel="noopener noreferrer">Scheme</a> or <a href="https://en.wikipedia.org/wiki/Dylan_(programming_language)" rel="noopener noreferrer">Dylan</a>.</p>
<aside class="parenthetical">
<p>Indeed, Apple originally pitched Swift as “Objective-C without the C”.</p>
</aside>
<p>Last year,
we saw something similar with at <a href="/wwdc-2019/">WWDC 2019</a>.
Anyone familiar with <a href="https://en.wikipedia.org/wiki/React_(web_framework)" rel="noopener noreferrer">React</a> or <a href="https://en.wikipedia.org/wiki/Elm_(programming_language)" rel="noopener noreferrer">Elm</a>
immediately recognized their influence on
<a href="https://developer.apple.com/xcode/swiftui/" rel="noopener noreferrer">SwiftUI</a> and <a href="https://developer.apple.com/documentation/combine" rel="noopener noreferrer">Combine</a>
(even if Apple hadn’t come out and acknowledged it explicitly).</p>
<p>For some,
the connection between React and Elm with JavaScript
is an inconvenient truth.
I’ve seen numerous developers profess their disdain for the language
in ways that echo the old rivalry between iOS and Android
(or the even older rivalry between <a href="https://en.wikipedia.org/wiki/Get_a_Mac" rel="noopener noreferrer">Mac and PC</a>).</p>
<p>And yet,
there are countless examples of good ideas from <em>“them”</em>
being criticized and mocked until they’re incorporated into an Apple product:</p>
<ul>
<li>
<kbd title="alt">⌥</kbd><kbd title="tab">⇥</kbd> app switching on Windows
(<kbd title="command">⌘</kbd><kbd title="tab">⇥</kbd> on macOS)</li>
<li>Dark mode in Android
(<a href="/dark-mode/">added in iOS 13</a>)</li>
<li>Generics in Java and other languages
(a core feature in Swift,
<a href="https://developer.apple.com/documentation/swift/imported_c_and_objective-c_apis/using_imported_lightweight_generics_in_swift" rel="noopener noreferrer">later added to Objective-C</a>)</li>
<li>
<a href="https://reactjs.org/docs/introducing-jsx.html" rel="noopener noreferrer">JSX</a>-style <abbr title="domain-specific languages">DSL</abbr>s
declarative UI
(<a href="https://forums.swift.org/t/function-builders/25167" rel="noopener noreferrer">function builders</a> in SwiftUI)</li>
</ul>
<p>All of which begs the question:</p>
<p><em>Why did we consider these good ideas heretical until Apple did it?</em></p>
<h2>
<a class="anchor" aria-hidden="true" id="us-vs-them" href="#us-vs-them"></a>Us vs. Them</h2>
<p>Another flavor of this arises from the dichotomy between “Native” and “Hybrid”.</p>
<aside class="parenthetical">
<p>Often the “other” isn’t even distinguished beyond a negative definition —
“Non-native”.</p>
</aside>
<p>Whenever a company writes some blog post about React Native,
what inevitably follows is chorus of developers who either
praise the decision as courageous (if switching away)
or call it idiotic (if adopting it).</p>
<p>As developers,
we tend to align ourselves with enlightenment ideals like objectivity.
We say that we make decisions based in the indisputable reality of fact.
We consider ourselves reasonable and our decisions well-reasoned.</p>
<p>But to what extent is this actually true?
Do our thoughts lead us to our preferences,
or do we use thoughts to rationalize them after the fact?</p>
<hr><a id="get-on-with-it"></a>
<p>In the 1960s and 70s,
the social psychologist Henri Tajfel and his colleagues
ran a <a href="https://en.wikipedia.org/wiki/Minimal_group_paradigm" rel="noopener noreferrer">series of experiments</a>
that demonstrated how little it takes
for people to engage in intergroup discrimination.</p>
<p>In one experiment,
a group of boys were shown pictures with clusters of dots
and instructed to guess how many there were
as a test of their visual judgment.
The researchers split the group between
those who overestimated or underestimated the number.
Except, they only pretended to do this —
the boys were, in fact, randomly assigned to one of the two groups.
They were then given the task of allocating a fixed amount of real money
to other boys in the study.</p>
<p>The results surprised even the researchers:</p>
<p>Overwhelmingly, the boys chose outcomes where their assigned group
(under- or over-estimators) received more money than their counterparts —
<em>even when that meant getting less overall</em>.</p>
<p>Successful replication of these results in follow-up studies since then
presents compelling evidence of this peculiarity in human nature.
That a willingness to engage in “us vs. them” discrimination
can arise from completely artificial distinctions,
irrespective of any rationale of self-interest.</p>
<hr>
<p><em>How else could you explain the intense tribalism
around how we talk to computers?</em></p>
<h2>
<a class="anchor" aria-hidden="true" id="the-dream-of-purity" href="#the-dream-of-purity"></a>The Dream of Purity</h2>
<p>When a developer proudly declares something to be
“Pure Swift” or “100% JavaScript free”,
what are they really saying?
What’s presented as an objective statement of fact
often feels more like an oath of allegiance.</p>
<p>If you see the existence of competing technologies
as a fight between good and evil,
perhaps there are more important battles to fight.
If you can’t evaluate solutions as a series of trade-offs,
what chance do you have at accomplishing anything at all?</p>
<p>Yes,
there are real differences between technologies
and reasonable people disagree about
which one is best-suited to solve a particular problem.
But don’t mistake this for a moral contest.</p>
<blockquote>
<p>Purity is an ideal;
a vision of the condition which needs yet to be created,
or such as needs to be diligently protected against the genuine or imagined odds.
Without such a vision, neither the concept of purity makes sense,
nor the distinction between purity and impurity can be sensibly drawn.</p>
<p>– Zygmunt Bauman</p>
</blockquote>
<hr>
<p>It’s of no practical consequence that
the grounds on which Apple Park sits today
were fruit orchards a hundred years ago.
But it’s poetic.
Long before it was “Silicon Valley”,
the stretch of land between the San Andreas and Hayward faults
was called “the Valley of Heart’s Delight”
for all of its fruit trees and flowering plants.</p>
<p>Dwelling on this,
you might reflect on how humans are like apple trees.
That we need a variety of different influences to reach our potential.
(Even self-starters benefit from a unique perspective).</p>
<p>You might then consider what we share in common with
the bees that pollinate apple trees.
Like them,
our success comes not from our individual intelligence,
but in our ability to share information.</p>
<p>Whether we’re like bees or like apples,
we come away learning the same lesson:
We can achieve remarkable results by working together.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>A brief essay about the flowering of ideas, written for the occasion of Earth Day.</p>Swift Logging2020-03-26T00:00:00-07:002020-03-26T00:00:00-07:00https://nshipster.com/swift-log
<p>In 2002,
the United States Congress enacted
the <a href="https://en.wikipedia.org/wiki/Sarbanes%E2%80%93Oxley_Act" rel="noopener noreferrer">Sarbanes–Oxley Act</a>,
which introduced broad oversight to corporations
in response to accounting scandals at companies like
<a href="https://en.wikipedia.org/wiki/Enron_scandal" rel="noopener noreferrer">Enron</a> and
<a href="https://en.wikipedia.org/wiki/MCI_Inc.#Accounting_scandals" rel="noopener noreferrer">MCI WorldCom</a>
around that time.
This act,
<a href="https://en.wikipedia.org/wiki/PCI_DSS" rel="noopener noreferrer">
<abbr title="Payment Card Industry Data Security Standard">PCI</abbr>
</a>
and
<a href="https://en.wikipedia.org/wiki/HIPAA" rel="noopener noreferrer">
<abbr title="Health Insurance Portability and Accountability Act">
HIPAA
</abbr>
</a>,
formed the regulatory backdrop
for a new generation of
<abbr title="information technology">IT</abbr> companies
emerging from the <a href="https://en.wikipedia.org/wiki/Dot-com_bubble" rel="noopener noreferrer">dot-com bubble</a>.</p>
<p>Around the same time,
we saw the emergence of ephemeral, distributed infrastructure —
what we now call <a href="https://en.wikipedia.org/wiki/Cloud_computing" rel="noopener noreferrer">“Cloud computing”</a> —
a paradigm that made systems more capable but also more complex.</p>
<p>To solve both the regulatory and logistical challenges of the 21<sup>st</sup> century,
our field established best practices around application logging.
And many of the same tools and standards are still in use today.</p>
<aside class="parenthetical">
<p>Just as <code>print</code> is a poor man’s <a href="https://developer.apple.com/videos/play/wwdc2019/429/" rel="noopener noreferrer">debugger</a>,
it’s also a shallow replacement for a proper logging system,
with distinct log levels and configurable output settings.</p>
</aside>
<aside class="admonition info">
<p><em>Sarbanes–Oxley</em> is notable for giving rise to
<em><a href="https://www.oyez.org/cases/2014/13-7451" rel="noopener noreferrer">Yates v. United States</a></em>:
a delightful Supreme Court case that asked the question
_“Are fish (🐟) tangible objects?”</p>
<p>Although the Court found in a 5 – 4 decision
that fish are <em>not</em>, in fact, “tangible objects”
(for purposes of the statute),
we remain unconvinced
for the same reasons articulated in
<a href="https://supreme.justia.com/cases/federal/us/574/528/#tab-opinion-3243031" rel="noopener noreferrer">Justice Kagan’s dissent</a>
<em>(and pretty much anything written by
<a href="https://en.wikipedia.org/wiki/Claude_Shannon" rel="noopener noreferrer">Claude Shannon</a>,
for that matter)</em>.</p>
</aside>
<hr><a id="get-on-with-it"></a>
<p>This week on NSHipster,
we’re taking a look at
<a href="https://github.com/apple/swift-log" rel="noopener noreferrer"><code>Swift<wbr></wbr>Log</code></a>:
a community-driven, open-source standard for logging in Swift.</p>
<p>Developed by the Swift on Server community
and endorsed by the
<a href="https://swift.org/server/" rel="noopener noreferrer">SSWG (Swift Server Work Group)</a>,
its benefit isn’t limited to use on the server.
Indeed,
any Swift code intended to be run from the command line
would benefit from adopting <code>Swift<wbr></wbr>Log</code>.
Read on to learn how.</p>
<aside class="admonition warning">
<p><code>Swift<wbr></wbr>Log</code> is distinct from the
<a href="https://developer.apple.com/documentation/os/logging" rel="noopener noreferrer">Unified Logging System</a>
(<code>os_log</code>),
which is specific to Apple platforms.</p>
<p>Readers may already be familiar with <code>os_log</code> and its, <em>*ahem*</em>
<a href="https://mjtsai.com/blog/2019/03/06/problems-with-os_log/" rel="noopener noreferrer">quirks</a>
<em>(a topic for a future article, perhaps)</em>.
But for the uninitiated,
all you need to know is that
<code>os_log</code> is for macOS and iOS apps and
<code>Swift<wbr></wbr>Log</code> is for everything else.</p>
<p>If you’re interested in learning more about Unified Logging,
you can get a quick overview of
by skimming the <a href="https://developer.apple.com/documentation/os/logging" rel="noopener noreferrer"><code>os_log</code> docs</a>;
for an in-depth look,
check out
<a href="https://developer.apple.com/videos/play/wwdc2016/721/" rel="noopener noreferrer">“Unified Logging and Activity Tracing”</a>
from WWDC 2016
and
<a href="https://developer.apple.com/videos/play/wwdc2018/405/" rel="noopener noreferrer">“Measuring Performance Using Logging”</a>
from WWDC 2018.</p>
</aside>
<hr>
<p>As always,
an example would be helpful in guiding our discussion.
In the spirit of transparency and nostalgia,
let’s imagine writing a Swift program
that audits the finances of a ’00s Fortune 500 company.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">struct</span> <span class="kt">Auditor</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">watch</span><span class="p">(</span><span class="n">_</span> <span class="nv">directory</span><span class="p">:</span> <span class="kt">URL</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">cleanup</span><span class="p">()</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="p">}</span>
<span class="k">do</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">auditor</span> <span class="o">=</span> <span class="kt">Auditor</span><span class="p">()</span>
<span class="k">defer</span> <span class="p">{</span> <span class="n">auditor</span><span class="o">.</span><span class="nf">cleanup</span><span class="p">()</span> <span class="p">}</span>
<span class="k">try</span> <span class="n">auditor</span><span class="o">.</span><span class="nf">watch</span><span class="p">(</span><span class="nv">directory</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"ftp://<var class="placeholder">…</var>/reports"</span><span class="p">)</span><span class="o">!</span><span class="p">,</span>
<span class="nv">extensions</span><span class="p">:</span> <span class="p">[</span><span class="s">"xls"</span><span class="p">,</span> <span class="s">"ods"</span><span class="p">,</span> <span class="s">"qdf"</span><span class="p">])</span> <span class="c1">// poll for changes</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="s">"error: </span><span class="se">\(</span><span class="n">error</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>An <code>Auditor</code> type polls for changes to a directory
<em>(an FTP server, because remember: it’s 2003)</em>.
Each time a file is added, removed, or changed,
its contents are audited for discrepancies.
If any financial oddities are encountered,
they’re logged using the <code>print</code> function.
The same goes for issues connecting to the FTP,
or any other problems the program might encounter —
everything’s logged using <code>print</code>.</p>
<aside class="parenthetical">
<p>The implementation details aren’t important;
only the interface is relevant to our discussion.</p>
</aside>
<p>Simple enough.
We can run it from the command line like so:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">starting up...
ERROR: unable to reconnect to FTP
</span><span class="gp">#</span><span class="w"> </span><span class="o">(</span>try again after restarting PC under our desk<span class="o">)</span>
<span class="go">
</span><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">+ connected to FTP server
! accounting discrepancy in balance sheet
** Quicken database corruption! **
^C
shutting down...
</span></code></pre>
<p>Such a program might be technically compliant,
but it leaves a lot of room for improvement:</p>
<ul>
<li>For one,
our output doesn’t have any timestamps associated with it.
There’s no way to know whether a problem was detected an hour ago or last week.</li>
<li>Another problem is that our output lacks any coherent structure.
At a glance,
there’s no straightforward way to isolate program noise from real issues.</li>
<li>Finally, —
<em>and this is mostly due to an under-specified example</em> —
it’s unclear how this output is handled.
Where is this output going?
How is it collected, aggregated, and analyzed?</li>
</ul>
<hr>
<p>The good news is that
all of these problems (and many others) can be solved
by adopting a formal logging infrastructure in your project.</p>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="adopting-swiftlog-in-your-swift-program" href="#adopting-swiftlog-in-your-swift-program"></a>Adopting SwiftLog in Your Swift Program</h2>
<p>Adding <code>Swift<wbr></wbr>Log</code> to an existing Swift package is a breeze.
You can incorporate it incrementally
without making any fundamental changes to your code
and have it working in a matter of minutes.</p>
<h3>
<a class="anchor" aria-hidden="true" id="add-swift-log-as-a-package-dependency" href="#add-swift-log-as-a-package-dependency"></a>Add swift-log as a Package Dependency</h3>
<p>In your <code>Package.swift</code> manifest,
add <code>swift-log</code> as a package dependency and
add the <code>Logging</code> module to your target’s list of dependencies.</p>
<pre class="highlight" data-lang="Swift"><code><span class="c1">// swift-tools-version:5.1</span>
<span class="kd">import</span> <span class="kt">Package<wbr></wbr>Description</span>
<span class="k">let</span> <span class="nv">package</span> <span class="o">=</span> <span class="kt">Package</span><span class="p">(</span>
<span class="nv">name</span><span class="p">:</span> <span class="s">"Auditor2000"</span><span class="p">,</span>
<span class="nv">products</span><span class="p">:</span> <span class="p">[</span>
<span class="o">.</span><span class="nf">executable</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"audit"</span><span class="p">,</span> <span class="nv">targets</span><span class="p">:</span> <span class="p">[</span><span class="s">"audit"</span><span class="p">])</span>
<span class="p">],</span>
<span class="nv">dependencies</span><span class="p">:</span> <span class="p">[</span>
<span class="o">.</span><span class="nf">package</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="s">"https://github.com/apple/swift-log.git"</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="s">"1.2.0"</span><span class="p">),</span>
<span class="p">],</span>
<span class="nv">targets</span><span class="p">:</span> <span class="p">[</span>
<span class="o">.</span><span class="nf">target</span><span class="p">(</span><span class="nv">name</span><span class="p">:</span> <span class="s">"audit"</span><span class="p">,</span> <span class="nv">dependencies</span><span class="p">:</span> <span class="p">[</span><span class="s">"Logging"</span><span class="p">])</span>
<span class="p">]</span>
<span class="p">)</span>
</code></pre>
<h3>
<a class="anchor" aria-hidden="true" id="create-a-shared-global-logger" href="#create-a-shared-global-logger"></a>Create a Shared, Global Logger</h3>
<p><code>Logger</code> provides two initializers,
the simpler of them taking a single <code>label</code> parameter:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"com.NSHipster.Auditor2000"</span><span class="p">)</span>
</code></pre>
<p>In <a href="https://en.wikipedia.org/wiki/POSIX" rel="noopener noreferrer">POSIX</a> systems,
programs operate on three, predefined
<a href="https://en.wikipedia.org/wiki/Standard_streams" rel="noopener noreferrer">streams</a>:</p>
<table>
<thead>
<tr>
<th>File Handle</th>
<th>Description</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr>
<td>0</td>
<td><code>stdin</code></td>
<td>Standard Input</td>
</tr>
<tr>
<td>1</td>
<td><code>stdout</code></td>
<td>Standard Output</td>
</tr>
<tr>
<td>2</td>
<td><code>stderr</code></td>
<td>Standard Error</td>
</tr>
</tbody>
</table>
<p>By default,
<code>Logger</code> uses the built-in <code>Stream<wbr></wbr>Log<wbr></wbr>Handler</code> type
to write logged messages to standard output (<code>stdout</code>).
We can override this behavior to instead write to standard error (<code>stderr</code>)
by using the more complex initializer,
which takes a <code>factory</code> parameter:
a closure that takes a single <code>String</code> parameter (the label)
and returns an object conforming to <code>Log<wbr></wbr>Handler</code>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"com.NSHipster.Auditor2000"</span><span class="p">,</span>
<span class="nv">factory</span><span class="p">:</span> <span class="kt">Stream<wbr></wbr>Log<wbr></wbr>Handler</span><span class="o">.</span><span class="n">standard<wbr></wbr>Error</span><span class="p">)</span>
</code></pre>
<aside class="admonition info">
<p>Alternatively,
you can set default logger globally
using the <code>Logging<wbr></wbr>System.bootstrap()</code> method.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kt">Logging<wbr></wbr>System</span><span class="o">.</span><span class="nf">bootstrap</span><span class="p">(</span><span class="kt">Stream<wbr></wbr>Log<wbr></wbr>Handler</span><span class="o">.</span><span class="n">standard<wbr></wbr>Error</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"com.NSHipster.Auditor2000"</span><span class="p">)</span>
</code></pre>
<p>After doing this,
any subsequent <code>Logger</code> instances created
using the <code>Logger(label:)</code> initializer
will default to the specified handler.</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="replacing-print-statements-with-logging-statements" href="#replacing-print-statements-with-logging-statements"></a>Replacing Print Statements with Logging Statements</h3>
<p>Declaring our <code>logger</code> as a top-level constant
lets us call it anywhere within our module.
Let’s revisit our example and spruce it up with our new logger:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">do</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">auditor</span> <span class="o">=</span> <span class="kt">Auditor</span><span class="p">()</span>
<span class="k">defer</span> <span class="p">{</span>
<span class="n">logger</span><span class="o">.</span><span class="nf">trace</span><span class="p">(</span><span class="s">"Shutting down"</span><span class="p">)</span>
<span class="n">auditor</span><span class="o">.</span><span class="nf">cleanup</span><span class="p">()</span>
<span class="p">}</span>
<span class="n">logger</span><span class="o">.</span><span class="nf">trace</span><span class="p">(</span><span class="s">"Starting up"</span><span class="p">)</span>
<span class="k">try</span> <span class="n">auditor</span><span class="o">.</span><span class="nf">watch</span><span class="p">(</span><span class="nv">directory</span><span class="p">:</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"ftp://<var class="placeholder">…</var>/reports"</span><span class="p">)</span><span class="o">!</span><span class="p">,</span>
<span class="nv">extensions</span><span class="p">:</span> <span class="p">[</span><span class="s">"xls"</span><span class="p">,</span> <span class="s">"ods"</span><span class="p">,</span> <span class="s">"qdf"</span><span class="p">])</span> <span class="c1">// poll for changes</span>
<span class="p">}</span> <span class="k">catch</span> <span class="p">{</span>
<span class="n">logger</span><span class="o">.</span><span class="nf">critical</span><span class="p">(</span><span class="s">"</span><span class="se">\(</span><span class="n">error</span><span class="se">)</span><span class="s">"</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>The <code>trace</code>, <code>debug</code>, and <code>critical</code> methods
log a message at their respective <dfn>log level</dfn>.
<code>Swift<wbr></wbr>Log</code> defines seven levels,
ranked in ascending order of severity from <code>trace</code> to <code>critical</code>:</p>
<table id="log-levels">
<thead>
<tr>
<th>Level</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr id="log-level-trace">
<td><code>.trace</code></td>
<td>Appropriate for messages that contain information only when debugging a program.</td>
</tr>
<tr id="log-level-debug">
<td><code>.debug</code></td>
<td>Appropriate for messages that contain information normally of use only when debugging a program.</td>
</tr>
<tr id="log-level-info">
<td><code>.info</code></td>
<td>Appropriate for informational messages.</td>
</tr>
<tr id="log-level-notice">
<td><code>.notice</code></td>
<td>Appropriate for conditions that are not error conditions, but that may require special handling.</td>
</tr>
<tr id="log-level-warning">
<td><code>.warning</code></td>
<td>Appropriate for messages that are not error conditions, but more severe than <code>.notice</code>
</td>
</tr>
<tr id="log-level-error">
<td><code>.error</code></td>
<td>Appropriate for error conditions.</td>
</tr>
<tr id="log-level-critical">
<td><code>.critical</code></td>
<td>Appropriate for critical error conditions that usually require immediate attention.</td>
</tr>
</tbody>
</table>
<p>If we re-run our <code>audit</code> example with our new logging framework in place,
we can see the immediate benefit of clearly-labeled, distinct severity levels
in log lines:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">2020-03-26T09:40:10-0700 critical: Couldn't connect to ftp://<var class="placeholder">…</var>
</span><span class="gp">#</span><span class="w"> </span><span class="o">(</span>try again after plugging <span class="k">in </span>loose ethernet cord<span class="o">)</span>
<span class="go">
</span><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">2020-03-26T10:21:22-0700 warning: Discrepancy in balance sheet
2020-03-26T10:21:22-0700 error: Quicken database corruption
^C
</span></code></pre>
<p>Beyond merely labeling messages,
<em>which — don’t get us wrong — is sufficient benefit on its own</em>,
log levels provide a configurable level of disclosure.
Notice that the messages logged with the <code>trace</code> method
don’t appear in the example output.
That’s because <code>Logger</code> defaults to showing only messages
logged as <code>info</code> level or higher.</p>
<p>You can configure that by setting the <code>Logger</code>’s <code>log<wbr></wbr>Level</code> property.</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">var</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"com.NSHipster.Auditor2000"</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="n">log<wbr></wbr>Level</span> <span class="o">=</span> <span class="o">.</span><span class="n">trace</span>
</code></pre>
<p>After making this change,
the example output would instead look something like this:</p>
<pre class="highlight" data-lang="Terminal"><code><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">2020-03-25T09:40:00-0700 trace: Starting up
2020-03-26T09:40:10-0700 critical: Couldn't connect to ftp://<var class="placeholder">…</var>
2020-03-25T09:40:11-0700 trace: Shutting down
</span><span class="gp">#</span><span class="w"> </span><span class="o">(</span>try again after plugging <span class="k">in </span>loose ethernet cord<span class="o">)</span>
<span class="go">
</span><span class="gp">$</span><span class="w"> </span>swift run audit
<span class="go">2020-03-25T09:41:00-0700 trace: Starting up
2020-03-26T09:41:01-0700 debug: Connected to ftp://<var class="placeholder">…</var>/reports
2020-03-26T09:41:01-0700 debug: Watching file extensions ["xls", "ods", "qdf"]
2020-03-26T10:21:22-0700 warning: Discrepancy in balance sheet
2020-03-26T10:21:22-0700 error: Quicken database corruption
^C
2020-03-26T10:30:00-0700 trace: Shutting down
</span></code></pre>
<h2>
<a class="anchor" aria-hidden="true" id="using-multiple-logging-handlers-at-once" href="#using-multiple-logging-handlers-at-once"></a>Using Multiple Logging Handlers at Once</h2>
<p>Thinking back to our objections in the original example,
the only remaining concern
is what we actually <em>do</em> with these logs.</p>
<p>According to <a href="https://12factor.net/logs" rel="noopener noreferrer">12 Factor App</a> principles:</p>
<blockquote>
<h2>
<a class="anchor" aria-hidden="true" id="xi-logs" href="#xi-logs"></a>XI. Logs</h2>
<p><em>[…]</em></p>
<p><strong>A twelve-factor app never concerns itself with
routing or storage of its output stream.</strong>
It should not attempt to write to or manage logfiles.
Instead, each running process writes its event stream, unbuffered, to <code>stdout</code>.</p>
</blockquote>
<p>Collecting, routing, indexing, and analyzing logs across a distributed system
often requires a constellation of open-source libraries and commercial products.
Fortunately,
most of these components traffic in a shared currency of
<a href="https://en.wikipedia.org/wiki/Syslog" rel="noopener noreferrer">syslog</a> messages —
and thanks to
<a href="https://github.com/ianpartridge/swift-log-syslog" rel="noopener noreferrer">this package by Ian Partridge</a>,
Swift can, as well.</p>
<p>That said,
few engineers have managed to retrieve this information
from the likes of <a href="https://www.splunk.com" rel="noopener noreferrer">Splunk</a>
and lived to tell the tale.
For us mere mortals,
we might prefer
<a href="https://github.com/wlisac/swift-log-slack" rel="noopener noreferrer">this package by Will Lisac</a>,
which sends log messages to
<a href="https://slack.com" rel="noopener noreferrer">Slack</a>.</p>
<p>The good news is that we can use both at once,
without changing how messages are logged at the call site
by using another piece of the <code>Logging</code> module:
<code>Multiplex<wbr></wbr>Log<wbr></wbr>Handler</code>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kd">struct</span> <span class="kt">Foundation</span><span class="o">.</span><span class="kt">Process<wbr></wbr>Info</span>
<span class="kd">import</span> <span class="kt">Logging</span>
<span class="kd">import</span> <span class="kt">Logging<wbr></wbr>Syslog</span>
<span class="kd">import</span> <span class="kt">Logging<wbr></wbr>Slack</span>
<span class="kt">Logging<wbr></wbr>System</span><span class="o">.</span><span class="n">bootstrap</span> <span class="p">{</span> <span class="n">label</span> <span class="k">in</span>
<span class="k">let</span> <span class="nv">webhook<wbr></wbr>URL</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span>
<span class="kt">Process<wbr></wbr>Info</span><span class="o">.</span><span class="n">process<wbr></wbr>Info</span><span class="o">.</span><span class="n">environment</span><span class="p">[</span><span class="s">"SLACK_LOGGING_WEBHOOK_URL"</span><span class="p">]</span><span class="o">!</span>
<span class="p">)</span><span class="o">!</span>
<span class="k">var</span> <span class="nv">slack<wbr></wbr>Handler</span> <span class="o">=</span> <span class="kt">Slack<wbr></wbr>Log<wbr></wbr>Handler</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="n">label</span><span class="p">,</span> <span class="nv">webhook<wbr></wbr>URL</span><span class="p">:</span> <span class="n">webhook<wbr></wbr>URL</span><span class="p">)</span>
<span class="n">slack<wbr></wbr>Handler</span><span class="o">.</span><span class="n">log<wbr></wbr>Level</span> <span class="o">=</span> <span class="o">.</span><span class="n">critical</span>
<span class="k">let</span> <span class="nv">syslog<wbr></wbr>Handler</span> <span class="o">=</span> <span class="kt">Syslog<wbr></wbr>Log<wbr></wbr>Handler</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="n">label</span><span class="p">)</span>
<span class="k">return</span> <span class="kt">Multiplex<wbr></wbr>Log<wbr></wbr>Handler</span><span class="p">([</span>
<span class="n">syslog<wbr></wbr>Handler</span><span class="p">,</span>
<span class="n">slack<wbr></wbr>Handler</span>
<span class="p">])</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="s">"com.NSHipster.Auditor2000"</span><span class="p">)</span>
</code></pre>
<aside class="parenthetical">
<p>Harkening to <a href="https://12factor.net/config" rel="noopener noreferrer">another 12 Factor principle</a>,
we pull the webhook URL from an environment variable rather than hard-coding it.</p>
</aside>
<p>With all of this in place,
our system will log everything in syslog format to standard out (<code>stdout</code>),
where it can be collected and analyzed by some other system.</p>
<hr>
<p>But the real strength of this approach to logging
is that it can be extended to meet the specific needs of any environment.
Instead of writing syslog to <code>stdout</code> or Slack messages,
your system could send emails,
open SalesForce tickets,
or trigger a webhook to activate some
<abbr title="Internet of Things">IoT</abbr> device.</p>
<aside class="parenthetical">
<p>Granted, each of those examples would probably be better served
by a separate monitoring service that ingests a log stream
and reacts to events according to a more elaborate set of rules.</p>
</aside>
<p>Here’s how you can extend <code>Swift<wbr></wbr>Log</code> to fit your needs
by writing a custom log handler:</p>
<h2>
<a class="anchor" aria-hidden="true" id="creating-a-custom-log-handler" href="#creating-a-custom-log-handler"></a>Creating a Custom Log Handler</h2>
<p>The <code>Log<wbr></wbr>Handler</code> protocol specifies the requirements for types
that can be registered as message handlers by <code>Logger</code>:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">protocol</span> <span class="kt">Log<wbr></wbr>Handler</span> <span class="p">{</span>
<span class="nf">subscript</span><span class="p">(</span><span class="n">metadata<wbr></wbr>Key</span> <span class="nv">_</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Metadata</span><span class="o">.</span><span class="kt">Value</span><span class="p">?</span> <span class="p">{</span> <span class="k">get</span> <span class="k">set</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">metadata</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Metadata</span> <span class="p">{</span> <span class="k">get</span> <span class="k">set</span> <span class="p">}</span>
<span class="k">var</span> <span class="nv">log<wbr></wbr>Level</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Level</span> <span class="p">{</span> <span class="k">get</span> <span class="k">set</span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">log</span><span class="p">(</span><span class="nv">level</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Level</span><span class="p">,</span>
<span class="nv">message</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Message</span><span class="p">,</span>
<span class="nv">metadata</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Metadata</span><span class="p">?,</span>
<span class="nv">file</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">function</span><span class="p">:</span> <span class="kt">String</span><span class="p">,</span> <span class="nv">line</span><span class="p">:</span> <span class="kt">UInt</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>In the process of writing this article,
I created <a href="https://github.com/NSHipster/swift-log-github-actions" rel="noopener noreferrer">custom handler</a>
that formats log messages for GitHub Actions
so that they’re surfaced on GitHub’s UI like so:</p>
<p><img src="/assets/github-actions-ui-3fe079aeea203a7d579a873d74ef310d9d4cfb9522604675179a9ddb243756e0bd269aa4472ab82ccb9712f33f513aae528112cbabec46ad7b6072c329be00a4.png" integrity="sha512-P+B5ruogOn1Xmoc9dO8xDZ1M+5UiYEZ1F5qd2yQ3VuC9JpqkRyq4LMuXEvM/UTquUoESy6vsRq17YHLDKb4ApA==" crossorigin="anonymous" alt=""></p>
<aside class="admonition info">
<p>For more information,
see
<a href="https://help.github.com/en/actions/reference/workflow-commands-for-github-actions" rel="noopener noreferrer">“Workflow commands for GitHub Actions.”</a></p>
</aside>
<p>If you’re interested in making your own logging handler,
you can learn a lot by just browsing
<a href="https://github.com/NSHipster/swift-log-github-actions" rel="noopener noreferrer">the code for this project</a>.
But I did want to call out a few points of interest here:</p>
<h3>
<a class="anchor" aria-hidden="true" id="conditional-boostrapping" href="#conditional-boostrapping"></a>Conditional Boostrapping</h3>
<p>When bootstrapping your logging system,
you can define some logic for how things are configured.
For logging formatters specific to a particular CI vendor,
for example,
you might check the environment to see if you’re running locally or on CI
and adjust accordingly.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Logging</span>
<span class="kd">import</span> <span class="kt">Logging<wbr></wbr>Git<wbr></wbr>Hub<wbr></wbr>Actions</span>
<span class="kd">import</span> <span class="kd">struct</span> <span class="kt">Foundation</span><span class="o">.</span><span class="kt">Process<wbr></wbr>Info</span>
<span class="kt">Logging<wbr></wbr>System</span><span class="o">.</span><span class="n">bootstrap</span> <span class="p">{</span> <span class="n">label</span> <span class="k">in</span>
<span class="c1">// Are we running in a Git<wbr></wbr>Hub Actions workflow?</span>
<span class="k">if</span> <span class="kt">Process<wbr></wbr>Info</span><span class="o">.</span><span class="n">process<wbr></wbr>Info</span><span class="o">.</span><span class="n">environment</span><span class="p">[</span><span class="s">"GITHUB_ACTIONS"</span><span class="p">]</span> <span class="o">==</span> <span class="s">"true"</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Git<wbr></wbr>Hub<wbr></wbr>Actions<wbr></wbr>Log<wbr></wbr>Handler</span><span class="o">.</span><span class="nf">standard<wbr></wbr>Output</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="n">label</span><span class="p">)</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Stream<wbr></wbr>Log<wbr></wbr>Handler</span><span class="o">.</span><span class="nf">standard<wbr></wbr>Output</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="n">label</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<h3>
<a class="anchor" aria-hidden="true" id="testing-custom-log-handlers" href="#testing-custom-log-handlers"></a>Testing Custom Log Handlers</h3>
<p>Testing turned out to be more of a challenge than originally anticipated.
I could be missing something obvious,
but there doesn’t seem to be a way to create assertions about
text written to standard output.
So here’s what I did instead:</p>
<p>First,
create an <code>internal</code> initializer that takes a <code>Text<wbr></wbr>Output<wbr></wbr>Stream</code> parameter,
and store it in a <code>private</code> property.</p>
<aside class="parenthetical">
<p>Swift symbols have <code>internal</code> access control by default;
the keyword is included here for clarity.</p>
</aside>
<pre class="highlight" data-lang="Swift"><code><span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Git<wbr></wbr>Hub<wbr></wbr>Actions<wbr></wbr>Log<wbr></wbr>Handler</span><span class="p">:</span> <span class="kt">Log<wbr></wbr>Handler</span> <span class="p">{</span>
<span class="kd">private</span> <span class="k">var</span> <span class="nv">output<wbr></wbr>Stream</span><span class="p">:</span> <span class="kt">Text<wbr></wbr>Output<wbr></wbr>Stream</span>
<span class="kd">internal</span> <span class="nf">init</span><span class="p">(</span><span class="nv">output<wbr></wbr>Stream</span><span class="p">:</span> <span class="kt">Text<wbr></wbr>Output<wbr></wbr>Stream</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">output<wbr></wbr>Stream</span> <span class="o">=</span> <span class="n">output<wbr></wbr>Stream</span>
<span class="p">}</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="p">}</span>
</code></pre>
<p>Then,
in the test target,
create a type that adopts <code>Text<wbr></wbr>Output<wbr></wbr>Stream</code>
and collects logged messages to a stored property
for later inspection.
By using a
<a href="https://docs.swift.org/swift-book/LanguageGuide/AccessControl.html#ID5" rel="noopener noreferrer"><code>@testable import</code></a>
of the module declaring <code>Git<wbr></wbr>Hub<wbr></wbr>Actions<wbr></wbr>Log<wbr></wbr>Handler</code>,
we can access that <code>internal</code> initializer from before,
and pass an instance of <code>Mock<wbr></wbr>Text<wbr></wbr>Output<wbr></wbr>Stream</code> to intercept logged messages.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Logging</span>
<span class="kd">@testable</span> <span class="kd">import</span> <span class="kt">Logging<wbr></wbr>Git<wbr></wbr>Hub<wbr></wbr>Actions</span>
<span class="kd">final</span> <span class="kd">class</span> <span class="kt">Mock<wbr></wbr>Text<wbr></wbr>Output<wbr></wbr>Stream</span><span class="p">:</span> <span class="kt">Text<wbr></wbr>Output<wbr></wbr>Stream</span> <span class="p">{</span>
<span class="kd">public</span> <span class="kd">private(set)</span> <span class="k">var</span> <span class="nv">lines</span><span class="p">:</span> <span class="p">[</span><span class="kt">String</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="kd">public</span> <span class="nf">init</span><span class="p">(</span><span class="n">_</span> <span class="nv">body</span><span class="p">:</span> <span class="p">(</span><span class="kt">Logger</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span><span class="p">)</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">logger</span> <span class="o">=</span> <span class="kt">Logger</span><span class="p">(</span><span class="nv">label</span><span class="p">:</span> <span class="kd">#file</span><span class="p">)</span> <span class="p">{</span> <span class="n">label</span> <span class="k">in</span>
<span class="kt">Git<wbr></wbr>Hub<wbr></wbr>Actions<wbr></wbr>Log<wbr></wbr>Handler</span><span class="p">(</span><span class="nv">output<wbr></wbr>Stream</span><span class="p">:</span> <span class="k">self</span><span class="p">)</span>
<span class="p">}</span>
<span class="nf">body</span><span class="p">(</span><span class="n">logger</span><span class="p">)</span>
<span class="p">}</span>
<span class="c1">// MARK: - Text<wbr></wbr>Output<wbr></wbr>Stream</span>
<span class="kd">func</span> <span class="nf">write</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
<span class="n">lines</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>With these pieces in place,
we can finally test that our handler works as expected:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">func</span> <span class="nf">test<wbr></wbr>Logging</span><span class="p">()</span> <span class="p">{</span>
<span class="k">var</span> <span class="nv">log<wbr></wbr>Level</span><span class="p">:</span> <span class="kt">Logger</span><span class="o">.</span><span class="kt">Level</span><span class="p">?</span>
<span class="k">let</span> <span class="nv">expectation</span> <span class="o">=</span> <span class="kt">Mock<wbr></wbr>Text<wbr></wbr>Output<wbr></wbr>Stream</span> <span class="p">{</span> <span class="n">logger</span> <span class="k">in</span>
<span class="n">log<wbr></wbr>Level</span> <span class="o">=</span> <span class="n">logger</span><span class="o">.</span><span class="n">handler</span><span class="o">.</span><span class="n">log<wbr></wbr>Level</span>
<span class="n">logger</span><span class="o">.</span><span class="nf">trace</span><span class="p">(</span><span class="s">"🥱"</span><span class="p">)</span>
<span class="n">logger</span><span class="o">.</span><span class="nf">error</span><span class="p">(</span><span class="s">"😱"</span><span class="p">)</span>
<span class="p">}</span>
<span class="kt">XCTAssert<wbr></wbr>Greater<wbr></wbr>Than</span><span class="p">(</span><span class="n">log<wbr></wbr>Level</span><span class="o">!</span><span class="p">,</span> <span class="o">.</span><span class="n">trace</span><span class="p">)</span>
<span class="kt">XCTAssert<wbr></wbr>Equal</span><span class="p">(</span><span class="n">expectation</span><span class="o">.</span><span class="n">lines</span><span class="o">.</span><span class="n">count</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// trace log is ignored</span>
<span class="kt">XCTAssert<wbr></wbr>True</span><span class="p">(</span><span class="n">expectation</span><span class="o">.</span><span class="n">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="nf">has<wbr></wbr>Prefix</span><span class="p">(</span><span class="s">"::error "</span><span class="p">))</span>
<span class="kt">XCTAssert<wbr></wbr>True</span><span class="p">(</span><span class="n">expectation</span><span class="o">.</span><span class="n">lines</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="nf">has<wbr></wbr>Suffix</span><span class="p">(</span><span class="s">"::😱"</span><span class="p">))</span>
<span class="p">}</span>
</code></pre>
<aside class="admonition warning">
<p>As to how or where messages are logged,
<code>Swift<wbr></wbr>Log</code> is surprisingly tight-lipped.
There’s <a href="https://github.com/apple/swift-log/blob/0e21dd789300fc37a43019fba68b4e97c9938142/Sources/Logging/Logging.swift#L524-L550" rel="noopener noreferrer">an internal type</a> that buffers writes to <code>stdout</code>,
but it’s not exposed by the module.</p>
<p>If you’re in search for a replacement
and would prefer not to copy-paste something as involved as that,
here’s a dead-simple alternative:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Standard<wbr></wbr>Text<wbr></wbr>Output<wbr></wbr>Stream</span><span class="p">:</span> <span class="kt">Text<wbr></wbr>Output<wbr></wbr>Stream</span> <span class="p">{</span>
<span class="k">mutating</span> <span class="kd">func</span> <span class="nf">write</span><span class="p">(</span><span class="n">_</span> <span class="nv">string</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="p">{</span>
<span class="nf">print</span><span class="p">(</span><span class="n">string</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</aside>
<link rel="stylesheet" type="text/css" href="/assets/articles/swift-log-63f365f3c278a66a407f650a805341b0443ead7da0083a4b0def8e70e1c6bc7d7956e702e9527153fc2b691d104972879b8b4e15db80f4b3d23e0c918cd79fcb.css" integrity="sha512-Y/Nl88J4pmpAf2UKgFNBsEQ+rX2gCDpLDe+OcOHGvH15VucC6VJxU/wraR0QSXKHm4tOFduA9LPSPgyRjNefyw==" crossorigin="anonymous">
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>Developed by the Swift on Server community, its benefit isn’t limited to use on the server. Indeed, any Swift code intended to be run from the command line would benefit from adopting SwiftLog.</p>Xcode Build Configuration Files2020-02-27T00:00:00-08:002020-02-27T00:00:00-08:00https://nshipster.com/xcconfig
<p>Software development best practices
<a href="https://12factor.net/config" rel="noopener noreferrer">prescribe</a>
strict separation of configuration from code.
Yet developers on Apple platforms
often struggle to square these guidelines with Xcode’s project-heavy workflow.</p>
<p>Understanding what each project setting does
and how they all interact with one another
is a skill that can take years to hone.
And the fact that much of this information
is buried deep within the GUIs of Xcode does us no favors.</p>
<p>Navigate to the “Build Settings” tab of the project editor,
and you’ll be greeted by <em>hundreds</em> of build settings
spread across layers of projects, targets, and configurations —
<em>and that’s to say nothing of the other six tabs!</em></p>
<picture>
<source srcset="/assets/xcconfig-project-build-settings--dark-8589b42a218f36c38e2cac91333236000b18919491d3d00a2140005d045317062f4bad94bdcc5e16aaabedb79f4168edb4503c83cc9163f26cbb279d10a58d3e.png" media="(prefers-color-scheme: dark)"></source>
<img src="/assets/xcconfig-project-build-settings--light-4c8624f6a37113dc51e85964be85519b079d44118061f753d15764a6124f92c1ece20d536c077bf64f5ba183604947a68d603aad9a0c6da7481db34fbbf26a6f.png" alt="Xcode build settings">
</picture>
<p>Fortunately,
there’s a better way to manage all of this configuration
that doesn’t involve clicking through a maze of tabs and disclosure arrows.</p>
<p>This week,
we’ll show you how you can use text-based <code>xcconfig</code> files
to externalize build settings from Xcode
to make your projects more compact, comprehensible, and powerful.</p>
<aside class="admonition info">
<p>Check out <a href="https://xcodebuildsettings.com" rel="noopener noreferrer">XcodeBuildSettings.com</a>
for a complete reference of every build setting
supported for the latest version of Xcode.</p>
</aside>
<hr><a id="get-on-with-it"></a>
<p><a href="https://help.apple.com/xcode/mac/current/#/dev745c5c974" rel="noopener noreferrer">Xcode build configuration files</a>,
more commonly known by their <code>xcconfig</code> file extension,
allow build settings for your app to be declared and managed without Xcode.
They’re plain text,
which means they’re much friendlier to source control systems
and can be modified with any editor.</p>
<p>Fundamentally,
each configuration file consists of a sequence of key-value assignments
with the following syntax:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><var class="placeholder">BUILD_SETTING_NAME</var> <span class="o">=</span> <var class="placeholder">value</var>
</code></pre>
<p>For example,
to specify the Swift language version for a project,
you’d specify the <code>SWIFT_VERSION</code> build setting like so:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="err">SWIFT_VERSION</span> <span class="o">=</span> <span class="err">5.0</span>
</code></pre>
<aside class="admonition info">
<p>According to the <a href="http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08" rel="noopener noreferrer"><abbr title="Portable Operating System Interface">POSIX</abbr> standard</a>
environment variables have names consisting solely of
uppercase letters, digits, and underscore (<code>_</code>) —
a convention I like to call <code>SCREAMING_SNAKE_CASE</code> 🐍🗯.</p>
</aside>
<hr>
<p>At first glance,
<code>xcconfig</code> files bear a striking resemblance to <code>.env</code> files,
with their simple, newline-delimited syntax.
But there’s more to Xcode build configuration files than meets the eye.
<em>Behold!</em></p>
<h3>
<a class="anchor" aria-hidden="true" id="retaining-existing-values" href="#retaining-existing-values"></a>Retaining Existing Values</h3>
<p>To append rather than replace existing definitions,
use the <code>$(inherited)</code> variable like so:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><var class="placeholder">BUILD_SETTING_NAME</var> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span><var class="placeholder">additional value</var>
</code></pre>
<p>You typically do this to build up lists of values,
such as the paths in which
the compiler searches for frameworks
to find included header files
(<code>FRAMEWORK_SEARCH_PATHS</code>):</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="err">FRAMEWORK_SEARCH_PATHS</span> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span> <span class="si">$(</span><span class="err">PROJECT_DIR</span><span class="si">)</span>
</code></pre>
<p>Xcode assigns inherited values in the following order
(from lowest to highest precedence):</p>
<ul>
<li>Platform Defaults</li>
<li>Xcode Project xcconfig File</li>
<li>Xcode Project File Build Settings</li>
<li>Target xcconfig File</li>
<li>Target Build Settings</li>
</ul>
<aside class="admonition info">
<p>Spaces are used to delimit items in string and path lists.
To specify an item containing whitespace,
you must enclose it with quotation marks (<code>"</code>).</p>
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="referencing-values" href="#referencing-values"></a>Referencing Values</h3>
<p>You can substitute values from other settings
by their declaration name
with the following syntax:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><var class="placeholder">BUILD_SETTING_NAME</var> <span class="o">=</span> <span class="si">$(</span><var class="placeholder">ANOTHER_BUILD_SETTING_NAME</var><span class="si">)</span>
</code></pre>
<p>Substitutions can be used to
define new variables according to existing values,
or inline to build up new values dynamically.</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="err">OBJROOT</span> <span class="o">=</span> <span class="si">$(</span><span class="err">SYMROOT</span><span class="si">)</span>
<span class="err">CONFIGURATION_BUILD_DIR</span> <span class="o">=</span> <span class="si">$(</span><span class="err">BUILD_DIR</span><span class="si">)</span><span class="err">/</span><span class="si">$(</span><span class="err">CONFIGURATION</span><span class="si">)</span><span class="err">-</span><span class="si">$(</span><span class="err">PLATFORM_NAME</span><span class="si">)</span>
</code></pre>
<h3>
<a class="anchor" aria-hidden="true" id="setting-fallback-values-for-referenced-build-settings" href="#setting-fallback-values-for-referenced-build-settings"></a>Setting Fallback Values for Referenced Build Settings</h3>
<p>In Xcode 11.4 and later,
you can use the <code>default</code> evaluation operator
to specify a fallback value to use
if the referenced build setting evaluates as empty.</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="si">$(</span><var class="placeholder">BUILD_SETTING_NAME</var><span class="p">:</span><span class="err">default</span><span class="o">=</span><var class="placeholder">value</var><span class="si">)</span>
</code></pre>
<h3>
<a class="anchor" aria-hidden="true" id="conditionalizing-build-settings" href="#conditionalizing-build-settings"></a>Conditionalizing Build Settings</h3>
<p>You can conditionalize build settings according to their
SDK (<code>sdk</code>), architecture (<code>arch</code>), and / or configuration (<code>config</code>)
according to the following syntax:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><var class="placeholder">BUILD_SETTING_NAME</var><span class="o">[</span><span class="k">sdk=<var class="placeholder">sdk</var>] </span><span class="o">=</span> <span class="n"><var class="placeholder">value for specified sdk</var></span>
<var class="placeholder">BUILD_SETTING_NAME</var><span class="o">[</span><span class="k">arch=<var class="placeholder">architecture</var>] </span><span class="o">=</span> <span class="n"><var class="placeholder">value for specified architecture</var></span>
<var class="placeholder">BUILD_SETTING_NAME</var><span class="o">[</span><span class="k">config=<var class="placeholder">configuration</var>] </span><span class="o">=</span> <span class="n"><var class="placeholder">value for specified configuration</var></span>
</code></pre>
<p>Given a choice between multiple definitions of the same build setting,
the compiler resolves according to specificity.</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><var class="placeholder">BUILD_SETTING_NAME</var><span class="o">[</span><span class="k">sdk=<var class="placeholder">sdk</var>][arch=<var class="placeholder">architecture</var>] </span><span class="o">=</span> <span class="n"><var class="placeholder">value for specified sdk and architectures</var></span>
<var class="placeholder">BUILD_SETTING_NAME</var><span class="o">[</span><span class="k">sdk=*][arch=<var class="placeholder">architecture</var>] </span><span class="o">=</span> <span class="n"><var class="placeholder">value for all other sdks with specified architecture</var></span>
</code></pre>
<p>For example,
you might specify the following build setting
to speed up local builds by only compiling for the active architecture:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="err">ONLY_ACTIVE_ARCH</span><span class="o">[</span><span class="k">config=Debug][sdk=*][arch=*] </span><span class="o">=</span> <span class="n">YES</span>
</code></pre>
<h3>
<a class="anchor" aria-hidden="true" id="including-build-settings-from-other-configuration-files" href="#including-build-settings-from-other-configuration-files"></a>Including Build Settings from Other Configuration Files</h3>
<p>A build configuration file can include settings from other configuration files
using the same <code>#include</code> syntax
as the equivalent <code>C</code> directive
on which this functionality is based:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="cp">#include "<var class="placeholder">path/to/File.xcconfig</var>"
</span></code></pre>
<p>As we’ll see later on in the article,
you can take advantage of this to build up cascading lists of build settings
in really powerful ways.</p>
<aside class="admonition info">
<p>Normally when the compiler encounters an <code>#include</code> directive
that can’t be resolved,
it raises an error.
But <code>xcconfig</code> files also support an <code>#include?</code> directive,
that doesn’t complain if the file can’t be found.</p>
<p>There aren’t many cases in which you’d want
the existence or nonexistence of a file
to change compile-time behavior;
after all, builds are best when they’re predictable.
But you might use this
as a hook for optional development tools like <a href="https://revealapp.com/" rel="noopener noreferrer">Reveal</a>,
which requires the following configuration:</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="cp"># Reveal.xcconfig
</span><span class="err">OTHER_LDFLAGS</span> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span> <span class="err">-weak_framework</span> <span class="err">Reveal<wbr></wbr>Server</span>
<span class="err">FRAMEWORK_SEARCH_PATHS</span> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span> <span class="err">/Applications/Reveal.app/Contents/Shared<wbr></wbr>Support/i<wbr></wbr>OS-Libraries</span>
</code></pre>
</aside>
<h2>
<a class="anchor" aria-hidden="true" id="creating-build-configuration-files" href="#creating-build-configuration-files"></a>Creating Build Configuration Files</h2>
<p>To create a build configuration file,
select the “File > New File…” menu item (<kbd>⌘</kbd><kbd>N</kbd>),
scroll down to the section labeled “Other”,
and select the Configuration Settings File template.
Next, save it somewhere in your project directory,
making sure to add it to your desired targets</p>
<picture>
<source srcset="/assets/xcconfig-new-file--dark-95d6c7c0f47545ee6eac2f9594cf9c07fb0b0457620f79146031b08e0c2a51841434d42d094025173362871c8f38db00acc976413212384d3023ebb21aa6b503.png" media="(prefers-color-scheme: dark)"></source>
<img src="/assets/xcconfig-new-file--light-2196fa7cbd39f743d406ba6de095699bd6bc8965a9f92d0d5fd98d59d54b89cd949dc82ca4fd4735b40dd55a423d462ce94085077a5b5cdfa78edffdce5e6537.png" alt="Xcode new configuration file">
</picture>
<p>Once you’ve created an <code>xcconfig</code> file,
you can assign it to one or more build configurations
for its associated targets.</p>
<picture>
<source srcset="/assets/xcconfig-project-configurations--dark-64fb95e11411fd1cad56cdda65e4e261be22850de58a8eda26530d6428b02ba793a2a9fe621badbe1cb5502b300069b6bfd88c12230092f8186c9f8b4d24746b.png" media="(prefers-color-scheme: dark)"></source>
<img src="/assets/xcconfig-project-configurations--light-9fa05b222eb93e0c144f00a1fd9996f53ff005d6af16cbbda35a217065efbe59057e968c0c7ba7f50cc185de958504aceabc1bd43fd4f72e8d682133f77c7fa9.png" alt="Xcode project configuration">
</picture>
<aside class="admonition info">
<p>Build configuration files shouldn’t be included in any of your project’s targets.
If you find any <code>.xcconfig</code> files showing up in your app’s <code>.ipa</code> archive,
make sure that they aren’t a member of any targets
and don’t appear in any “Copy Bundle Resources” build phases.</p>
</aside>
<hr>
<p>Now that we’ve covered the basics of using Xcode build configuration files
let’s look at a couple of examples of how you can use them
to manage development, stage, and production environments.</p>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="customizing-app-name-and-icon-for-internal-builds" href="#customizing-app-name-and-icon-for-internal-builds"></a>Customizing App Name and Icon for Internal Builds</h2>
<p>Developing an iOS app usually involves
juggling various internal builds
on your simulators and test devices
(as well as the latest version from the App Store,
to use as a reference).</p>
<p>You can make things easier on yourself
with <code>xcconfig</code> files that assign each configuration
a distinct name and app icon.</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="c1">// Development.xcconfig</span>
<span class="err">PRODUCT_NAME</span> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span> <span class="err">α</span>
<span class="err">ASSETCATALOG_COMPILER_APPICON_NAME</span> <span class="o">=</span> <span class="err">App<wbr></wbr>Icon-Alpha</span>
<span class="c1">//////////////////////////////////////////////////</span>
<span class="c1">// Staging.xcconfig</span>
<span class="err">PRODUCT_NAME</span> <span class="o">=</span> <span class="si">$(</span><span class="err">inherited</span><span class="si">)</span> <span class="err">β</span>
<span class="err">ASSETCATALOG_COMPILER_APPICON_NAME</span> <span class="o">=</span> <span class="err">App<wbr></wbr>Icon-Beta</span>
</code></pre>
<h2>
<a class="anchor" aria-hidden="true" id="managing-constants-across-different-environments" href="#managing-constants-across-different-environments"></a>Managing Constants Across Different Environments</h2>
<p>If your backend developers comport themselves according to the aforementioned
<a href="https://12factor.net/config" rel="noopener noreferrer">12 Factor App</a> philosophy,
then they’ll have separate endpoints for
development, stage, and production environments.</p>
<p>On iOS,
perhaps the most common approach to managing these environments
is to use conditional compilation statements
with build settings like <code>DEBUG</code>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="cp">#if DEBUG</span>
<span class="k">let</span> <span class="nv">api<wbr></wbr>Base<wbr></wbr>URL</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://api.staging.example.com"</span><span class="p">)</span><span class="o">!</span>
<span class="cp">#else</span>
<span class="k">let</span> <span class="nv">api<wbr></wbr>Base<wbr></wbr>URL</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://api.example.com"</span><span class="p">)</span><span class="o">!</span>
<span class="cp">#endif</span>
</code></pre>
<p>This gets the job done,
but runs afoul of the canon of code / configuration separation.</p>
<p>An alternative approach takes these environment-specific values
and puts them where they belong —
into <code>xcconfig</code> files.</p>
<pre class="highlight" data-lang="Xcode Build Settings"><code><span class="c1">// Development.xcconfig</span>
<span class="err">API_BASE_URL</span> <span class="o">=</span> <span class="err">api.staging.example.com</span>
<span class="c1">//////////////////////////////////////////</span>
<span class="c1">// Production.xcconfig</span>
<span class="err">API_BASE_URL</span> <span class="o">=</span> <span class="err">api.example.com</span>
</code></pre>
<aside class="admonition warning">
<p><code>xcconfig</code> files treat the sequence
<code>//</code> as a comment delimiter,
regardless of whether it’s enclosed in quotation marks.
If you try to escape with backslashes <code>\/\/</code>,
those backslashes show up literally
and must be removed from the resulting value.
This is especially inconvenient when specifying per-environment URL constants.</p>
<p>If you’d rather not work around this unfortunate behavior,
you can always omit the scheme and prepend <code>https://</code> in code.
<em>(You are using https… right?)</em></p>
</aside>
<p>However,
to pull these values programmatically,
we’ll need to take one additional step:</p>
<h3>
<a class="anchor" aria-hidden="true" id="accessing-build-settings-from-swift" href="#accessing-build-settings-from-swift"></a>Accessing Build Settings from Swift</h3>
<p>Build settings defined by
the Xcode project file, <code>xcconfig</code> files, and environment variables,
are only available at build time.
When you run the compiled app,
none of that surrounding context is available.
<em>(And thank goodness for that!)</em></p>
<p>But wait a sec —
don’t you remember seeing some of those build settings before
in one of those other tabs?
Info, was it?</p>
<p>As it so happens,
that info tab is actually just a fancy presentation of
the target’s <code>Info.plist</code> file.
At build time,
that <code>Info.plist</code> file is compiled
according to the build settings provided
and copied into the resulting app <a href="/bundles-and-packages/">bundle</a>.
Therefore,
by adding references to <code>$(API_BASE_URL)</code>,
you can access the values for those settings
through the <code>info<wbr></wbr>Dictionary</code> property of Foundation’s <code>Bundle</code> API.
<em>Neat!</em></p>
<picture>
<source srcset="/assets/xcconfig-project-info-plist--dark-85da4210e4ec44ac151e205b188626205da77822da790b9dc82e84d8cbb30b7a2c7b5e15ec736d6e886eb88119c846837b6f588e89e3a6f526a4681cf89623f0.png" media="(prefers-color-scheme: dark)"></source>
<img src="/assets/xcconfig-project-info-plist--light-3c51d15109870c490ca5116b14bf6eb428047a5cdee9bf6041e208088d20518cbb960ba9f093f828b37bb6346aa5a435dd77f862014eb43a76b0135b8c3b3d42.png" alt="Xcode Info.plist">
</picture>
<p>Following this approach,
we might do something like the following:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Foundation</span>
<span class="kd">enum</span> <span class="kt">Configuration</span> <span class="p">{</span>
<span class="kd">enum</span> <span class="kt">Error</span><span class="p">:</span> <span class="kt">Swift</span><span class="o">.</span><span class="kt">Error</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">missing<wbr></wbr>Key</span><span class="p">,</span> <span class="n">invalid<wbr></wbr>Value</span>
<span class="p">}</span>
<span class="kd">static</span> <span class="kd">func</span> <span class="n">value</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="k">for</span> <span class="nv">key</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="k">throws</span> <span class="o">-></span> <span class="kt">T</span> <span class="k">where</span> <span class="kt">T</span><span class="p">:</span> <span class="kt">Lossless<wbr></wbr>String<wbr></wbr>Convertible</span> <span class="p">{</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">object</span> <span class="o">=</span> <span class="kt">Bundle</span><span class="o">.</span><span class="n">main</span><span class="o">.</span><span class="nf">object</span><span class="p">(</span><span class="nv">for<wbr></wbr>Info<wbr></wbr>Dictionary<wbr></wbr>Key</span><span class="p">:</span><span class="n">key</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span>
<span class="k">throw</span> <span class="kt">Error</span><span class="o">.</span><span class="n">missing<wbr></wbr>Key</span>
<span class="p">}</span>
<span class="k">switch</span> <span class="n">object</span> <span class="p">{</span>
<span class="k">case</span> <span class="k">let</span> <span class="nv">value</span> <span class="k">as</span> <span class="kt">T</span><span class="p">:</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">case</span> <span class="k">let</span> <span class="nv">string</span> <span class="k">as</span> <span class="kt">String</span><span class="p">:</span>
<span class="k">guard</span> <span class="k">let</span> <span class="nv">value</span> <span class="o">=</span> <span class="kt">T</span><span class="p">(</span><span class="n">string</span><span class="p">)</span> <span class="k">else</span> <span class="p">{</span> <span class="k">fallthrough</span> <span class="p">}</span>
<span class="k">return</span> <span class="n">value</span>
<span class="k">default</span><span class="p">:</span>
<span class="k">throw</span> <span class="kt">Error</span><span class="o">.</span><span class="n">invalid<wbr></wbr>Value</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kd">enum</span> <span class="kt">API</span> <span class="p">{</span>
<span class="kd">static</span> <span class="k">var</span> <span class="nv">base<wbr></wbr>URL</span><span class="p">:</span> <span class="kt">URL</span> <span class="p">{</span>
<span class="k">return</span> <span class="k">try!</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="s">"https://"</span> <span class="o">+</span> <span class="kt">Configuration</span><span class="o">.</span><span class="nf">value</span><span class="p">(</span><span class="nv">for</span><span class="p">:</span> <span class="s">"API_BASE_URL"</span><span class="p">))</span><span class="o">!</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>When viewed from the call site,
we find that this approach harmonizes beautifully
with our best practices —
not a single hard-coded constant in sight!</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">url</span> <span class="o">=</span> <span class="kt">URL</span><span class="p">(</span><span class="nv">string</span><span class="p">:</span> <span class="n">path</span><span class="p">,</span> <span class="nv">relative<wbr></wbr>To</span><span class="p">:</span> <span class="kt">API</span><span class="o">.</span><span class="n">base<wbr></wbr>URL</span><span class="p">)</span><span class="o">!</span>
<span class="k">var</span> <span class="nv">request</span> <span class="o">=</span> <span class="kt">URLRequest</span><span class="p">(</span><span class="nv">url</span><span class="p">:</span> <span class="n">url</span><span class="p">)</span>
<span class="n">request</span><span class="o">.</span><span class="n">http<wbr></wbr>Method</span> <span class="o">=</span> <span class="n">method</span>
</code></pre>
<aside class="admonition error">
<p>Don’t use <code>xcconfig</code> files to store secrets like API keys or other credentials
For more information,
please refer to our article about <a href="/secrets/">secret management on iOS</a>.</p>
</aside>
<hr>
<p>Xcode projects are monolithic, fragile, and opaque.
They’re a source of friction for collaboration among team members
and generally a drag to work with.</p>
<p>Fortunately,
<code>xcconfig</code> files go a long way to address these pain points.
Moving configuration out of Xcode and into <code>xcconfig</code> files
confers a multitude of benefits
and offers a way to distance your project from the particulars of Xcode
without leaving the Cupertino-approved “happy path”.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>Software development best practices prescribe strict separation of configuration from code. Learn how you can use <code>xcconfig</code> files to make your Xcode projects more compact, comprehensible, and powerful.</p>Static and Dynamic Callable Types in Swift2020-02-12T00:00:00-08:002020-02-12T00:00:00-08:00https://nshipster.com/callable
<p>Last week,
Apple released the <a href="https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_beta_release_notes" rel="noopener noreferrer">first beta of Xcode 11.4</a>,
and it’s proving to be one of the most substantial updates in recent memory.
<code>XCTest</code> got <a href="https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_beta_release_notes#3530390" rel="noopener noreferrer">a huge boost</a>,
with numerous quality of life improvements,
and <a href="https://developer.apple.com/documentation/xcode_release_notes/xcode_11_4_beta_release_notes#3530393" rel="noopener noreferrer">Simulator</a>, likewise, got a solid dose of
<abbr title="tender loving care">TLC</abbr>.
But it’s the changes to Swift that are getting the lion’s share of attention.</p>
<p>In Xcode 11.4,
Swift compile times are down across the board,
with many developers reporting improvements of 10 – 20% in their projects.
And thanks to a <a href="https://swift.org/blog/new-diagnostic-arch-overview/" title="Swift.org - New Diagnostic Architecture Overview" rel="noopener noreferrer">new diagnostics architecture</a>,
error messages from the compiler are consistently more helpful.
This is also the first version of Xcode to ship with the new
<a href="/language-server-protocol/"><code>sourcekit-lsp</code> server</a>,
which serves to empower editors like <a href="/vscode/">VSCode</a>
to work with Swift in a more meaningful way.</p>
<p>Yet,
despite all of these improvements
(which are truly an incredible achievement by Apple’s Developer Tools team),
much of the early feedback has focused on
the most visible additions to Swift 5.2.
And the response from the peanut galleries of
Twitter, Hacker News, and Reddit has been —
to put it charitably — <em>“mixed”</em>.</p>
<hr><a id="get-on-with-it"></a>
<p>If like most of us,
you aren’t tuned into the comings-and-goings of <a href="https://apple.github.io/swift-evolution/" title="Swift Evolution Proposals Dashboard" rel="noopener noreferrer">Swift Evolution</a>,
Xcode 11.4 was your first exposure to two new additions to the language:
<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md" title="SE-0249: Key Path Expressions as Functions" rel="noopener noreferrer">key path expressions as functions</a>
and
<a href="https://github.com/apple/swift-evolution/blob/master/proposals/0253-callable.md" title="SE-0253: Callable values of user-defined nominal types" rel="noopener noreferrer">callable values of user-defined nominal types</a>.</p>
<p>The first of these allows key paths to replace
one-off closures used by functions like <code>map</code>:</p>
<pre class="highlight" data-lang="Swift"><code><span class="c1">// Swift >= 5.2</span>
<span class="s">"🧁🍭🍦"</span><span class="o">.</span><span class="n">unicode<wbr></wbr>Scalars</span><span class="o">.</span><span class="nf">map</span><span class="p">(\</span><span class="o">.</span><span class="n">properties</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
<span class="c1">// ["CUPCAKE", "LOLLIPOP", "SOFT ICE CREAM"]</span>
<span class="c1">// Swift <5.2 equivalent</span>
<span class="s">"🧁🍭🍦"</span><span class="o">.</span><span class="n">unicode<wbr></wbr>Scalars</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="n">properties</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>
</code></pre>
<p>The second allows instances of types with a method named <code>call<wbr></wbr>As<wbr></wbr>Function</code>
to be called as if they were a function:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Sweetener</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">additives</span><span class="p">:</span> <span class="kt">Set</span><span class="o"><</span><span class="kt">Character</span><span class="o">></span>
<span class="kd">init</span><span class="o"><</span><span class="kt">S</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">sequence</span><span class="p">:</span> <span class="kt">S</span><span class="p">)</span> <span class="k">where</span> <span class="kt">S</span><span class="p">:</span> <span class="kt">Sequence</span><span class="p">,</span> <span class="kt">S</span><span class="o">.</span><span class="kt">Element</span> <span class="o">==</span> <span class="kt">Character</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">additives</span> <span class="o">=</span> <span class="kt">Set</span><span class="p">(</span><span class="n">sequence</span><span class="p">)</span>
<span class="p">}</span>
<span class="kd">func</span> <span class="nf">call<wbr></wbr>As<wbr></wbr>Function</span><span class="p">(</span><span class="n">_</span> <span class="nv">message</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="p">{</span>
<span class="n">message</span><span class="o">.</span><span class="nf">split</span><span class="p">(</span><span class="nv">separator</span><span class="p">:</span> <span class="s">" "</span><span class="p">)</span>
<span class="o">.</span><span class="n">flat<wbr></wbr>Map</span> <span class="p">{</span> <span class="p">[</span><span class="nv">$0</span><span class="p">,</span> <span class="s">"</span><span class="se">\(</span><span class="n">additives</span><span class="o">.</span><span class="nf">random<wbr></wbr>Element</span><span class="p">()</span><span class="o">!</span><span class="se">)</span><span class="s">"</span><span class="p">]</span> <span class="p">}</span>
<span class="o">.</span><span class="nf">joined</span><span class="p">(</span><span class="nv">separator</span><span class="p">:</span> <span class="s">" "</span><span class="p">)</span> <span class="o">+</span> <span class="s">"😋"</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">let</span> <span class="nv">dessertify</span> <span class="o">=</span> <span class="kt">Sweetener</span><span class="p">(</span><span class="s">"🧁🍭🍦"</span><span class="p">)</span>
<span class="nf">dessertify</span><span class="p">(</span><span class="s">"Hello, world!"</span><span class="p">)</span>
<span class="c1">// "Hello, 🍭 world! 🍦😋"</span>
</code></pre>
<hr>
<p>Granted,
both of those examples are terrible.
And that’s kinda the problem.</p>
<hr>
<p>Too often,
coverage of <em>“What’s New In Swift”</em>
amounts to little more than a regurgitation of Swift Evolution proposals,
interspersed with poorly motivated (and often emoji-laden) examples.
Such treatments provide a poor characterization of Swift language features,
and — in the case of Swift 5.2 —
serves to feed into the popular critique that these are frivolous additions —
mere <dfn><a href="https://en.wikipedia.org/wiki/Syntactic_sugar" rel="noopener noreferrer">syntactic sugar</a></dfn>.</p>
<aside class="parenthetical">
<p>To the extent that we’ve been guilty of that…
our bad <span lang="und-Zsye">🙇♂️</span>.</p>
</aside>
<p>This week,
we hope to reach the ooey gooey center of the issue
by providing some historical and theoretical context
for understanding these new features.</p>
<h2>
<a class="anchor" aria-hidden="true" id="syntactic-sugar-in-swift" href="#syntactic-sugar-in-swift"></a>Syntactic Sugar in Swift</h2>
<p>If you’re salty about “key path as function” being too sugary,
recall that the <span lang="la">status quo</span>
isn’t without a sweet tooth.
Consider our saccharine example from before:</p>
<pre class="highlight" data-lang="Swift"><code><span class="s">"🧁🍭🍦"</span><span class="o">.</span><span class="n">unicode<wbr></wbr>Scalars</span><span class="o">.</span><span class="n">map</span> <span class="p">{</span> <span class="nv">$0</span><span class="o">.</span><span class="n">properties</span><span class="o">.</span><span class="n">name</span> <span class="p">}</span>
</code></pre>
<p>That expression relies on at least four different syntactic concessions:</p>
<ol>
<li>
<strong>Trailing closure syntax</strong>,
which allows a final closure argument label of a function to be omitted</li>
<li>
<strong>Anonymous closure arguments</strong>,
which allow arguments in closures to be used positionally (<code>$0</code>, <code>$1</code>, …)
without binding to a named variable.</li>
<li><strong>Inferred parameter and return value types</strong></li>
<li><strong>Implicit return from single-expression closures</strong></li>
</ol>
<p>If you wanted to cut sugar out of your diet completely,
you’d best get <a href="https://en.wikipedia.org/wiki/Mavis_Beacon_Teaches_Typing" title="Mavis Beacon Teaches Typing" rel="noopener noreferrer">Mavis Beacon</a> on the line,
because you’ll be doing a lot more <a href="/rawrepresentable/">typing</a>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="s">"🧁🍭🍦"</span><span class="o">.</span><span class="n">unicode<wbr></wbr>Scalars</span><span class="o">.</span><span class="nf">map</span><span class="p">(</span><span class="nv">transform</span><span class="p">:</span> <span class="p">{</span> <span class="p">(</span><span class="nv">unicode<wbr></wbr>Scalar</span><span class="p">:</span> <span class="kt">Unicode</span><span class="o">.</span><span class="kt">Scalar</span><span class="p">)</span> <span class="o">-></span> <span class="kt">String</span> <span class="k">in</span>
<span class="k">return</span> <span class="n">unicode<wbr></wbr>Scalar</span><span class="o">.</span><span class="n">properties</span><span class="o">.</span><span class="n">name</span>
<span class="p">})</span>
</code></pre>
<aside class="parenthetical">
<p>Also, who knew that the argument label in <code>map</code> was “transform”?</p>
</aside>
<p>In fact,
as we’ll see in the examples to come,
Swift is a marshmallow world in the winter,
<em>syntactically speaking</em>.
From initializers and method calls to optionals and method chaining,
nearly everything about Swift could be described as a cotton candy melody —
it really just depends on where you draw the line between
“language feature” and “syntactic sugar”.</p>
<hr>
<p>To understand why,
you have to understand how we got here in the first place,
which requires a bit of history, math, and computer science.
Get ready to eat your vegetables 🥦.</p>
<h2>
<a class="anchor" aria-hidden="true" id="the-calculus-and-speculative-computer-science-fiction" href="#the-calculus-and-speculative-computer-science-fiction"></a>The λ-Calculus and Speculative Computer Science Fiction</h2>
<p>All programming languages can be seen as various attempts to represent
<a href="https://en.wikipedia.org/wiki/Lambda_calculus" rel="noopener noreferrer">the <abbr lang="la" title="lambda">λ</abbr>-calculus</a>.
Everything you need to write code —
variables, binding, application —
it’s all in there,
buried under a mass of Greek letters and mathematical notation.</p>
<p>Setting aside syntactic differences,
each programming language can be understood by
its combination of affordances for
making programs easier to write and easier to read.
Language features like
objects,
classes,
modules,
optionals,
literals,
and generics
are all just abstractions built on top of the λ-calculus.</p>
<p>Any other deviation from pure mathematical formalism
can be ascribed to real-world constraints,
such as
<a href="https://en.wikipedia.org/wiki/QWERTY" title="QWERTY" rel="noopener noreferrer">a typewriter from the 1870s</a>,
<a href="https://en.wikipedia.org/wiki/Punched_card#IBM_80-column_punched_card_format_and_character_codes" rel="noopener noreferrer">a punch card from the 1920s</a>,
<a href="https://en.wikipedia.org/wiki/Von_Neumann_architecture" title="Von Neumann Architecture" rel="noopener noreferrer">a computer architecture from the 1940s</a>,
or <a href="https://en.wikipedia.org/wiki/ASCII" rel="noopener noreferrer">a character encoding from the 1960s</a>.</p>
<p>Among the earliest programming languages were Lisp, ALGOL*, and COBOL,
from which nearly every other language derives.</p>
<aside class="parenthetical">
<p>We’re using FORTRAN as a stand-in here,
for lack of an easily-accessible ALGOL environment.</p>
</aside>
<div class="highlight-group">
<div role="tablist" aria-label="Languages">
<button role="tab" id="code-listing-1-lisp-tab" class="lisp" aria-label="Languages" aria-controls="code-listing-1-lisp" aria-selected="true" tabindex="-1">
Lisp
</button>
<button role="tab" id="code-listing-1-fortran-tab" class="fortran" aria-label="Languages" aria-controls="code-listing-1-fortran" aria-selected="false" tabindex="-1">
FORTRAN
</button>
<button role="tab" id="code-listing-1-cobol-tab" class="cobol" aria-label="Languages" aria-controls="code-listing-1-cobol" aria-selected="false" tabindex="-1">
COBOL
</button>
</div>
<pre class="highlight" data-lang="Lisp" id="code-listing-1-lisp" role="tabpanel" tabindex="0" aria-labelledby="code-listing-1-lisp-tab"><code><span class="p">(</span><span class="nb">defun</span> <span class="nv">square</span> <span class="p">(</span><span class="nv">x</span><span class="p">)</span>
<span class="p">(</span><span class="nb">*</span> <span class="nv">x</span> <span class="nv">x</span><span class="p">))</span>
<span class="p">(</span><span class="nb">print</span> <span class="p">(</span><span class="nv">square</span> <span class="mi">4</span><span class="p">))</span>
<span class="c1">;; 16</span>
</code></pre>
<pre class="highlight" data-lang="FORTRAN" id="code-listing-1-fortran" role="tabpanel" tabindex="0" aria-labelledby="code-listing-1-fortran-tab" hidden="hidden"><code><span class="k">pure</span><span class="w"> </span><span class="k">function</span><span class="w"> </span><span class="n">square</span><span class="p">(</span><span class="n">x</span><span class="p">)</span><span class="w">
</span><span class="kt">integer</span><span class="p">,</span><span class="w"> </span><span class="k">intent</span><span class="p">(</span><span class="k">in</span><span class="p">)</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">x</span><span class="w">
</span><span class="kt">integer</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">square</span><span class="w">
</span><span class="n">square</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">x</span><span class="w"> </span><span class="o">*</span><span class="w"> </span><span class="n">x</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">function</span><span class="w">
</span><span class="k">program</span><span class="w"> </span><span class="n">main</span><span class="w">
</span><span class="kt">integer</span><span class="w"> </span><span class="p">::</span><span class="w"> </span><span class="n">square</span><span class="w">
</span><span class="k">print</span><span class="w"> </span><span class="o">*</span><span class="p">,</span><span class="w"> </span><span class="n">square</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span><span class="w">
</span><span class="k">end</span><span class="w"> </span><span class="k">program</span><span class="w"> </span><span class="n">main</span><span class="w">
</span><span class="c1">! 16</span><span class="w">
</span></code></pre>
<pre class="highlight" data-lang="COBOL" id="code-listing-1-cobol" role="tabpanel" tabindex="0" aria-labelledby="code-listing-1-cobol-tab" hidden="hidden"><code><span class="n">IDENTIFICATION</span> <span class="n">DIVISION</span><span class="p">.</span>
<span class="n">PROGRAM</span><span class="o">-</span><span class="n">ID</span><span class="p">.</span> <span class="n">example</span><span class="p">.</span>
<span class="n">DATA</span> <span class="n">DIVISION</span><span class="p">.</span>
<span class="n">WORKING</span><span class="o">-</span><span class="n">STORAGE</span> <span class="n">SECTION</span><span class="p">.</span>
<span class="mi">01</span> <span class="n">x</span> <span class="n">PIC</span> <span class="mi">9</span><span class="p">(</span><span class="mi">3</span><span class="p">)</span> <span class="n">VALUE</span> <span class="mi">4</span><span class="p">.</span>
<span class="mi">01</span> <span class="n">y</span> <span class="n">PIC</span> <span class="mi">9</span><span class="p">(</span><span class="mi">9</span><span class="p">).</span>
<span class="n">PROCEDURE</span> <span class="n">DIVISION</span><span class="p">.</span>
<span class="n">CALL</span> <span class="s2">"square"</span> <span class="n">USING</span>
<span class="n">BY</span> <span class="n">CONTENT</span> <span class="n">x</span>
<span class="n">BY</span> <span class="n">REFERENCE</span> <span class="n">y</span><span class="p">.</span>
<span class="n">DISPLAY</span> <span class="n">y</span><span class="p">.</span>
<span class="n">STOP</span> <span class="n">RUN</span><span class="p">.</span>
<span class="n">END</span> <span class="n">PROGRAM</span> <span class="n">example</span><span class="p">.</span>
<span class="n">IDENTIFICATION</span> <span class="n">DIVISION</span><span class="p">.</span>
<span class="n">PROGRAM</span><span class="o">-</span><span class="n">ID</span><span class="p">.</span> <span class="n">square</span><span class="p">.</span>
<span class="n">DATA</span> <span class="n">DIVISION</span><span class="p">.</span>
<span class="n">LINKAGE</span> <span class="n">SECTION</span><span class="p">.</span>
<span class="mi">01</span> <span class="n">x</span> <span class="n">PIC</span> <span class="mi">9</span><span class="p">(</span><span class="mi">3</span><span class="p">).</span>
<span class="mi">01</span> <span class="n">y</span> <span class="n">PIC</span> <span class="mi">9</span><span class="p">(</span><span class="mi">3</span><span class="p">).</span>
<span class="n">PROCEDURE</span> <span class="n">DIVISION</span> <span class="n">USING</span> <span class="n">x</span><span class="p">,</span> <span class="n">y</span><span class="p">.</span>
<span class="n">MULTIPLY</span> <span class="n">x</span> <span class="n">BY</span> <span class="n">x</span> <span class="n">GIVING</span> <span class="n">y</span><span class="p">.</span>
<span class="n">EXIT</span> <span class="n">PROGRAM</span><span class="p">.</span>
<span class="n">END</span> <span class="n">PROGRAM</span> <span class="n">square</span><span class="p">.</span>
<span class="c1">* 016000000</span>
</code></pre>
</div>
<p>Here you get a glimpse into three very different timelines;
ours is the reality in which ALGOL’s syntax (option #2)
“won out” over the alternatives.
From ALGOL 60,
you can draw a straight line from
<a href="https://en.wikipedia.org/wiki/CPL_(programming_language)" rel="noopener noreferrer">CPL</a> in 1963,
to <a href="https://en.wikipedia.org/wiki/BCPL" rel="noopener noreferrer">BCPL</a> in 1967
and <a href="https://en.wikipedia.org/wiki/C_(programming_language)" rel="noopener noreferrer">C</a> in 1972,
followed by <a href="/direct/#object-oriented-programming">Objective-C in 1984</a>
and Swift in 2014.
That’s the lineage that informs what types are callable and how we call them.</p>
<hr>
<p><em>Now, back to Swift…</em></p>
<h2>
<a class="anchor" aria-hidden="true" id="function-types-in-swift" href="#function-types-in-swift"></a>Function Types in Swift</h2>
<p>Functions are first-class objects in Swift,
meaning that they can be assigned to variables,
stored in properties,
and passed as arguments or returned as values from other functions.</p>
<p>What distinguishes function types from other values
is that they’re <dfn>callable</dfn>,
meaning that you can invoke them to produce new values.</p>
<h3>
<a class="anchor" aria-hidden="true" id="closures" href="#closures"></a>Closures</h3>
<p>Swift’s fundamental function type is the <dfn>closure</dfn>,
a self-contained unit of functionality.</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">square</span><span class="p">:</span> <span class="p">(</span><span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Int</span> <span class="o">=</span> <span class="p">{</span> <span class="n">x</span> <span class="k">in</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span> <span class="p">}</span>
</code></pre>
<p>As a function type,
you can call a closure by passing the requisite number of arguments
between opening and closing parentheses <code>()</code> —
<em lang="fr">a la</em> ALGOL.</p>
<pre class="highlight" data-lang="Swift"><code><span class="nf">square</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1">// 16</span>
</code></pre>
<aside class="admonition info">
<p>The number of arguments taken by a function type
is known as its <dfn>arity</dfn>.</p>
</aside>
<p>Closures are so called because they <dfn>close over</dfn> and capture
references to any variables from the context in which they’re defined.
However, capturing semantics aren’t always desirable,
which is why Swift provides dedicated syntax to a special kind of closure
known as a <dfn>function</dfn>.</p>
<h3>
<a class="anchor" aria-hidden="true" id="functions" href="#functions"></a>Functions</h3>
<p>Functions defined at a top-level / global scope
are named closures that don’t capture any values.
In Swift,
you declare them with the <code>func</code> keyword:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">func</span> <span class="nf">square</span><span class="p">(</span><span class="n">_</span> <span class="nv">x</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Int</span> <span class="p">{</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span> <span class="p">}</span>
<span class="nf">square</span><span class="p">(</span><span class="mi">4</span><span class="p">)</span> <span class="c1">// 16</span>
</code></pre>
<p>Compared to closures,
functions have greater flexibility in how arguments are passed.</p>
<p>Function arguments can have named labels
instead of a closure’s unlabeled, positional arguments —
which goes a long way to clarify the effect of code at its call site:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">func</span> <span class="nf">deposit</span><span class="p">(</span><span class="nv">amount</span><span class="p">:</span> <span class="kt">Decimal</span><span class="p">,</span>
<span class="n">from</span> <span class="nv">source</span><span class="p">:</span> <span class="kt">Account</span><span class="p">,</span>
<span class="n">to</span> <span class="nv">destination</span><span class="p">:</span> <span class="kt">Account</span><span class="p">)</span> <span class="k">throws</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="k">try</span> <span class="nf">deposit</span><span class="p">(</span><span class="nv">amount</span><span class="p">:</span> <span class="mf">1000.00</span><span class="p">,</span> <span class="nv">from</span><span class="p">:</span> <span class="n">checking</span><span class="p">,</span> <span class="nv">to</span><span class="p">:</span> <span class="n">savings</span><span class="p">)</span>
</code></pre>
<p>Functions can be <a href="https://docs.swift.org/swift-book/LanguageGuide/Generics.html" title="The Swift Programming Language - Generics" rel="noopener noreferrer">generic</a>,
allowing them to be used for multiple types of arguments:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">func</span> <span class="n">square</span><span class="o"><</span><span class="kt">T</span><span class="p">:</span> <span class="kt">Numeric</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">x</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span> <span class="n">x</span> <span class="o">*</span> <span class="n">x</span> <span class="p">}</span>
<span class="kd">func</span> <span class="n">increment</span><span class="o"><</span><span class="kt">T</span><span class="p">:</span> <span class="kt">Numeric</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">x</span><span class="p">:</span> <span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span> <span class="n">x</span> <span class="o">+</span> <span class="mi">1</span> <span class="p">}</span>
<span class="kd">func</span> <span class="n">compose</span><span class="o"><</span><span class="kt">T</span><span class="o">></span><span class="p">(</span><span class="n">_</span> <span class="nv">f</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">(</span><span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span><span class="p">,</span> <span class="n">_</span> <span class="nv">g</span><span class="p">:</span> <span class="kd">@escaping</span> <span class="p">(</span><span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="p">(</span><span class="kt">T</span><span class="p">)</span> <span class="o">-></span> <span class="kt">T</span> <span class="p">{</span>
<span class="p">{</span> <span class="n">x</span> <span class="k">in</span> <span class="nf">g</span><span class="p">(</span><span class="nf">f</span><span class="p">(</span><span class="n">x</span><span class="p">))</span> <span class="p">}</span>
<span class="p">}</span>
<span class="nf">compose</span><span class="p">(</span><span class="n">increment</span><span class="p">,</span> <span class="n">square</span><span class="p">)(</span><span class="mi">4</span> <span class="k">as</span> <span class="kt">Int</span><span class="p">)</span> <span class="c1">// 25 ((4 + 1)²)</span>
<span class="nf">compose</span><span class="p">(</span><span class="n">increment</span><span class="p">,</span> <span class="n">square</span><span class="p">)(</span><span class="mf">4.2</span> <span class="k">as</span> <span class="kt">Double</span><span class="p">)</span> <span class="c1">// 27.04 ((4.2 + 1)²)</span>
</code></pre>
<p>Functions can also take variadic arguments,
implicit closures,
and default argument values
(allowing for magic expression literals like <code>#file</code> and <code>#line</code>):</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">func</span> <span class="nf">print</span><span class="p">(</span><span class="nv">items</span><span class="p">:</span> <span class="kt">Any</span><span class="o">...</span><span class="p">)</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">assert</span><span class="p">(</span><span class="n">_</span> <span class="nv">condition</span><span class="p">:</span> <span class="kd">@autoclosure</span> <span class="p">()</span> <span class="o">-></span> <span class="kt">Bool</span><span class="p">,</span>
<span class="n">_</span> <span class="nv">message</span><span class="p">:</span> <span class="kd">@autoclosure</span> <span class="p">()</span> <span class="o">-></span> <span class="kt">String</span> <span class="o">=</span> <span class="kt">String</span><span class="p">(),</span>
<span class="nv">file</span><span class="p">:</span> <span class="kt">Static<wbr></wbr>String</span> <span class="o">=</span> <span class="kd">#file</span><span class="p">,</span>
<span class="nv">line</span><span class="p">:</span> <span class="kt">UInt</span> <span class="o">=</span> <span class="kd">#line</span><span class="p">)</span> <span class="p">{</span> <span class="err"><var class="placeholder">…</var></span> <span class="p">}</span>
</code></pre>
<p>And yet,
despite all of this flexibility for accepting arguments,
most functions you’ll encounter operate on an <em>implicit</em> <code>self</code> argument.
These functions are called methods.</p>
<h3>
<a class="anchor" aria-hidden="true" id="methods" href="#methods"></a>Methods</h3>
<p>A <dfn>method</dfn> is a function contained by a type.
Methods automatically provide access to <code>self</code>,
allowing them to effectively capture the instance on which they’re called
as an implicit argument.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Queue</span><span class="o"><</span><span class="kt">Element</span><span class="o">></span> <span class="p">{</span>
<span class="kd">private</span> <span class="k">var</span> <span class="nv">elements</span><span class="p">:</span> <span class="p">[</span><span class="kt">Element</span><span class="p">]</span> <span class="o">=</span> <span class="p">[]</span>
<span class="k">mutating</span> <span class="kd">func</span> <span class="nf">push</span><span class="p">(</span><span class="n">_</span> <span class="nv">new<wbr></wbr>Element</span><span class="p">:</span> <span class="kt">Element</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="nf">append</span><span class="p">(</span><span class="n">new<wbr></wbr>Element</span><span class="p">)</span>
<span class="p">}</span>
<span class="k">mutating</span> <span class="kd">func</span> <span class="nf">pop</span><span class="p">()</span> <span class="o">-></span> <span class="kt">Element</span><span class="p">?</span> <span class="p">{</span>
<span class="k">guard</span> <span class="o">!</span><span class="k">self</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="n">is<wbr></wbr>Empty</span> <span class="k">else</span> <span class="p">{</span> <span class="k">return</span> <span class="kc">nil</span> <span class="p">}</span>
<span class="k">return</span> <span class="k">self</span><span class="o">.</span><span class="n">elements</span><span class="o">.</span><span class="nf">remove<wbr></wbr>First</span><span class="p">()</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<aside class="admonition info">
<p>Swift goes one step further
by allowing <code>self.</code> to be omitted for member access —
making the already implicit <code>self</code> all the more implicit.</p>
</aside>
<hr>
<p>Putting everything together,
these syntactic affordances allow Swift code to be
expressive, clear, and concise:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">var</span> <span class="nv">queue</span> <span class="o">=</span> <span class="kt">Queue</span><span class="o"><</span><span class="kt">Int</span><span class="o">></span><span class="p">()</span>
<span class="n">queue</span><span class="o">.</span><span class="nf">push</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span>
<span class="n">queue</span><span class="o">.</span><span class="nf">push</span><span class="p">(</span><span class="mi">2</span><span class="p">)</span>
<span class="n">queue</span><span class="o">.</span><span class="nf">pop</span><span class="p">()</span> <span class="c1">// 1</span>
</code></pre>
<p>Compared to more verbose languages like Objective-C,
the experience of writing Swift is, well, pretty <em>sweet</em>.
It’s hard to imagine any Swift developers objecting to what we have here
as being “sugar-coated”.</p>
<p>But like a 16oz can of <a href="https://en.wikipedia.org/wiki/Surge_(drink)" title="SURGE" rel="noopener noreferrer">Surge</a>,
the sugar content of something is often surprising.
Turns out,
that example from before is far from innocent:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">var</span> <span class="nv">queue</span> <span class="o">=</span> <span class="kt">Queue</span><span class="o"><</span><span class="kt">Int</span><span class="o">></span><span class="p">()</span> <span class="c1">// desugars to `Queue<Int>.init()`</span>
<span class="n">queue</span><span class="o">.</span><span class="nf">push</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// desugars to `Queue.push(&queue)(1)`</span>
</code></pre>
<p>All this time,
our so-called “direct” calls to methods and initializers
were actually shorthand for <del><a href="https://en.wikipedia.org/wiki/Currying" rel="noopener noreferrer">function currying</a></del>
<ins><a href="https://en.wikipedia.org/wiki/Partial_application" rel="noopener noreferrer">partially-applied functions</a></ins>.</p>
<aside class="admonition info">
<p>Partial application and currying are often conflated.
In fact,
<a href="https://ericasadun.com/2017/04/03/musings-on-partial-application/" rel="noopener noreferrer">they’re distinct but related concepts</a>.</p>
<p>Early versions of Swift had a dedicated syntax for currying functions,
but it proved less useful than originally anticipated
and was removed by the <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0002-remove-currying.md" title="SE-0002: Removing currying func declaration syntax" rel="noopener noreferrer">second-ever Swift Evolution proposal</a>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="c1">// Swift <3:</span>
<span class="kd">func</span> <span class="nf">curried</span><span class="p">(</span><span class="nv">x</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)(</span><span class="nv">y</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Float</span> <span class="p">{</span>
<span class="k">return</span> <span class="kt">Float</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="kt">Float</span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="o">!</span>
<span class="p">}</span>
<span class="c1">// Swift >=3</span>
<span class="kd">func</span> <span class="nf">curried</span><span class="p">(</span><span class="nv">x</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="p">(</span><span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Float</span> <span class="p">{</span>
<span class="k">return</span> <span class="p">{</span> <span class="p">(</span><span class="nv">y</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Float</span> <span class="k">in</span>
<span class="k">return</span> <span class="kt">Float</span><span class="p">(</span><span class="n">x</span><span class="p">)</span> <span class="o">+</span> <span class="kt">Float</span><span class="p">(</span><span class="n">y</span><span class="p">)</span><span class="o">!</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
</aside>
<p>With this in mind,
let’s now take another look at callable types in Swift more generally.</p>
<h2>
<a class="anchor" aria-hidden="true" id="type-instance-member-static-dynamic" href="#type-instance-member-static-dynamic"></a>{Type, Instance, Member} ⨯ {Static, Dynamic}</h2>
<p>Since their introduction in Swift 4.2 and Swift 5, respectively,
many developers have had a hard time keeping
<code>@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</code> and <code>@dynamic<wbr></wbr>Callable</code>
straight in their minds —
made even more difficult by the introduction of <code>call<wbr></wbr>As<wbr></wbr>Function</code> in Swift 5.2.</p>
<p>If you’re also confused,
we think the following table can help clear things up:</p>
<table>
<thead>
<tr>
<th> </th>
<th>Static</th>
<th>Dynamic</th>
</tr>
</thead>
<tbody>
<tr>
<td>Type</td>
<td><code>init</code></td>
<td><em>N/A</em></td>
</tr>
<tr>
<td>Instance</td>
<td><strong><code>call<wbr></wbr>As<wbr></wbr>Function</code></strong></td>
<td><strong><code>@dynamic<wbr></wbr>Callable</code></strong></td>
</tr>
<tr>
<td>Member</td>
<td><code>func</code></td>
<td><strong><code>@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</code></strong></td>
</tr>
</tbody>
</table>
<p>Swift has always had static callable types and type members.
What’s changed in new versions of Swift
is that instances are now callable,
and both instances and members can now be called dynamically.</p>
<aside class="admonition warning">
<p>You might have noticed the blank spot in our table.
Indeed, there’s no way to dynamically call types.
In fact, there’s no way to statically call types
other than to invoke initializers —
and that’s probably for the best.</p>
</aside>
<p>Let’s see what that means in practice,
starting with static callables.</p>
<h3>
<a class="anchor" aria-hidden="true" id="static-callable" href="#static-callable"></a>Static Callable</h3>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Static</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">()</span> <span class="p">{}</span>
<span class="kd">func</span> <span class="nf">call<wbr></wbr>As<wbr></wbr>Function</span><span class="p">()</span> <span class="p">{}</span>
<span class="kd">static</span> <span class="kd">func</span> <span class="nf">function</span><span class="p">()</span> <span class="p">{}</span>
<span class="kd">func</span> <span class="nf">function</span><span class="p">()</span> <span class="p">{}</span>
<span class="p">}</span>
</code></pre>
<p>This type can be called statically in the following ways:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">instance</span> <span class="o">=</span> <span class="kt">Static</span><span class="p">()</span> <span class="c1">// <var class="placeholder">❶</var> desugars to `Static.init()`</span>
<span class="kt">Static</span><span class="o">.</span><span class="nf">function</span><span class="p">()</span> <span class="c1">// <var class="placeholder">❷</var> (no syntactic sugar!)</span>
<span class="n">instance</span><span class="o">.</span><span class="nf">function</span><span class="p">()</span> <span class="c1">// <var class="placeholder">❸</var> desugars to Static.function(instance)()</span>
<span class="nf">instance</span><span class="p">()</span> <span class="c1">// <var class="placeholder">❹</var> desugars to `Static.call<wbr></wbr>As<wbr></wbr>Function(instance)()`</span>
</code></pre>
<dl>
<dt>❶</dt>
<dd>Calling the <code>Static</code> type invokes an initializer</dd>
<dt>❷</dt>
<dd>Calling <code>function</code> on the <code>Static</code> type
invokes the corresponding static function member,
passing <code>Static</code> as an implicit <code>self</code> argument.</dd>
<dt>❸</dt>
<dd>Calling <code>function</code> on an instance of <code>Static</code>
invokes the corresponding function member,
passing the instance as an implicit <code>self</code> argument.</dd>
<dt>❹</dt>
<dd>Calling an instance of <code>Static</code>
invokes the <code>call<wbr></wbr>As<wbr></wbr>Function()</code> function member,
passing the instance as an implicit <code>self</code> argument.</dd>
</dl>
<aside class="admonition info">
<p>A few points for completeness’ sake:</p>
<ul>
<li>You can also statically call subscripts and variable members (properties).</li>
<li>Operators provide an alternative way to invoke static member functions.</li>
<li>Enumeration cases are, well…
something else entirely.</li>
</ul>
<!-- Interestingly,
[a draft proposal](https://forums.swift.org/t/enum-cases-as-protocol-witnesses/32753/19)
to allow enumeration cases to be treated as protocol witnesses
is currently making the rounds on the Swift forums. -->
</aside>
<h3>
<a class="anchor" aria-hidden="true" id="dynamic-callable" href="#dynamic-callable"></a>Dynamic Callable</h3>
<pre class="highlight" data-lang="Swift"><code><span class="kd">@dynamic<wbr></wbr>Callable</span>
<span class="kd">@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</span>
<span class="kd">struct</span> <span class="kt">Dynamic</span> <span class="p">{</span>
<span class="kd">func</span> <span class="nf">dynamically<wbr></wbr>Call</span><span class="p">(</span><span class="n">with<wbr></wbr>Arguments</span> <span class="nv">args</span><span class="p">:</span> <span class="p">[</span><span class="kt">Int</span><span class="p">])</span> <span class="o">-></span> <span class="kt">Void</span> <span class="p">{</span> <span class="p">()</span> <span class="p">}</span>
<span class="kd">func</span> <span class="nf">dynamically<wbr></wbr>Call</span><span class="p">(</span><span class="n">with<wbr></wbr>Keyword<wbr></wbr>Arguments</span> <span class="nv">args</span><span class="p">:</span> <span class="kt">Key<wbr></wbr>Value<wbr></wbr>Pairs</span><span class="o"><</span><span class="kt">String</span><span class="p">,</span> <span class="kt">Int</span><span class="o">></span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span> <span class="p">{</span> <span class="p">()</span> <span class="p">}</span>
<span class="kd">static</span> <span class="nf">subscript</span><span class="p">(</span><span class="n">dynamic<wbr></wbr>Member</span> <span class="nv">member</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="p">(</span><span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span> <span class="p">{</span> <span class="p">{</span> <span class="n">_</span> <span class="k">in</span> <span class="p">}</span> <span class="p">}</span>
<span class="nf">subscript</span><span class="p">(</span><span class="n">dynamic<wbr></wbr>Member</span> <span class="nv">member</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="p">(</span><span class="kt">Int</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Void</span> <span class="p">{</span> <span class="p">{</span> <span class="n">_</span> <span class="k">in</span> <span class="p">}</span> <span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>This type can be called dynamically in a few different ways:</p>
<pre class="highlight" data-lang="Swift"><code><span class="k">let</span> <span class="nv">instance</span> <span class="o">=</span> <span class="kt">Dynamic</span><span class="p">()</span> <span class="c1">// desugars to `Dynamic.init()`</span>
<span class="nf">instance</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// <var class="placeholder">❶</var> desugars to `Dynamic.dynamically<wbr></wbr>Call(instance)(with<wbr></wbr>Arguments: [1])`</span>
<span class="nf">instance</span><span class="p">(</span><span class="nv">a</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// <var class="placeholder">❷</var> desugars to `Dynamic.dynamically<wbr></wbr>Call(instance)(with<wbr></wbr>Keyword<wbr></wbr>Arguments: ["a": 1])`</span>
<span class="kt">Dynamic</span><span class="o">.</span><span class="nf">function</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// <var class="placeholder">❸</var> desugars to `Dynamic[dynamic<wbr></wbr>Member: "function"](1)`</span>
<span class="n">instance</span><span class="o">.</span><span class="nf">function</span><span class="p">(</span><span class="mi">1</span><span class="p">)</span> <span class="c1">// <var class="placeholder">❹</var> desugars to `instance[dynamic<wbr></wbr>Member: "function"](1)`</span>
</code></pre>
<dl>
<dt>❶</dt>
<dd>Calling an instance of <code>Dynamic</code>
invokes the <code>dynamically<wbr></wbr>Call(with<wbr></wbr>Arguments:)</code> method,
passing an array of arguments
and <code>Dynamic</code> as an implicit <code>self</code> argument.</dd>
<dt>❷</dt>
<dd>Calling an instance of <code>Dynamic</code>
with at least one labeled argument
invokes the <code>dynamically<wbr></wbr>Call(with<wbr></wbr>Keyword<wbr></wbr>Arguments:)</code> method,
passing the arguments in a <a href="/keyvaluepairs/"><code>Key<wbr></wbr>Value<wbr></wbr>Pairs</code> object</a>
and <code>Dynamic</code> as an implicit <code>self</code> argument.</dd>
<dt>❸</dt>
<dd>Calling <code>function</code> on the <code>Dynamic</code> type
invokes the static <code>dynamic<wbr></wbr>Member</code> subscript,
passing <code>"function"</code> as the key;
here, we call the returned anonymous closure.</dd>
<dt>❹</dt>
<dd>Calling <code>function</code> on an instance of <code>Dynamic</code>
invokes the <code>dynamic<wbr></wbr>Member</code> subscript,
passing <code>"function"</code> as the key;
here, we call the returned anonymous closure.</dd>
</dl>
<h4>
<a class="anchor" aria-hidden="true" id="dynamism-by-declaration-attributes" href="#dynamism-by-declaration-attributes"></a>Dynamism by Declaration Attributes</h4>
<p><code>@dynamic<wbr></wbr>Callable</code> and <code>@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</code>
are declaration attributes,
which means that they can’t be applied to existing declarations
through an extension.</p>
<p>So you can’t, for example,
<em>spice up</em> <code>Int</code> with <a href="https://github.com/rails/rails/blob/master/activesupport/lib/active_support/core_ext/array/access.r" rel="noopener noreferrer">Ruby-ish</a>
natural language accessors:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</span> <span class="c1">// ⚠︎ Error: '@dynamic<wbr></wbr>Member<wbr></wbr>Lookup' attribute cannot be applied to this declaration</span>
<span class="kd">extension</span> <span class="kt">Int</span> <span class="p">{</span>
<span class="kd">static</span> <span class="nf">subscript</span><span class="p">(</span><span class="n">dynamic<wbr></wbr>Member</span> <span class="nv">member</span><span class="p">:</span> <span class="kt">String</span><span class="p">)</span> <span class="o">-></span> <span class="kt">Int</span><span class="p">?</span> <span class="p">{</span>
<span class="k">let</span> <span class="nv">string</span> <span class="o">=</span> <span class="n">member</span><span class="o">.</span><span class="nf">replacing<wbr></wbr>Occurrences</span><span class="p">(</span><span class="nv">of</span><span class="p">:</span> <span class="s">"_"</span><span class="p">,</span> <span class="nv">with</span><span class="p">:</span> <span class="s">"-"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">formatter</span> <span class="o">=</span> <span class="kt">Number<wbr></wbr>Formatter</span><span class="p">()</span>
<span class="n">formatter</span><span class="o">.</span><span class="n">number<wbr></wbr>Style</span> <span class="o">=</span> <span class="o">.</span><span class="n">spell<wbr></wbr>Out</span>
<span class="k">return</span> <span class="n">formatter</span><span class="o">.</span><span class="nf">number</span><span class="p">(</span><span class="nv">from</span><span class="p">:</span> <span class="n">string</span><span class="p">)?</span><span class="o">.</span><span class="n">int<wbr></wbr>Value</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="c1">// ⚠︎ Error: Just to be super clear, this doesn't work</span>
<span class="kt">Int</span><span class="o">.</span><span class="n">forty_two</span> <span class="c1">// 42 (hypothetically, if we could apply `@dynamic<wbr></wbr>Member<wbr></wbr>Lookup` in an extension)</span>
</code></pre>
<p>Contrast this with <code>call<wbr></wbr>As<wbr></wbr>Function</code>,
which can be added to any type in an extension.</p>
<aside class="admonition info">
<p>For more information about these new language features,
check out the original Swift Evolution proposals:</p>
<ul>
<li><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0195-dynamic-member-lookup.md" title='SE-0195: Introduce User-defined \"Dynamic Member Lookup\" Types' rel="noopener noreferrer">SE-0195: Introduce User-defined “Dynamic Member Lookup” Types</a></li>
<li><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0216-dynamic-callable.md" title='SE-0216: Introduce user-defined dynamically \"callable\" types' rel="noopener noreferrer">SE-0216: Introduce - user-defined dynamically “callable” types</a></li>
<li><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md" title="SE-0249: Key Path Expressions as Functions" rel="noopener noreferrer">SE-0249: Key Path Expressions as Functions</a></li>
<li><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0252-keypath-dynamic-member-lookup.md" title="SE-0252: Key Path Member Lookup" rel="noopener noreferrer">SE-0252: Key - Path Member Lookup</a></li>
<li><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0253-callable.md" title="SE-0253: Callable values of user-defined nominal types" rel="noopener noreferrer">SE-0253: Callable values of user-defined nominal types</a></li>
</ul>
</aside>
<hr>
<p>There’s much more to talk about with
<code>@dynamic<wbr></wbr>Member<wbr></wbr>Lookup</code>, <code>@dynamic<wbr></wbr>Callable</code>, and <code>call<wbr></wbr>As<wbr></wbr>Function</code>,
and we look forward to covering them all in more detail
in future articles.</p>
<hr>
<p><em>But speaking of <del>Ruby</del><ins>Python</ins>…</em></p>
<h2>
<a class="anchor" aria-hidden="true" id="swift-_______" href="#swift-_______"></a>Swift ⨯ <strong>__</strong><strong>__</strong><strong>__</strong>_</h2>
<p>Adding to
<a href="/numericcast/">our list of <em>“What code is like”</em></a>:</p>
<blockquote>
<p>Code is like fan fiction.</p>
</blockquote>
<p>Sometimes to ship software,
you need to pair up and “ship” different technologies.</p>
<aside class="parenthetical">
<p>In a way,
the story of Swift is one of the great, tragic romances in modern computing;
how else might we describe the way
Objective-C sacrificed itself to make Swift possible?</p>
</aside>
<p>In building these features,
the “powers that be” have ordained that
<a href="https://github.com/tensorflow/swift/blob/master/docs/WhySwiftForTensorFlow.md" rel="noopener noreferrer">Swift replace Python for Machine Learning</a>.
Taking for granted that an incremental approach is best,
the way to make that happen is to allow
Swift to interoperate with Python
as seamlessly as it does with Objective-C.
And since Swift 4.2,
we’ve been <a href="https://www.tensorflow.org/swift/tutorials/python_interoperability" rel="noopener noreferrer">getting pretty close</a>.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">import</span> <span class="kt">Python</span>
<span class="k">let</span> <span class="nv">numpy</span> <span class="o">=</span> <span class="kt">Python</span><span class="o">.</span><span class="nf">import</span><span class="p">(</span><span class="s">"numpy"</span><span class="p">)</span>
<span class="k">let</span> <span class="nv">zeros</span> <span class="o">=</span> <span class="n">numpy</span><span class="o">.</span><span class="nf">ones</span><span class="p">([</span><span class="mi">2</span><span class="p">,</span> <span class="mi">4</span><span class="p">])</span>
<span class="cm">/* [[1, 1, 1, 1]
[1, 1, 1, 1]] */</span>
</code></pre>
<h2>
<a class="anchor" aria-hidden="true" id="the-externalities-of-dynamism" href="#the-externalities-of-dynamism"></a>The Externalities of Dynamism</h2>
<p>The promise of additive changes is that they don’t change anything
if you don’t want them to.
You can continue to write Swift code
remaining totally ignorant of the features described in this article
(most of us have so far).
But let’s be clear:
there are no cost-free abstractions.</p>
<p>Economics uses the term <a href="https://en.wikipedia.org/wiki/Externality" rel="noopener noreferrer"><dfn>negative externalities</dfn></a>
to describe indirect costs incurred by a decision.
Although you don’t pay for these features unless you use them,
we all shoulder the burden of a more complex language
that’s more difficult to teach, learn, document, and reason about.</p>
<hr>
<p>A lot of us who have been with Swift from the beginning
have grown weary of Swift Evolution.
And for those on the outside looking in,
it’s unfathomable that we’re wasting time on inconsequential “sugar” like this
instead of features that will <em>really</em> move the needle,
like <a href="https://gist.github.com/lattner/429b9070918248274f25b714dcfc7619" rel="noopener noreferrer"><code>async</code> / <code>await</code></a>.</p>
<p>In isolation,
each of these proposals is thoughtful and useful — <em>genuinely</em>.
We’ve already <a href="https://github.com/NSHipster/DBSCAN" rel="noopener noreferrer">had occasion</a> to use a few of them.
But it can be really hard to judge things on their own technical merits
when they’re steeped in emotional baggage.</p>
<p>Everyone has their own sugar tolerance,
and it’s often informed by what they’re accustomed to.
Being cognizant of the <a href="https://en.wikipedia.org/wiki/Drawbridge_mentality" rel="noopener noreferrer">drawbridge effect</a>,
I honestly can’t tell if I’m out of touch,
or if it’s <a href="https://knowyourmeme.com/memes/am-i-out-of-touch" rel="noopener noreferrer">the children who are wrong</a>…</p>
<link rel="stylesheet" type="text/css" href="/assets/articles/callable-1811de91ae8bdf936090533342a18ed820c717af1a764b8964a79f53965ee966d72ed43b646e12aeac7769e2411cd82b4a0579e4c88b571b9d0cbbf98d501c82.css" integrity="sha512-GBHeka6L35NgkFMzQqGO2CDHF68adkuJZKefU5Ze6WbXLtQ7ZG4Srqx3aeJBHNgrSgV55MiLVxudDLv5jVAcgg==" crossorigin="anonymous">
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>If like most of us, you aren’t tuned into the comings-and-goings of Swift Evolution, Xcode 11.4 is your first exposure to two new additions to the language: key path expressions as functions and callable values of user-defined nominal types.</p>RawRepresentable2020-01-29T00:00:00-08:002020-01-29T00:00:00-08:00https://nshipster.com/rawrepresentable
<p>Programming is about typing.
And programming languages are typically judged by how much they make you type —
in both senses of the word.</p>
<p>Swift is beloved for being able to save us a few keystrokes
without compromising safety or performance,
whether it’s through
implicit typing or
automatic synthesis of protocols like
<a href="/equatable-and-comparable/"><code>Equatable</code></a> and
<a href="/hashable/"><code>Hashable</code></a>.
But the <abbr title="Ice-T's 1991 single 'O.G. Original Gangster'">OG</abbr>
ergonomic feature of Swift is undoubtedly
automatic synthesis of <code>Raw<wbr></wbr>Representable</code> conformance
for enumerations with raw types.
You know…
the language feature that lets you do this:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="kt">Greeting</span><span class="p">:</span> <span class="kt">String</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">hello</span> <span class="o">=</span> <span class="s">"hello"</span>
<span class="k">case</span> <span class="n">goodbye</span> <span class="c1">// implicit raw value of "goodbye"</span>
<span class="p">}</span>
<span class="kd">enum</span> <span class="kt">Sort<wbr></wbr>Order</span><span class="p">:</span> <span class="kt">Int</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">ascending</span> <span class="o">=</span> <span class="o">-</span><span class="mi">1</span>
<span class="k">case</span> <span class="n">same</span> <span class="c1">// implicit raw value of 0</span>
<span class="k">case</span> <span class="n">descending</span> <span class="c1">// implicit raw value of 1</span>
<span class="p">}</span>
</code></pre>
<p>Though <em>“enum + RawValue”</em> has been carved into the oak tree of our hearts
since first we laid eyes on that language with a fast bird,
few of us have had occasion to consider
what <code>Raw<wbr></wbr>Representable</code> means outside of autosynthesis.
This week,
we invite you to do a little extra typing
and explore some untypical use cases for the <code>Raw<wbr></wbr>Representable</code> protocol.</p>
<hr><a id="get-on-with-it"></a>
<p>In Swift,
an enumeration can be declared with
<dfn>raw value syntax</dfn>.</p>
<p>According to <a href="https://developer.apple.com/documentation/swift/rawrepresentable" rel="noopener noreferrer">the documentation</a>:</p>
<blockquote>
<p>For any enumeration with a string, integer, or floating-point raw type,
the Swift compiler automatically adds <code>Raw<wbr></wbr>Representable</code> conformance.</p>
</blockquote>
<p>When developers first start working with Swift,
they inevitably run into situations where raw value syntax doesn’t work:</p>
<ul>
<li>Enumerations with raw values other than <code>Int</code> or <code>String</code>
</li>
<li>Enumerations with associated values</li>
</ul>
<p>Upon seeing those bright, red error sigils,
many of us fall back to a more conventional enumeration,
failing to realize that what we wanted to do wasn’t impossible,
but rather just slightly beyond what the compiler can do for us.</p>
<hr>
<h2>
<a class="anchor" aria-hidden="true" id="rawrepresentable-with-c-raw-value-types" href="#rawrepresentable-with-c-raw-value-types"></a>RawRepresentable with C Raw Value Types</h2>
<p>The primary motivation for raw value enumerations is
to improve interoperability.
Quoting again from the docs:</p>
<blockquote>
<p>Using the raw value of a conforming type
streamlines interoperation with Objective-C and legacy APIs.</p>
</blockquote>
<p>This is true of Objective-C frameworks in the Apple SDK,
which declare enumerations with <a href="/ns_enum-ns_options/"><code>NS_ENUM</code></a>.
But interoperability with other C libraries is often less seamless.</p>
<p>Consider the task of interfacing with
<a href="https://github.com/commonmark/cmark" rel="noopener noreferrer">libcmark</a>,
a library for working with Markdown according to the
<a href="http://spec.commonmark.org/" rel="noopener noreferrer">CommonMark spec</a>.
Among the imported data types is <code>cmark_node_type</code>,
which has the following C declaration:</p>
<pre class="highlight" data-lang="c"><code><span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
<span class="cm">/* Error status */</span>
<span class="n">CMARK_NODE_NONE</span><span class="p">,</span>
<span class="cm">/* Block */</span>
<span class="n">CMARK_NODE_DOCUMENT</span><span class="p">,</span>
<span class="n">CMARK_NODE_BLOCK_QUOTE</span><span class="p">,</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="n">CMARK_NODE_HEADING</span><span class="p">,</span>
<span class="n">CMARK_NODE_THEMATIC_BREAK</span><span class="p">,</span>
<span class="n">CMARK_NODE_FIRST_BLOCK</span> <span class="o">=</span> <span class="n">CMARK_NODE_DOCUMENT</span><span class="p">,</span>
<span class="n">CMARK_NODE_LAST_BLOCK</span> <span class="o">=</span> <span class="n">CMARK_NODE_THEMATIC_BREAK</span><span class="p">,</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="p">}</span> <span class="n">cmark_node_type</span><span class="p">;</span>
</code></pre>
<p>We can immediately see a few details that would need to be ironed out
along the path of Swiftification —
notably,
1) the sentinel <code>NONE</code> value, which would instead be represented by <code>nil</code>, and
2) the aliases for the first and last block values,
which wouldn’t be encoded by distinct enumeration cases.</p>
<p>Attempting to declare a Swift enumeration
with a raw value type of <code>cmark_node_type</code> results in a compiler error.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="kt">Node<wbr></wbr>Type</span><span class="p">:</span> <span class="n">cmark_node_type</span> <span class="p">{}</span> <span class="c1">// Error</span>
</code></pre>
<p>However,
that doesn’t totally rule out <code>cmark_node_type</code> from being a <code>Raw<wbr></wbr>Value</code> type.
Here’s what we need to make that happen:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="kt">Node<wbr></wbr>Type</span><span class="p">:</span> <span class="kt">Raw<wbr></wbr>Representable</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">document</span>
<span class="k">case</span> <span class="n">block<wbr></wbr>Quote</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="nf">init</span><span class="p">?(</span><span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="n">cmark_node_type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">raw<wbr></wbr>Value</span> <span class="p">{</span>
<span class="k">case</span> <span class="kt">CMARK_NODE_DOCUMENT</span><span class="p">:</span> <span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">document</span>
<span class="k">case</span> <span class="kt">CMARK_NODE_BLOCK_QUOTE</span><span class="p">:</span> <span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">block<wbr></wbr>Quote</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="k">default</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">nil</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="n">cmark_node_type</span> <span class="p">{</span>
<span class="k">switch</span> <span class="k">self</span> <span class="p">{</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">document</span><span class="p">:</span> <span class="k">return</span> <span class="kt">CMARK_NODE_DOCUMENT</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">block<wbr></wbr>Quote</span><span class="p">:</span> <span class="k">return</span> <span class="kt">CMARK_NODE_BLOCK_QUOTE</span>
<span class="err"><var class="placeholder">…</var></span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<p>It’s a far cry from being able to say <code>case document = CMARK_NODE_DOCUMENT</code>,
but this approach offers a reasonable solution
that falls within the existing semantics of the Swift standard library.</p>
<aside class="admonition info">
<p>You can omit a protocol’s associated type requirement
if the type can be determined from the protocol’s other requirements.</p>
<p>For instance,
the <code>Raw<wbr></wbr>Representable</code> protocol requires
a <code>raw<wbr></wbr>Value</code> property that returns a value of the associated <code>Raw<wbr></wbr>Value</code> type;
a conforming type can implicitly satisfy the associated type requirement
by declaring its property requirement with a concrete type
(in the example above, <code>cmark_node_type</code>).</p>
</aside>
<p>That debunks the myth about
<code>Int</code> and <code>String</code> being the only types that can be a raw value.
What about that one about associated values?</p>
<h2>
<a class="anchor" aria-hidden="true" id="rawrepresentable-and-associated-values" href="#rawrepresentable-and-associated-values"></a>RawRepresentable and Associated Values</h2>
<p>In Swift,
an enumeration case can have one or more <dfn>associated values</dfn>.
Associated values are a convenient way to introduce some flexibility
into the closed semantics of enumerations
and all the benefits they confer.</p>
<p><a href="https://github.com/apple/swift/blob/master/docs/Driver.md#output-file-maps" rel="noopener noreferrer">As the old adage goes</a>:</p>
<blockquote>
<p>There are three numbers in computer science: 0, 1, and N.</p>
</blockquote>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="kt">Number</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">zero</span>
<span class="k">case</span> <span class="n">one</span>
<span class="k">case</span> <span class="nf">n</span><span class="p">(</span><span class="kt">Int</span><span class="p">)</span>
<span class="p">}</span>
</code></pre>
<p>Because of the associated value on <code>n</code>,
the compiler can’t automatically synthesize an <code>Int</code> raw value type.
But that doesn’t mean we can’t roll up our sleeves and pick up the slack.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">extension</span> <span class="kt">Number</span><span class="p">:</span> <span class="kt">Raw<wbr></wbr>Representable</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">?(</span><span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">raw<wbr></wbr>Value</span> <span class="p">{</span>
<span class="k">case</span> <span class="mi">0</span><span class="p">:</span> <span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">zero</span>
<span class="k">case</span> <span class="mi">1</span><span class="p">:</span> <span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">one</span>
<span class="k">case</span> <span class="k">let</span> <span class="nv">n</span><span class="p">:</span> <span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="nf">n</span><span class="p">(</span><span class="n">n</span><span class="p">)</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="kt">Int</span> <span class="p">{</span>
<span class="k">switch</span> <span class="k">self</span> <span class="p">{</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">zero</span><span class="p">:</span> <span class="k">return</span> <span class="mi">0</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">one</span><span class="p">:</span> <span class="k">return</span> <span class="mi">1</span>
<span class="k">case</span> <span class="kd">let</span> <span class="o">.</span><span class="nf">n</span><span class="p">(</span><span class="n">n</span><span class="p">):</span> <span class="k">return</span> <span class="n">n</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="kt">Number</span><span class="p">(</span><span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="mi">1</span><span class="p">)</span> <span class="c1">// .one</span>
</code></pre>
<p>Another myth busted!</p>
<p>Let’s continue this example to clear up
a misconception we found in the documentation.</p>
<h2>
<a class="anchor" aria-hidden="true" id="rawrepresentable-as-raw-values-for-another-enumeration" href="#rawrepresentable-as-raw-values-for-another-enumeration"></a>RawRepresentable as Raw Values for Another Enumeration</h2>
<p>Consider the following from
the <code>Raw<wbr></wbr>Representable</code> docs:</p>
<blockquote>
<p>For any enumeration with a string, integer, or floating-point raw type,
the Swift compiler automatically adds <code>Raw<wbr></wbr>Representable</code> conformance.</p>
</blockquote>
<p>This is, strictly speaking, true.
But it actually under-sells what the compiler can do.
The actual requirements for raw values are as follows:</p>
<ul>
<li>The raw value type must be <code>Equatable</code>
</li>
<li>The raw value type must be
<code>Expressible<wbr></wbr>By<wbr></wbr>Integer<wbr></wbr>Literal</code>,
<code>Expressible<wbr></wbr>By<wbr></wbr>Float<wbr></wbr>Literal</code>, or
<code>Expressible<wbr></wbr>By<wbr></wbr>String<wbr></wbr>Literal</code>
</li>
<li>The raw value for each enumeration case must be a literal
(or unspecified, in which case the value is inferred)</li>
</ul>
<p>Let’s see what happens if we satisfy that for our <code>Number</code> type from before.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">extension</span> <span class="kt">Number</span><span class="p">:</span> <span class="kt">Equatable</span> <span class="p">{}</span> <span class="c1">// conformance is automatically synthesized</span>
<span class="kd">extension</span> <span class="kt">Number</span><span class="p">:</span> <span class="kt">Expressible<wbr></wbr>By<wbr></wbr>Integer<wbr></wbr>Literal</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">(</span><span class="n">integer<wbr></wbr>Literal</span> <span class="nv">value</span><span class="p">:</span> <span class="kt">Int</span><span class="p">)</span> <span class="p">{</span>
<span class="k">self</span><span class="o">.</span><span class="nf">init</span><span class="p">(</span><span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="n">value</span><span class="p">)</span><span class="o">!</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="o">-</span><span class="mi">1</span> <span class="k">as</span> <span class="kt">Number</span> <span class="c1">// .n(-1)</span>
<span class="mi">0</span> <span class="k">as</span> <span class="kt">Number</span> <span class="c1">// .zero</span>
<span class="mi">1</span> <span class="k">as</span> <span class="kt">Number</span> <span class="c1">// .one</span>
<span class="mi">2</span> <span class="k">as</span> <span class="kt">Number</span> <span class="c1">// .n(2)</span>
</code></pre>
<p>If we declare a new enumeration,
<code lang="zh-Hans">数</code>
(literally “Number”)
with a <code>Number</code> raw value…</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="nv">数</span><span class="p">:</span> <span class="kt">Number</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">一</span> <span class="o">=</span> <span class="mi">1</span>
<span class="k">case</span> <span class="n">二</span> <span class="o">=</span> <span class="mi">2</span>
<span class="k">case</span> <span class="n">三</span> <span class="o">=</span> <span class="mi">3</span>
<span class="p">}</span>
<span class="n">数</span><span class="o">.</span><span class="n">二</span> <span class="c1">// 二</span>
<span class="n">数</span><span class="o">.</span><span class="n">二</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span> <span class="c1">// .n(2)</span>
<span class="n">数</span><span class="o">.</span><span class="n">二</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span> <span class="c1">// 2</span>
</code></pre>
<p><em>Wait, that actually works? Neat!</em></p>
<p>What’s really interesting is that our contrived little enumeration type
benefits from the same, small memory footprint
that you get from using enumerations in more typical capacities:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kt">Memory<wbr></wbr>Layout</span><span class="o">.</span><span class="nf">size</span><span class="p">(</span><span class="nv">of<wbr></wbr>Value</span><span class="p">:</span> <span class="n">数</span><span class="o">.</span><span class="n">三</span><span class="p">)</span> <span class="c1">// 1 (bytes)</span>
<span class="kt">Memory<wbr></wbr>Layout</span><span class="o">.</span><span class="nf">size</span><span class="p">(</span><span class="nv">of<wbr></wbr>Value</span><span class="p">:</span> <span class="n">数</span><span class="o">.</span><span class="n">三</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span><span class="p">)</span> <span class="c1">// 9 (bytes)</span>
<span class="kt">Memory<wbr></wbr>Layout</span><span class="o">.</span><span class="nf">size</span><span class="p">(</span><span class="nv">of<wbr></wbr>Value</span><span class="p">:</span> <span class="n">数</span><span class="o">.</span><span class="n">三</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span><span class="o">.</span><span class="n">raw<wbr></wbr>Value</span><span class="p">)</span> <span class="c1">// 8 (bytes)</span>
</code></pre>
<p>If raw values aren’t limited to <code>String</code> or <code>Int</code>,
as once believed,
you may start to wonder:
<em>How far can we take this?</em></p>
<h2>
<a class="anchor" aria-hidden="true" id="rawrepresentable-with-metatype-raw-values" href="#rawrepresentable-with-metatype-raw-values"></a>RawRepresentable with Metatype Raw Values</h2>
<p>Probably the biggest selling point of enumerations in Swift
is how they encode a closed set of values.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">enum</span> <span class="kt">Element</span> <span class="p">{</span>
<span class="k">case</span> <span class="n">earth</span><span class="p">,</span> <span class="n">water</span><span class="p">,</span> <span class="n">air</span><span class="p">,</span> <span class="n">fire</span>
<span class="p">}</span>
</code></pre>
<p>Unfortunately,
there’s no equivalent way to “close off” which types conform to a protocol.</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">public</span> <span class="kd">protocol</span> <span class="kt">Elemental</span> <span class="p">{}</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Earth</span><span class="p">:</span> <span class="kt">Elemental</span> <span class="p">{}</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Water</span><span class="p">:</span> <span class="kt">Elemental</span> <span class="p">{}</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Air</span><span class="p">:</span> <span class="kt">Elemental</span> <span class="p">{}</span>
<span class="kd">public</span> <span class="kd">struct</span> <span class="kt">Fire</span><span class="p">:</span> <span class="kt">Elemental</span> <span class="p">{}</span>
</code></pre>
<p>Without built-in support for type unions
or an analog to the <code>open</code> access modifier for classes,
there’s nothing that an API provider can do,
for example,
to prevent a consumer from doing the following:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">struct</span> <span class="kt">Aether</span><span class="p">:</span> <span class="kt">Elemental</span> <span class="p">{}</span>
</code></pre>
<p>Any switch statement over a type-erased <code>Elemental</code> value
using <code>is</code> checks will necessarily have a <code>default</code> case.</p>
<p>Until we have a first-class language feature for providing such guarantees,
we can recruit enumerations and raw values for a reasonable approximation:</p>
<pre class="highlight" data-lang="Swift"><code><span class="kd">extension</span> <span class="kt">Element</span><span class="p">:</span> <span class="kt">Raw<wbr></wbr>Representable</span> <span class="p">{</span>
<span class="nf">init</span><span class="p">?(</span><span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="kt">Elemental</span><span class="o">.</span><span class="k">Type</span><span class="p">)</span> <span class="p">{</span>
<span class="k">switch</span> <span class="n">raw<wbr></wbr>Value</span> <span class="p">{</span>
<span class="k">case</span> <span class="k">is</span> <span class="kt">Earth</span><span class="o">.</span><span class="k">Type</span><span class="p">:</span>
<span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">earth</span>
<span class="k">case</span> <span class="k">is</span> <span class="kt">Water</span><span class="o">.</span><span class="k">Type</span><span class="p">:</span>
<span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">water</span>
<span class="k">case</span> <span class="k">is</span> <span class="kt">Air</span><span class="o">.</span><span class="k">Type</span><span class="p">:</span>
<span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">air</span>
<span class="k">case</span> <span class="k">is</span> <span class="kt">Fire</span><span class="o">.</span><span class="k">Type</span><span class="p">:</span>
<span class="k">self</span> <span class="o">=</span> <span class="o">.</span><span class="n">fire</span>
<span class="k">default</span><span class="p">:</span>
<span class="k">return</span> <span class="kc">nil</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="k">var</span> <span class="nv">raw<wbr></wbr>Value</span><span class="p">:</span> <span class="kt">Elemental</span><span class="o">.</span><span class="k">Type</span> <span class="p">{</span>
<span class="k">switch</span> <span class="k">self</span> <span class="p">{</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">earth</span><span class="p">:</span> <span class="k">return</span> <span class="kt">Earth</span><span class="o">.</span><span class="k">self</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">water</span><span class="p">:</span> <span class="k">return</span> <span class="kt">Water</span><span class="o">.</span><span class="k">self</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">air</span><span class="p">:</span> <span class="k">return</span> <span class="kt">Air</span><span class="o">.</span><span class="k">self</span>
<span class="k">case</span> <span class="o">.</span><span class="nv">fire</span><span class="p">:</span> <span class="k">return</span> <span class="kt">Fire</span><span class="o">.</span><span class="k">self</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre>
<aside class="admonition warning">
<p>This doesn’t work for protocols with an associated type requirement.
Sorry to disappoint anyone looking for an easy workaround for
<em>“Protocol can only be used as a generic constraint
because it has Self or associated type requirements”</em></p>
</aside>
<hr>
<p>Returning one last time to the docs,
we’re reminded that:</p>
<blockquote>
<p>With a <code>Raw<wbr></wbr>Representable</code> type,
you can switch back and forth between
a custom type and an associated <code>Raw<wbr></wbr>Value</code> type
without losing the value of the original <code>Raw<wbr></wbr>Representable</code> type.</p>
</blockquote>
<p>From the earliest days of the language,
<code>Raw<wbr></wbr>Representable</code> has been relegated to
the thankless task of C interoperability.
But looking now with a fresh set of eyes,
we can now see it for in all its
<a href="https://en.wikipedia.org/wiki/Injective_function" rel="noopener noreferrer">injective</a> glory.</p>
<p>So the next time you find yourself with an enumeration
whose cases broker in discrete, defined counterparts,
consider adopting <code>Raw<wbr></wbr>Representable</code> to formalize the connection.</p>
Matttmattt@nshipster.comhttps://nshipster.com/authors/mattt/<p>Programming is about typing. And programming languages are typically judged by how much they make you type — in both senses of the word.</p>