<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Hackthology</title><link href="https://hackthology.com/" rel="alternate"/><link href="https://hackthology.com/feeds/all.atom.xml" rel="self"/><id>https://hackthology.com/</id><updated>2026-03-19T00:00:00-04:00</updated><entry><title>Taming the Variants: Multi-Architecture Continuous Testing at Google</title><link href="https://hackthology.com/taming-the-variants-multi-architecture-continuous-testing-at-google.html" rel="alternate"/><published>2026-03-19T00:00:00-04:00</published><updated>2026-03-19T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, Sushmita Azad, et al.</name></author><id>tag:hackthology.com,2026-03-19:/taming-the-variants-multi-architecture-continuous-testing-at-google.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Sushmita Azad, Chandrakanth Chittappa, Ali Esmaeeli, Laura Macaddino, Sam Manfreda, David Margolin, Dharma Naidu, Sabuj Pattanayek, Sachin Sable, Ruslan Sakevych, Dushyant Acharya, Adrian Berding, Kevin Crossan, Wolff Dobson, Avi Kondareddy, and Abhayendra Singh.
&lt;em&gt;Taming the Variants: Multi-Architecture Continuous Testing at Google&lt;/em&gt;. &lt;a href="https://conf.researchr.org/home/icst-2026"&gt;ICST 2026&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="http://tba"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2026.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/taming-the-variants-multi-architecture-continuous-testing-at-google.html"&gt;WEB …&lt;/a&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Sushmita Azad, Chandrakanth Chittappa, Ali Esmaeeli, Laura Macaddino, Sam Manfreda, David Margolin, Dharma Naidu, Sabuj Pattanayek, Sachin Sable, Ruslan Sakevych, Dushyant Acharya, Adrian Berding, Kevin Crossan, Wolff Dobson, Avi Kondareddy, and Abhayendra Singh.
&lt;em&gt;Taming the Variants: Multi-Architecture Continuous Testing at Google&lt;/em&gt;. &lt;a href="https://conf.researchr.org/home/icst-2026"&gt;ICST 2026&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="http://tba"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2026.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/taming-the-variants-multi-architecture-continuous-testing-at-google.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2026.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Enterprises are increasingly adopting multiple general-purpose computer
architectures in the data center. This leads to new testing challenges as it
creates demand to qualify the software for the additional architectures. Naively
double-testing all software for both architectures is costly and unnecessary.
Further, reconfiguring CI/CD to take advantage of the new architecture can be
non-trivial at scale. This paper introduces CI/CD &lt;em&gt;variants&lt;/em&gt; and an optimized
testing cycle to solve these twin challenges. We empirically evaluate our
solution's impact on human and machine expenses using 44k projects at Google on
real production data. First, we estimate saving ~25% of machine expenses at the
negligible cost of a few delayed breakage detections per day. Second, we
estimate a 90+% reduction in human cost for migrating the configuration. All
features described in this paper are now Generally Available at Google and we
report this as an empirical case study in scaling CI/CD to new architectures.&lt;/p&gt;
&lt;h1 id="sec:introduction"&gt;I. Introduction&lt;/h1&gt;

&lt;p&gt;Over the last decade, hyperscalers have introduced multiple general-purpose
architectures into the data center [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;]. At Google, this creates challenges for our
very large scale continuous integration and delivery platforms (CI/CD) [&lt;a href="#ref-Memon2017"&gt;2&lt;/a&gt;]. We aim
to enable adoption by ensuring the software is appropriately built and tested.
We face two challenges.&lt;/p&gt;
&lt;p&gt;First, a high performance Continuous Integration [&lt;a href="#ref-Fowler2006"&gt;3&lt;/a&gt;] system identifies novel build
and test failures the moment they are introduced to the source repository. This
enables developers and automation to find and fix these failures as soon as
possible. The sooner a failure is found, the cheaper it is to fix. For
instance, a bug-introducing change can be automatically reverted without
review, provided there haven't been further changes that would cause merge
conflicts [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Henderson2024"&gt;5&lt;/a&gt;]. Finding failures as quickly as
possible is in tension with running tests as cheaply as possible (achieved by
adjusting testing frequency). Can we add the new architecture without
constantly retesting on both platforms?&lt;/p&gt;
&lt;p&gt;Second, when a new compute architecture is introduced, all projects need to
determine:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Is the project's code build-compatible?&lt;/li&gt;
&lt;li&gt;Do the project's tests pass on the new architecture?&lt;/li&gt;
&lt;li&gt;Is the project's runtime performance acceptable?&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Answering these questions requires modifying the CI/CD configuration to
additionally build, test, and deploy the code to the new architecture(s). This
mechanical, unrewarding task can be a costly undertaking for an organization.
Prior to the start of this project we estimate that it took an &lt;em&gt;expert&lt;/em&gt; from the
central Arm migration team (whose primary job was to perform this
qualification) hours of hands-on time just to make the required configuration
changes to a single project. Google operates a monorepo with billions of lines
of source code and over 100,000 binaries. Making manual changes to every
project was impractical [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;The two challenges are intertwined. We neither want to double test nor do we
want our users to manually edit configuration files. Further, manual changes
create bespoke additional CI/CD configurations requiring future maintenance.
While guides exist, users don't always follow instructions. This means that the
CI/CD systems would need complex logic to link functionally-equivalent x86 and
Arm configurations.&lt;/p&gt;
&lt;p&gt;Without reliably linking configurations, the system cannot optimize the testing
process. We solved both problems by introducing &lt;em&gt;variants&lt;/em&gt;: automatically
&lt;em&gt;re&lt;/em&gt;configured user projects. A variant adapts the original configuration for
each targeted platform. This flexible infrastructure also supports variants for
compiler optimization level, address and memory sanitization, and other build
modifications.&lt;/p&gt;
&lt;p&gt;Because the variants are automatically configured, they are also &lt;em&gt;structured&lt;/em&gt;.
This allows our systems to make consistent choices on how building and testing
should occur for each variant. Our primary CI system, the Test Automation
Platform (TAP) [&lt;a href="#ref-Memon2017"&gt;2&lt;/a&gt;, &lt;a href="#ref-Leong2019"&gt;6&lt;/a&gt;, &lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Henderson2024"&gt;5&lt;/a&gt;, &lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;], introduced a new testing mode: &lt;em&gt;Target Comprehensive Cycles&lt;/em&gt;,
optimizing the cost of testing across multiple architectures. Our CD system
also adopted Target Comprehensive cycles to realize the cost savings. However,
to prevent bugs escaping to production, it introduced &lt;em&gt;Late Stage Testing&lt;/em&gt;. This
phase executes the remaining tests prior to production, but at a lower
frequency.&lt;/p&gt;
&lt;h2 id="contributions"&gt;A. Contributions&lt;/h2&gt;

&lt;p&gt;We detail our solution, &lt;em&gt;Variants&lt;/em&gt;, and empirically analyze its efficacy and
performance. We measure the realized human migration savings from variants and
the machine costs avoided by &lt;em&gt;Target Comprehensive&lt;/em&gt; (TC) testing. Finally,
because optimizations involve a trade-off, we examine the productivity cost of
delaying the detection of bugs by skipping tests.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Variants&lt;/em&gt; are generally available and used by 44k projects. We present a
    large-scale empirical case study on the efficacy of our methods using
    production data. We estimated both the human and machine savings and the
    productivity cost of delayed breakage detection.&lt;/li&gt;
&lt;li&gt;A new &lt;em&gt;Target Comprehensive&lt;/em&gt; (TC) scheduling mode prevents doubled testing
    costs. We measured savings of approximately ~25% over the naive double
    testing strategy.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Late-Stage Testing&lt;/em&gt; (LST) shifts test load into later, less frequent, parts
    of the CI/CD pipeline. This executes test configurations skipped by TC prior
    to user release. Late-stage testing failures occur less than 0.1% of the
    time.&lt;/li&gt;
&lt;li&gt;Automated configuration for building and testing for alternative
    architectures reduces migration effort by approximately 90%.&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="sec:background"&gt;II. Background&lt;/h1&gt;

&lt;p&gt;At Google, developers use multiple tools as part of their CI/CD system. Testing
is typically handled by TAP (the Test Automation Platform), which performs
testing both prior to code being submitted (presubmit testing) and after code
is submitted to the mainline branch of the mono-repository. TAP only handles
tests that fit on a single machine and are &lt;em&gt;version hermetic&lt;/em&gt; (i.e. only use
code from a single version and do not make network calls). Some teams need
larger integration tests that need multiple machines or need to compare
behavior between the test environment or a production environment. These teams
additionally use an Integration Testing platform. While our work on variants is
also used by the Integration Testing platform, we constrain the focus of this
paper to TAP.&lt;/p&gt;
&lt;p&gt;TAP runs &lt;em&gt;testing cycles&lt;/em&gt;, where all projects and their &lt;em&gt;Bazel targets&lt;/em&gt; are
batched together at the same version [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;]. Once all the targets for a project have
executed, TAP computes a &lt;em&gt;Project Status&lt;/em&gt; (ex. &lt;code&gt;PASSING&lt;/code&gt;, &lt;code&gt;FAILING&lt;/code&gt;, ...). A
&lt;code&gt;PASSING&lt;/code&gt; status enables the next service in the CI/CD system to take over:
Rapid.&lt;/p&gt;
&lt;p&gt;Rapid is a generalized CI/CD workflow execution engine. It is similar in
capability to commercial and open source systems such as GitHub Actions or
Jenkins. It allows developers to orchestrate a complex series of processes to
build production packages, trigger integration tests, and trigger production
deployments. While Rapid's capabilities are very general, all Rapid "releases"
start with a &lt;em&gt;Candidate Creation&lt;/em&gt; phase, during which testing results from TAP
and other systems are verified before the production binary package is
created. A developer may configure some tests to only trigger in Rapid instead
of the more common and recommended method of using TAP.&lt;/p&gt;
&lt;p&gt;Due to the general complexity of software development at Google, we have a
managed platform that is built on top of all of this called &lt;em&gt;Urfin&lt;/em&gt;. It
provides a streamlined intent-based mechanism for developers to configure their
projects. Urfin standardizes the workflows that Rapid executes and the
production environments. When a project is configured by Urfin (instead of
"Rapid Native"), we are able to automatically determine what workflows modify
production environments (versus those used for additional verification or
validation with non-production data or users). This structural distinction is
relevant for our Late-Stage Testing strategy and empirical evaluation,
motivating our introduction of these terms.&lt;/p&gt;
&lt;h2 id="glossary"&gt;A. Glossary of Google Terminology&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Piper&lt;/strong&gt; – The version control system used at Google [&lt;a href="#ref-Potvin2016"&gt;8&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Changelist (CL)&lt;/strong&gt; – A commit in Piper. CLs have integer numbers and
    submitted CLs have monotonically increasing numbers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bazel&lt;/strong&gt; – The build tool used at Google: &lt;a href="https://bazel.build/"&gt;https://bazel.build/&lt;/a&gt; [&lt;a href="#ref-Winters2020"&gt;9&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Target&lt;/strong&gt; – The compilation unit in Bazel. TAP doesn't run individual test
    methods or even test classes / suites. Instead, it runs Bazel test targets
    that may contain many test methods and classes.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Forge&lt;/strong&gt; – The large remote build execution cluster used by Bazel [&lt;a href="#ref-Winters2020"&gt;9&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Build System&lt;/strong&gt; – A collection of services for batching and running builds
    in production [&lt;a href="#ref-Winters2020"&gt;9&lt;/a&gt;, &lt;a href="#ref-Wang2020"&gt;10&lt;/a&gt;, &lt;a href="#ref-Wang2021"&gt;11&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TAP&lt;/strong&gt; – The primary continuous integration platform [&lt;a href="#ref-Gupta2011"&gt;12&lt;/a&gt;, &lt;a href="#ref-Bland2012"&gt;13&lt;/a&gt;, &lt;a href="#ref-Micco2012"&gt;14&lt;/a&gt;, &lt;a href="#ref-Micco2013"&gt;15&lt;/a&gt;, &lt;a href="#ref-Elbaum2014"&gt;16&lt;/a&gt;, &lt;a href="#ref-Memon2017"&gt;2&lt;/a&gt;, &lt;a href="#ref-Spragins2018"&gt;17&lt;/a&gt;, &lt;a href="#ref-Leong2019"&gt;6&lt;/a&gt;, &lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Henderson2024"&gt;5&lt;/a&gt;, &lt;a href="#ref-Hoang2024"&gt;18&lt;/a&gt;, &lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rapid&lt;/strong&gt; – The primary workflow automation tool use to orchestrate release
    processes [&lt;a href="#ref-Winters2020"&gt;9&lt;/a&gt;].&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Urfin&lt;/strong&gt; – A managed platform built on top of tools like TAP and Rapid that
    dramatically simplifies configuration and usage of release automation.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Rapid Native&lt;/strong&gt; – Our term for release projects that don't use the managed
    platform (Urfin). These projects have non-standard workflows and
    configurations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Blueprint File&lt;/strong&gt; – The common configuration file format used by TAP, Rapid,
    and many other tools. It is defined in a bespoke configuration language
    (NCL).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="sec:background:config"&gt;B. Configuring TAP and Rapid&lt;/h2&gt;

&lt;p&gt;TAP, Rapid, and other tools are configured in &lt;em&gt;Blueprint files&lt;/em&gt;. Blueprints are
written in a bespoke, proprietary configuration language (NCL). NCL is a
high-level functional language for describing and manipulating protocol
buffers. It supports complex data types, functions, and libraries. The power of
the language has led to proliferation of complex Blueprints that are difficult
to mechanically modify for &lt;em&gt;Large Scale Changes&lt;/em&gt; [&lt;a href="#ref-Winters2020"&gt;9&lt;/a&gt;], even with the support of
modern LLM tooling [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;Users specify in the Blueprints what TAP should run by defining &lt;em&gt;TAP Projects&lt;/em&gt;.
A TAP Project has &lt;em&gt;patterns&lt;/em&gt; (that match Bazel targets), Bazel flags (which
control compilation modes such as building for Arm), a maximum execution
frequency, and notification routing. Rapid Projects are also defined in
Blueprints. These projects can be extremely complex. We will focus just on how
users configure testing. A Rapid Project can be &lt;em&gt;gated&lt;/em&gt; on one or more TAP
Projects, which must all pass. When they all pass it is called a &lt;em&gt;Shared Green&lt;/em&gt;
or a &lt;em&gt;Golden&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Urfin, the managed platform, generates Blueprints (and other configuration)
from a higher level "intent"-based configuration format. Urfin's configuration
is less flexible than Blueprints and large scale changes are easier to
mechanize.&lt;/p&gt;
&lt;h2 id="tap-overview"&gt;C. TAP Overview&lt;/h2&gt;

&lt;p&gt;The continuous integration system, TAP, has two phases: TAP Presubmit and TAP
Postsubmit. Presubmit runs as part of the developer's "code review loop",
executing when they send out changes for review and when they attempt to submit
the code to the repository. Because of the massive scale of the repository, TAP
Presubmit does not conduct exhaustive testing. Instead, it operates in a
"best-effort" mode that attempts to prevent most breakages from escaping into
submitted code. TAP Presubmit uses static build dependence-based test selection [&lt;a href="#ref-Gupta2011"&gt;12&lt;/a&gt;, &lt;a href="#ref-Elbaum2014"&gt;16&lt;/a&gt;],
machine learning driven selection [&lt;a href="#ref-Spragins2018"&gt;17&lt;/a&gt;], and machine learning driven flakiness
mitigation [&lt;a href="#ref-Hoang2024"&gt;18&lt;/a&gt;]. In this paper, we are focused on TAP Postsubmit's behavior and look
forward to analyzing changes to Presubmit in a future manuscript.&lt;/p&gt;
&lt;p&gt;TAP Postsubmit runs tests after changes have been submitted. While it
originally ran the &lt;em&gt;affected&lt;/em&gt; tests (based on the build graph) at every single
change [&lt;a href="#ref-Bland2012"&gt;13&lt;/a&gt;], this quickly proved too expensive. Today, Postsubmit runs periodically
and avoids running if its Forge is too full. This strategy effectively batches
many changes together, leading to a search problem when breakages occur [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Henderson2024"&gt;5&lt;/a&gt;].
We call these "periodic runs" &lt;em&gt;Fully Comprehensive&lt;/em&gt; (FC) testing cycles since TAP
runs all tests in all projects with all Bazel flag configurations that have
been affected since the last cycle. Because FC cycles currently run at a
maximum rate of once per hour, in 2025 we introduced a faster ML driven cycle
to find breakages faster called &lt;em&gt;Speculative&lt;/em&gt; cycles [&lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;]. Speculative cycles only
run targets whose executions are likely to reveal novel breakages.&lt;/p&gt;
&lt;h2 id="rapid-overview"&gt;D. Rapid Overview&lt;/h2&gt;

&lt;p&gt;Rapid runs user-defined "workflows" that are generally triggered off of a
schedule. The first workflow, &lt;em&gt;Candidate Creation&lt;/em&gt;, always creates a release
"candidate", which includes verifying test results and building the binary
packages. When Rapid is configured via Urfin, the managed platform, the
workflows are standardized and structured such that we know which workflows can
change production environments. Rapid's schedule for Candidate Creation
defaults to once every 2 hours in Urfin, and production pushes happen once per
day on business days. Many Rapid Native projects are configured at a slower
cadence.&lt;/p&gt;
&lt;p&gt;When verifying test results, Rapid can execute any tests not previously run.
Because it evolved independently from TAP, Rapid has always maintained its own
execution logic, which historically led to redundant and wasteful testing
effort. As part of this project, Rapid now recognizes which tests TAP has
already completed; by eliminating these redundant executions, we have also
reduced the risk of a release being blocked by flaky test failures.&lt;/p&gt;
&lt;h1 id="sec:configuring-architecture"&gt;III. Configuring CI/CD for the new Architecture&lt;/h1&gt;

&lt;p&gt;In order for a project to take advantage of the new compute platform, it needs
to be built and tested for the new platform. Practically, this requires
adjusting its Blueprint (the configuration, &lt;a href="#sec:background:config"&gt;Section II-B&lt;/a&gt;) to
additionally instruct the CI/CD systems to build and test for the new platform.&lt;/p&gt;
&lt;p&gt;Listing 1 provides an example of the work it takes to manually create new CI/CD
projects to build and test a binary for Arm. As shown in the listing, multiple
sections need to be modified and these modifications cannot always be done
atomically. Depending on the complexity of a project's configuration, it may
require refactoring of the functions or libraries used to generate the various
components (such as buildable units) to generate both Arm and x86 versions of
those components. Approximately 25% of active Rapid projects have complex
Blueprints requiring manual modifications.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listing 1: From a developers perspective, lines of code needed to manually configure arm-based testing and release automation.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// I need to manually create Arm Buildable Units&lt;/span&gt;
&lt;span class="n"&gt;local&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arm_buildable_unit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BuildableUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;arm_ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;build_flags&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--compilation_mode=opt&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--cpu=arm&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;test_patterns&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//ex/pattern/...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-//ex/pattern/x86tests/...&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// And associate them with a new Arm TAP Project&lt;/span&gt;
&lt;span class="n"&gt;blueprint_file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BlueprintFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;continuous_tests&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;arm_ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;arm_ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;buildable_units&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="n"&gt;buildable_unit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;arm_buildable_unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;continuous_tests&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// which I add to my Release project&amp;#39;s Golden Info.&lt;/span&gt;
&lt;span class="n"&gt;golden_changelist&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GoldenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tap_build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GoldenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tap_build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GoldenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tap_build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GoldenInfo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tap_build&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="c1"&gt;// create duplicate release with Arm config.&lt;/span&gt;
&lt;span class="n"&gt;ReleasableUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_multiarch_release&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_names&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex.arm&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_config.arm&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// and I add --fat_package_cpu=k8,arm to all Release BuildableUnits&lt;/span&gt;
&lt;span class="n"&gt;BuildableUnit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ex_package&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;mpm_patterns&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//ex/pattern/...&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;test_patterns&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;//ex/pattern/...&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-//ex/pattern/x86tests/...&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;build_flags&lt;/span&gt;&lt;span class="o"&gt;=[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--fat_mpm_cpu=k8, arm&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Additionally, as the central team gained experience migrating our largest
binaries to Arm they discovered a few best practices. For instance, it was
better to already have continuous testing results before going to the product
team with requested changes. This allowed the product team to better assess the
changes. However, setting up a normal CI pipeline for running the Arm tests
before notifying the product team is a recipe for friction and pushback, as
there are likely to be real and noisy failures. Thus, the central porting team
needed a way to run the tests in the same way the product team would.&lt;/p&gt;
&lt;p&gt;To solve this problem, we came up with the idea of having "shadow CI projects"
that would be duplicates of the production CI projects, but turn off
notifications, switch the cost accounting, and add the necessary flags to run
the project on Arm. To create these "shadow CI projects", the central team had
to create Blueprint files in their own directory that imported and modified the
target project's configuration. While the central team had a process that let
them drive migrations to increase the migration rate, we needed a more
automated solution.&lt;/p&gt;
&lt;h2 id="variants"&gt;A. Variants&lt;/h2&gt;

&lt;p&gt;The experiences of the central migration team led us to create &lt;em&gt;Variant&lt;/em&gt;
projects. These are automatically generated CI Projects that take the
user-supplied configuration and adjust it to use different Bazel flags. For
example, adding the flag &lt;code&gt;--cpu=arm&lt;/code&gt; will compile and test for Arm. Variants
are general and allow us, as the CI system owner, to dynamically define new
variants as needed.&lt;/p&gt;
&lt;p&gt;&lt;span id="fig:project-structure" label="fig:project-structure"&gt;
  &lt;a href="images/icst-2026/fig1.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;&lt;/em&gt;
  &lt;img alt="Figure 1" src="images/icst-2026/fig1.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure 1 shows the structure of how Rapid and TAP interact with the new &lt;code&gt;~arm&lt;/code&gt;
variant. Each TAP project has a copy made (potentially removing or adding
targets as necessary), and Rapid utilizes the shared green between the original
projects and the variant projects when creating release candidates. The new TAP
projects are largely identical to the original project, but we have the ability
to globally modify any setting in the variant projects we choose. We used this
to implement multiple "modes" for a variant: &lt;code&gt;DISABLED&lt;/code&gt;, &lt;code&gt;SHADOW&lt;/code&gt;, and
&lt;code&gt;RELEASE&lt;/code&gt;. We were then able to launch variants in &lt;code&gt;SHADOW&lt;/code&gt; mode globally with
no user involvement or toil from the central migration team. This allowed
collection of repository wide testing results to guide porting effort. When a
project is ready to adopt Arm, a simple top-level field lets them switch to
&lt;code&gt;RELEASE&lt;/code&gt; mode.&lt;/p&gt;
&lt;p&gt;Variant projects were designed to be largely &lt;em&gt;identical&lt;/em&gt; to regular user
configured projects. This meant most portions of TAP, downstream systems, and
API clients initially worked unmodified with the variants. However, we
eventually introduced differentiated behavior. For instance, we changed the web
user interface to explicitly show the user the relationships between the
projects when a variant is enabled and has valid targets.&lt;/p&gt;
&lt;h2 id="porting-process"&gt;B. Porting Process with Variants&lt;/h2&gt;

&lt;p&gt;By default, all projects run their Arm variant in shadow mode. Once a project's
tests all pass on Arm it becomes eligible for enabling the Arm release (but not
necessarily running in production [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;]). To enable the Arm release, we added a
single top level field to the Blueprint (plus service level opt-outs) that
enables Arm for all CI and Release projects defined in the Blueprint. This
field &lt;code&gt;arm_variant_mode&lt;/code&gt; is shown in Listing 2.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Listing 2: Simplified variant configuration&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;blueprint_file&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;BlueprintFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;arm_variant_mode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;devtools_blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;VariantMode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;VARIANT_MODE_RELEASE&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;continuous_tests&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;blueprint&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ContinuousTest&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;buildable_unit_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;example&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;buildable_units&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;buildable_unit&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This new field drastically simplifies the porting process. It can usually be
mechanically added (although not always). In &lt;a href="#sec:results:rq3"&gt;Section VI-E&lt;/a&gt;, we estimate the
total savings of human labor from this simplification. With the automated
construction of shadow projects and the ability to mechanically drive changes
to Blueprints, we were able to fully automate portions of the porting process.&lt;/p&gt;
&lt;h2 id="complexity-implementation"&gt;C. Complexity of Implementation&lt;/h2&gt;

&lt;p&gt;In &lt;a href="#sec:results:rq3"&gt;Section VI-E&lt;/a&gt;, we analyze the Return on Investment of this project and
find that it was positive. However, the actual implementation of variants was
complicated for many reasons that are outside of the scope of this paper to
fully describe. For instance, TAP manages a set of projects and their targets
at the scale of Google's multi-billion line mono-repository. Those projects and
targets form a bipartite graph where a project contains multiple targets but a
target may be inside multiple projects. Adding a single variant doubles the
size of that graph. There are technical challenges involved with optimizing the
variant implementation for computing, storing, and serving this graph. Note, the
graph is dynamic as it changes at practically every submitted change.&lt;/p&gt;
&lt;p&gt;Other, more prosaic challenges emerged, such as finding the correct policy for
detecting incompatible projects, redesigning data storage layers for project
status, and renegotiating the contract between Rapid and TAP, among many other
challenges. We regret that we do not provide the full saga of the development.&lt;/p&gt;
&lt;h1 id="sec:target-comprehensive"&gt;IV. Target Comprehensive Testing&lt;/h1&gt;

&lt;p&gt;One benefit of variants we have not yet discussed is their structured nature.
When developers manually create new CI and CD projects as shown in Listing 1,
there are no constraints on what they might change. We cannot enforce standard
naming conventions automatically, nor can we even ensure they create them in
the same Blueprint configuration file. Developers may add or subtract
additional flags in non-standard ways. They may add or remove sections of their
code from the patterns to be built and tested. Because of this, the central
services (TAP and Rapid) would need to make conservative choices when
qualifying releases.&lt;/p&gt;
&lt;p&gt;However, variants have none of the above problems. Their definitions (what
flags are added, what kind of targets are excluded, etc...) are centrally
defined and audited. This enables direct monitoring (as shown in &lt;a href="#sec:results:rq2"&gt;Section VI-C&lt;/a&gt;)
of behavior divergence between x86 and Arm. It also enables us to make changes
to how we schedule tests in TAP and Rapid.&lt;/p&gt;
&lt;p&gt;As discussed in &lt;a href="#sec:background"&gt;Section II&lt;/a&gt;, TAP has traditionally run all tests in all
configurations. We call this testing mode &lt;em&gt;Fully Comprehensive&lt;/em&gt; (FC). In order
to find breakages faster, we then also ran tests in a &lt;em&gt;Speculative&lt;/em&gt; mode [&lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;]. Now,
we introduce a third mode enabled by variants: &lt;em&gt;Target Comprehensive&lt;/em&gt; (TC)
testing. Under TC, we guarantee that targets are run &lt;em&gt;at least&lt;/em&gt; once in some
configuration (x86, arm, or other variant). Because of the automatically
generated nature of variants and our central monitoring, results in one
configuration are generally &lt;em&gt;substitutable&lt;/em&gt; for another configuration (see
&lt;a href="#sec:results:rq2"&gt;Section VI-C&lt;/a&gt;).&lt;/p&gt;
&lt;h2 id="integration-release"&gt;A. Integration with Release&lt;/h2&gt;

&lt;p&gt;A TAP project is eligible for Target Comprehensive testing when all release
projects that reference it are enabled for Arm (see Listing 2). Under TC, TAP
only guarantees to run a target on a single architecture (but it can choose to
run it on more). However, before a release goes to production (and potentially
executes on an architecture different than the one TAP tested on), we want to
qualify it in all configurations. To do so, we run the remainder of the tests
that TAP skipped during the release process. Figure 2 visualizes how this all
connect together.&lt;/p&gt;
&lt;p&gt;&lt;span id="fig:system-overview" label="fig:system-overview"&gt;
  &lt;a href="images/icst-2026/fig2.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 2&lt;/strong&gt;&lt;/em&gt;
  &lt;img alt="Figure 2" src="images/icst-2026/fig2.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In release, there are two types of projects: &lt;em&gt;Rapid Native&lt;/em&gt; (unmanaged) projects
and &lt;em&gt;Urfin&lt;/em&gt; (managed) projects (&lt;a href="#sec:background"&gt;Section II&lt;/a&gt;). By default, Urfin projects "Create
Candidates" every two hours and push production releases once per business day
(excluding Fridays). Because of the structured nature of Urfin, we know
centrally when an Urfin project pushes to production. This allows us to
&lt;em&gt;delay&lt;/em&gt; the finalization of testing to immediately before the production push.
We call this &lt;em&gt;Late Stage Testing&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In Rapid Native, we do not know when in the release process a developer may be
modifying production. Therefore, we need to continue to complete testing in the
traditional Create Candidate phase. Luckily, many Rapid Native projects tend to
be configured to Create Candidates once per day.&lt;/p&gt;
&lt;h2 id="cost-savings"&gt;B. Cost Savings&lt;/h2&gt;

&lt;p&gt;Target Comprehensive testing shifts the load &lt;em&gt;right&lt;/em&gt; in the Software Development
Life Cycle (closer to the user and further away from the developer). This is
expected to save machine cost by reducing the frequency at which tests are
executed on both architectures. We expect significant savings, since
production pushes usually only occur approximately once per day and TAP testing
cycles occur once per hour. In &lt;a href="#sec:results:rq1"&gt;Section VI-A&lt;/a&gt;, we empirically evaluate our
realized savings. While lower than the theoretical maximum for a variety of
reasons, the results are significant and financially meaningful to us.&lt;/p&gt;
&lt;h1 id="sec:evaluation"&gt;V. Empirical Evaluation&lt;/h1&gt;

&lt;h2 id="research-questions"&gt;A. Research Questions&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;RQ1&lt;/strong&gt;: How does the Target Comprehensive scheduling strategy, which
    executes a union of test targets once across architectures ($T_{\text{x86}}
    \cup T_{\text{Arm}}$), compare to a Fully Comprehensive baseline
    ($T_{\text{x86}} \times T_{\text{Arm}}$) in terms of compute resource
    consumption and project status latency?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RQ2&lt;/strong&gt;: Does the Target Comprehensive approach maintain release success
    rate compared to Fully Comprehensive testing? Specifically, what is the
    impact on breakage detection latency and rate of late failure detections?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RQ3&lt;/strong&gt;: How does an intent-based configuration abstraction,
    &lt;code&gt;arm_variant_mode&lt;/code&gt;, compare to manual Blueprint configuration in terms of
    upfront engineering cost (measured as saved migration effort)?&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="statistical-testing"&gt;B. Note on Statistical Testing&lt;/h2&gt;

&lt;p&gt;Throughout our analysis below, our primary method for assessing validity and
effect size is Bootstrap resampling (with 10,000 samples) to construct
confidence intervals at the 95% confidence level using the percentile method [&lt;a href="#ref-Hesterberg2012"&gt;19&lt;/a&gt;].
While our sample sizes are large enough to generally "ignore" normality
violations, the violations are at times quite severe in our datasets. To build
confidence in the conclusions we usually apply a secondary parametric analysis
(such as an appropriate t-test or regression model). The results of the
parametric tests confirmed the non-parametric Bootstrap method. Finally, the
Bootstrap method returns larger confidence intervals than the corresponding
parametric method employed. We present these more conservative intervals in the
text of the paper.&lt;/p&gt;
&lt;h2 id="analyzing-machine-costs"&gt;C. Analyzing the Effect on Machine Costs&lt;/h2&gt;

&lt;p&gt;The motivating reason for Target Comprehensive testing cycles was to save
machine costs as double testing was deemed unsustainable. So, did the cost
savings materialize? Forge provides highly-detailed &lt;em&gt;per action&lt;/em&gt; logs of
executor cost and time. An action is a single build action that Bazel invokes.
For instance, a compiler or linker command. Test actions (when a test is
executed) are trivially differentiable from the build actions.&lt;/p&gt;
&lt;p&gt;We analyzed Forge usage data from TAP Postsubmit (CI runs occurring after code
submission) for 44,243 projects that had Arm testing enabled. We collected
data over several weeks, joining Bazel targets with Forge actions to estimate
the amortized build cost, and collecting the direct execution cost for each
test action. For each testing cycle run by TAP Postsubmit, we summed the
amortized build costs and test costs for all targets in the project to create a
total cost per cycle. Target costs were normalized when shared by multiple
projects in the same testing cycle.&lt;/p&gt;
&lt;p&gt;We performed a paired comparison (by project) of the Target Comprehensive (TC)
and Fully Comprehensive (FC) costs. We evaluated performance using two
distinct metrics: &lt;em&gt;per-project&lt;/em&gt; savings and &lt;em&gt;global system&lt;/em&gt; savings. In both
cases, savings are defined as $1 - \text{TC} / \text{FC}$.&lt;/p&gt;
&lt;p&gt;To estimate the expected "per project" savings, we used the Geometric Mean (GM)
of the ratio for all projects: $1 - \text{GM}(\text{TC} / \text{FC})$. To
estimate the expected system (or total) savings, we estimated the ratio of the
sum of costs across all projects in a scheduling cycle: $1 - \sum \text{TC} /
\sum \text{FC}$.&lt;/p&gt;
&lt;p&gt;For both estimates, we used the non-parametric method Bootstrap re-sampling [&lt;a href="#ref-Hesterberg2012"&gt;19&lt;/a&gt;],
which does not require an assumption about normality of the data. As can be seen
in Figure 3, the data has heavy tails and multiple peaks violating this
assumption. Using Bootstrap, we resampled (for each estimate) 10,000 times and
computed the expected savings (the median) and 95% confidence interval using the
2.5th - 97.5th percentiles. Finally, we cross checked the per-project estimate
using a paired t-test.&lt;/p&gt;
&lt;h2 id="analyzing-project-status-latency"&gt;D. Analyzing the Effects on Project Status Latencies&lt;/h2&gt;

&lt;p&gt;A project status includes the results of all targets and indicates if the
project is passing, failing, broken, etc. &lt;em&gt;Project status latency&lt;/em&gt; is the time
elapsed between successive calculations of project statuses at each cycle. To
account for distribution variability, we utilize a Poisson Bootstrap method with
10,000 resamplings to analyze latency across 2.75 million FC statuses (before
launch) and 2.94 million TC statuses (after launch). The cohort consists of
31,996 TAP projects that were Arm-enabled just prior to launch of TC.&lt;/p&gt;
&lt;h2 id="analyzing-breakage-detection"&gt;E. Analyzing Breakage Detection Latency&lt;/h2&gt;

&lt;p&gt;Breakage detection latency is defined as the amount of time between when a
developer submits a bug that breaks a test and the breakage being detected
through a CI execution. We use Bootstrap analysis to compute confidence
intervals to compare this breakage detection latency before and after the
launch of Target Comprehensive testing. Further parametric analysis was
completed that agrees with the non-parametric analysis, which we omit for
brevity.&lt;/p&gt;
&lt;h2 id="analyzing-release-failure"&gt;F. Analyzing the Effects on Release Failure Rate&lt;/h2&gt;

&lt;p&gt;Our second question, RQ2, asks whether the reduction in coverage from Target
Comprehensive testing caused additional failures in release. As a reminder, for
binaries that will actually be released, we run the remaining tests that were
not run during Target Comprehensive. Thus, every test is run on both platforms
if it runs in production. Running on both platforms happens much less
frequently and enables the savings shown in RQ1.&lt;/p&gt;
&lt;p&gt;We gathered data on 91,815 Release Projects, including both projects with Arm
enabled and not enabled. Initial normality checks revealed the failure data to
be extremely heavy-tailed and zero-inflated: the vast majority of projects
never fail, while a small minority fail constantly. We filtered out
approximately 130 projects that failed 100% of the time in both periods, as
manual inspection confirmed these were abandoned and would otherwise skew
volume-weighted metrics.&lt;/p&gt;
&lt;p&gt;We analyzed the two project types: "Rapid Native" (flexible workflows) and
"Urfin" (managed/structured workflows). For Urfin, we distinguish between the
standard "Candidate Creation" phase and the additional "Late-stage" testing
performed immediately before production push.&lt;/p&gt;
&lt;p&gt;We compare across these 3 groups the change in test failure rates. We look at
the comparison in two ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;em&gt;Paired Analysis (System Burden):&lt;/em&gt; We calculated the mean arithmetic
    difference in failure rate for each project before and after Target
    Comprehensive was enabled. This measures the expected change in the total
    failure rate on the system.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Geometric Analysis (Typical Experience):&lt;/em&gt; We analyzed the change in the
    geometric mean of project failure rates. This metric controls for volume
    bias (projects with high execution counts) and outliers, answering the
    question: "Did the failure rate of a typical project change?"&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Given the non-normal shape of the data, we utilized Bootstrap re-sampling (10k
iterations) to estimate 95% confidence intervals as our primary method. We
cross-checked the paired analysis using a Wilcoxon Signed-Rank Test to detect
non-random drifts in rank order, and cross-checked the geometric analysis
using a Robust Linear Model (RLM) to provide parametric validation robust to
outliers.&lt;/p&gt;
&lt;h2 id="estimating-engineering-savings"&gt;G. Estimating Engineering Cost Savings&lt;/h2&gt;

&lt;p&gt;We want to compare the engineering costs of migrating projects using the new
variants approach versus a more complex legacy method. We measured effort using
the following normalized units that represent the time that a single software
engineer spends working.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Definition 1 (SWEy).&lt;/strong&gt; &lt;em&gt;A SWE Year is a normalized unit that represents a
software engineer working for a year.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;SWEy are treated as interchangeable regardless of which person or how many
persons work on the migration. Note that coordination costs between multiple
people working on a migration are also neglected. Due to confidentiality
constraints, we are unable to report our internal SWEy numbers that we have
computed. Instead, &lt;em&gt;total effort saved&lt;/em&gt; will be reported, which provides a
percentage of working time avoided due to the improved configuration mechanism.&lt;/p&gt;
&lt;p&gt;To estimate the total effort, we began by estimating the average or expected
effort to migrate a single configuration file (i.e., Blueprint). This was
estimated using data from the team conducting central high-priority migrations.
This team spent approximately 80% of their total time on conducting manual
migrations before variants were introduced. Based on their migration output
over the course of an entire quarter, we derived a specific (but confidential)
estimate of the average time spent per Blueprint.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Definition 2 (BPe).&lt;/strong&gt; &lt;em&gt;BPe = "Blueprint Effort", or the time spent to migrate
a single Blueprint without variants. (Actual number is confidential).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Note, the above estimation was computed from expert engineers who were tasked
only with conducting migrations. This central team only migrated a small
fraction of the total projects. Engineers who don't work on migrations every
day are less expert in conducting the migration and they take longer. We
estimate that the migration would take twice as long for a non-expert engineer.
We use the range [BPe, 2 ⋅ BPe] to estimate a normal distribution of effort.&lt;/p&gt;
&lt;p&gt;In the same way, we can estimate Ve:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Definition 3.&lt;/strong&gt; &lt;em&gt;Ve = "Variant Effort" of the time spent to migrate a single
Blueprint using variants. (Actual number is confidential).&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Using these estimates, we can estimate total migration costs:&lt;/p&gt;
&lt;p&gt;$$\text{baseline-total}&lt;em _text_SWEy_="\text{(SWEy)"&gt;{\text{(SWEy)}} = \text{project count} \times 2 \times \text{BPe}&lt;/em&gt;$$}&lt;/p&gt;
&lt;p&gt;$$\text{variant-total}&lt;em _text_SWEy_="\text{(SWEy)"&gt;{\text{(SWEy)}} = \text{project count} \times \text{Ve}&lt;/em&gt;$$}&lt;/p&gt;
&lt;p&gt;To compute return on investment, we account for realized machine savings (see
&lt;a href="#sec:results:rq1"&gt;Section VI-A&lt;/a&gt;) and the development cost (number of SWEy spent on development).&lt;/p&gt;
&lt;p&gt;$$\text{ROI} = 1 - \frac{\text{variant-total} + \text{development} - \text{machine savings}}{\text{baseline total}}$$&lt;/p&gt;
&lt;p&gt;To estimate the return on investment when many of the parameters for the
computation are estimates themselves, we used a Monte Carlo simulation
parameterized by our ranges of values for quantities such as BPe, VPe, and the
machine cost savings. We assumed these values could be drawn from a roughly
normal distribution and took 100k samples of each for the MC simulation.&lt;/p&gt;
&lt;h2 id="threats-validity"&gt;H. Threats to Validity&lt;/h2&gt;

&lt;p&gt;Developer behavior and resource usage predictably varies throughout the year,
with large observed dips during holiday periods. Our comparison accounts for
this effect by excluding holidays. Additionally, for our most business critical
question (machine cost savings), we were fortunate to be able to conduct a
paired analysis by executing a combination of both cycle types after launch.
This provided us a robust data set of FC cycles before and after launch and TC
cycles after launch, which helps us account for any time based factor. Second,
our return on investment computation relies on estimation of effort by experts
and may not be perfectly reflective of actual effort. While we attempt to
account for this effect, we acknowledge the limitation of both our attempt, and
the Monte Carlo simulation used to provide the confidence interval. Further,
factors outside the scope of this paper, such as any differences in actual
machine cost or other unaccounted costs (either human or machine) could reduce
(or strengthen) the actual return.&lt;/p&gt;
&lt;p&gt;Finally, this is a case study of one organization conducting a single project
to scale their environment to another machine platform. Our results may not
generalize. We observe in our own data that the existence of platform specific
test behavior is highly dependent on the context of the specific project. We
expect other organizations may have a different mixture of code, and if most
code is sensitive to the runtime platform then the savings realized here will
be unrealizable for that organization.&lt;/p&gt;
&lt;h1 id="sec:results"&gt;VI. Results&lt;/h1&gt;

&lt;h2 id="sec:results:rq1"&gt;A. RQ1: Compute Resource Consumption&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:forge-cost" label="fig:forge-cost"&gt;
  &lt;a href="images/icst-2026/fig3.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 3&lt;/strong&gt;&lt;/em&gt;
  &lt;img alt="Figure 3" src="images/icst-2026/fig3.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure 3 shows a breakdown of machine costs for running projects under Target
Comprehensive and Fully Comprehensive testing cycles. As seen in the figure,
there is a high variance in project costs. The plots indicate that x86 Test
costs were generally lower under Target Comprehensive (as expected), while Arm
Test costs were generally higher (as expected). Table 1 summarizes the results
of our statistical analysis. We observed total savings of ~25%; statistical
analysis confirmed the trends evident in the plots, with the most savings
derived from avoiding x86 Testing. However, we also saw a substantial 14.8%
decrease in build costs attributable to a decrease in double compilation under
TC testing.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 1: Build and test cost savings of Target Comprehensive scheduling.&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Category&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Typical Project Savings (Geometric Mean)&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Global System Savings (Expected Total Savings)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Total&lt;/td&gt;
&lt;td style="text-align: left;"&gt;20.6% (20.3% - 21.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;24.9% (19.6% - 29.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;x86 Build&lt;/td&gt;
&lt;td style="text-align: left;"&gt;16.0% (15.6% - 16.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;14.9% (7.7% - 21.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;x86 Test&lt;/td&gt;
&lt;td style="text-align: left;"&gt;56.9% (56.4% - 57.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;66.7% (58.0% - 72.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Arm Test&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-25.5% (-26.8% - -24.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-18.4% (-28.7% - -9.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;We validated the per-project savings using a paired t-test on the per-project
mean of log-transformed costs. The result was highly significant ($t(44242) =
-101.3, p &amp;lt; 0.001$), and the derived confidence interval aligned closely with
the non-parametric Bootstrap estimates reported in Table 1. This convergence
reinforces the statistical validity of our findings. Diagnostic checks (Q-Q
plots) confirmed that the data is left-skewed (skewness: -1.46) and
leptokurtic (kurtosis: 19.8), exhibiting heavy tails. Despite these
deviations from normality, the large sample size supports the use of the
parametric t-test, while the Bootstrap analysis provides a robust,
assumption-free confirmation.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Target Comprehensive testing has an expected system wide savings of ~25%
versus Fully Comprehensive.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="sec:results:rq1-2"&gt;B. RQ1: Comparison of Project Status Latencies&lt;/h2&gt;

&lt;p&gt;Table 2 presents the project status latencies and 95% CI for FC and TC, along
with the percentage difference between the two periods. Significant
architectural changes and varying project definitions occurred between the FC
and TC periods. However, our analysis deliberately focuses on the &lt;strong&gt;holistic,
end-to-end latency&lt;/strong&gt; to capture the net impact on system performance,
regardless of these confounding factors.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 2: Project Status Latency in minutes (p50 and p90).&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;&lt;/th&gt;
&lt;th style="text-align: left;"&gt;p50 [95% CI]&lt;/th&gt;
&lt;th style="text-align: left;"&gt;p90 [95% CI]&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;FC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;88.50 [88.43 - 88.58] min&lt;/td&gt;
&lt;td style="text-align: left;"&gt;200.78 [200.43 - 201.12] min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;TC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;75.08 [75.03 - 75.13] min&lt;/td&gt;
&lt;td style="text-align: left;"&gt;176.58 [176.25 - 176.90] min&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;% Diff&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-15.16%&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-12.05%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;Target Comprehensive testing has a median latency savings of 15% and p90
savings of 12%.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="sec:results:rq2"&gt;C. RQ2: Breakage Detection Latency&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:breakage-latency" label="fig:breakage-latency"&gt;
  &lt;a href="images/icst-2026/fig4.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 4&lt;/strong&gt;&lt;/em&gt;
  &lt;img alt="Figure 4" src="images/icst-2026/fig4.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure 4 summarizes the results of our analysis. We compared the latency of
detecting newly-introduced breakages (from submission of the culprit change to
the first failure being detected) before and after launch of Target
Comprehensive. While the median breakage detection latency was unchanged, the
mean and 90th percentile showed significant changes. To understand why, we
plotted a breakdown of the number of breakages occurring in ranges of
latencies (ex. 17 breakages in 90 minutes - 105 minutes) before and after. We
then used Bootstrap re-sampling to estimate the change in the number of
breakages likely to occur in each bucket. As visualized in Figure 4, the
results indicate that we can expect approximately 4 additional breakages per
day that take more than 12 hours to detect. This is a regression and a cost of
Target Comprehensive testing as implemented today. We look forward to further
optimizations to address this in the future.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We expect 4 additional breakages per day that take more than 12 hours to
detect.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="late-stage-defect"&gt;D. RQ2: Late-Stage Defect Detection Rates&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:failure-compare" label="fig:failure-compare"&gt;
  &lt;a href="images/icst-2026/fig5.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 5&lt;/strong&gt;&lt;/em&gt;
  &lt;img alt="Figure 5" src="images/icst-2026/fig5.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure 5 illustrates the distribution of release-time testing failures for
projects with Arm enabled versus disabled, distinguishing rates before and
after the rollout of Target Comprehensive testing. In general, the Urfin
failure rate is approximately 1/10th that of Rapid Native. Notably,
Arm-disabled Rapid Native projects (which were unaffected by the rollout) also
saw a regression during this period, suggesting a potential global regression
in failure rates unrelated to the launch.&lt;/p&gt;
&lt;p&gt;Tables 3 and 4 summarize the results of our statistical analysis. We highlight
two key findings. First, the paired bootstrap analysis for Rapid Native
indicates a worst-case regression of 0.27%, but the confidence interval also
spans zero, allowing for a possible 0.1% improvement. However, the Wilcoxon
Signed-Rank Test reports a statistically significant difference in rank order
($p = 0.003$). Given this conflict between magnitude (CI includes 0) and rank
drift (Significant P-value), we classify this as a &lt;em&gt;potential regression&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Second, both analytical methods confirm an unambiguous improvement in the
failure rate for Urfin Late-Stage testing. Prior to this rollout, Urfin
projects executed Arm tests exclusively in the Late-stage phase (a MVP
optimization while we waited for Target Comprehensive implementation to
complete). The introduction of Target Comprehensive testing effectively
&lt;em&gt;shifted left&lt;/em&gt; this coverage. TC can identify Arm and x86 failures earlier in
the TAP Postsubmit CI phase. This operational change explains the significant
decrease in Late-Stage failures ($p &amp;lt; 0.001$). This result justifies the
strategy of probabilistic early testing (TC) over exclusive late-stage
verification (MVP optimization).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 3: Paired Analysis of Change in Test Failure Rate (Arithmetic Mean).&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;&lt;/th&gt;
&lt;th style="text-align: left;"&gt;&amp;delta; Failure Rate&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Wilcoxon Pval&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Rapid Native&lt;/td&gt;
&lt;td style="text-align: left;"&gt;0.09% (-0.10, 0.27)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p=0.003&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Urfin - CC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;0.01% (-0.00, 0.03)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p&amp;lt;0.001&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Urfin - LS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-0.08% (-0.11, -0.06)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p&amp;lt;0.001&lt;/td&gt;
&lt;td style="text-align: left;"&gt;+++&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Verdicts: (+++) Improvement, (-) Potential Regression (CI spans 0).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table 4: Analysis of Change in Typical Test Failure Rate (Geometric Mean).&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;&lt;/th&gt;
&lt;th style="text-align: left;"&gt;&amp;delta; Failure Rate&lt;/th&gt;
&lt;th style="text-align: left;"&gt;RLM Pval&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Rapid Native&lt;/td&gt;
&lt;td style="text-align: left;"&gt;0.008% (0.004, 0.012)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p&amp;lt;0.001&lt;/td&gt;
&lt;td style="text-align: left;"&gt;--&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Urfin - CC&lt;/td&gt;
&lt;td style="text-align: left;"&gt;0.001% (0.000, 0.003)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p=0.159&lt;/td&gt;
&lt;td style="text-align: left;"&gt;~-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Urfin - LS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;-0.003% (-0.003, -0.002)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;p&amp;lt;0.001&lt;/td&gt;
&lt;td style="text-align: left;"&gt;++&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Verdicts: (++) Small Improvement, (--) Small Regression, (~-) Conflict between
Robust Linear Model (RLM) and Bootstrap, Prefer Bootstrap Prediction of Small
Regression.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Rapid Native projects show a potential 0.1% regression in failure rates.
Urfin projects show a clear 0.08% improvement (decrease) in late-stage
failures.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="sec:results:rq3"&gt;E. RQ3: Engineering Savings&lt;/h2&gt;

&lt;p&gt;As shown in Listings 1 and 2, the amount of code that must be added to enable a
project to take advantage of Arm is much less with variants. Typically,
projects need to change only a single line. We estimate that for the typical
Blueprint, variants require only 1/10th of the lines of code to maintain
compared to the legacy system. Not all Blueprints needed humans to migrate
them.&lt;/p&gt;
&lt;p&gt;Many Blueprints could be handled by tooling (either traditional tooling or
LLMs); however, there was a large number of Blueprints that did need human
effort. We restrict our ROI computation below to those requiring human effort.&lt;/p&gt;
&lt;p&gt;The new configuration syntax significantly reduces the effort to change a
complicated Blueprint that cannot be automatically changed. We quantified this
as percent change from legacy configuration to the modern configuration. With
the modern syntax, 55% fewer Blueprints needed to be changed by hand.&lt;/p&gt;
&lt;p&gt;Based on the Monte Carlo simulation, we believe our return on investment is
approximately 40% and between (10%, 56%) when all these different costs are
accounted for. We also estimated the savings in just migration cost. The MC
simulation estimates a migration savings of 95%, with an interval of (91%,
98%). As more projects adopt Arm over the coming year, our realized return on
investment for this capability will continue to grow, both in terms of saved
migration costs and increased savings of machine costs as more projects adopt
Target Comprehensive testing.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Our estimated ROI for this project is 40%.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id="related-work"&gt;VII. Related Work&lt;/h1&gt;

&lt;p&gt;In this paper, we presented an empirical case study examining the cost and
benefit of the Target Comprehensive (TC) testing strategy. TC runs each test on
either Arm or x86, but not both, for high frequency CI executions. This can be
viewed as a trivial case of Combinatorial Interaction Testing (CIT) [&lt;a href="#ref-Kuhn2013"&gt;20&lt;/a&gt;, &lt;a href="#ref-Kuhn2015"&gt;21&lt;/a&gt;] where we
only have 1 parameter. CIT has long been a standard tool for testing the t-way
interactions between various options in software testing. The most direct
analogy for this paper comes from the world of mobile software testing. With
the proliferation of devices, operating system variants, and manufacturer
customizations, mobile application developers have long had to test their
software across many devices. This has led to the proliferation of commercial
services to facilitate such testing (ex. Firebase Test Lab, AWS Device Farm,
Sauce Labs, etc...).&lt;/p&gt;
&lt;p&gt;Vilkomir explicitly studied the number of (random) devices one should test on
to identify all bugs [&lt;a href="#ref-Vilkomir2015"&gt;22&lt;/a&gt;, &lt;a href="#ref-Vilkomir2018"&gt;23&lt;/a&gt;]. They found that 13 devices achieved 100% coverage in
their study and 5 devices provided 80%+ confidence that all bugs had been
identified. They also examined if there were smarter ways to select the devices
such that fewer devices would be required to achieve the same degree of
confidence. In 2018, Kowalczyk &lt;em&gt;et al.&lt;/em&gt; [&lt;a href="#ref-Kowalczyk2018"&gt;24&lt;/a&gt;] also studied interactions between
different properties of devices and test failures. Kowalczyk also found that
the applications studied showed a variance in both failure rate and program
coverage that depended on the configuration.&lt;/p&gt;
&lt;p&gt;As reported by Lin &lt;em&gt;et al.&lt;/em&gt; in 2023 [&lt;a href="#ref-Lin2023"&gt;25&lt;/a&gt;], the difficulties in managing the
extensive (and expensive) on device testing strategy led ByteDance to create a
"virtual device farm" [&lt;a href="#ref-Lin2023"&gt;25&lt;/a&gt;]. Here, we find a direct analogy to Target Comprehensive
testing. The Virtual Device Farm mimicked the real devices with emulators,
though the fidelity was imperfect. To accommodate this, they would run the
majority of their testing effort on the virtual farm. However, final
validation tests ran on the physical farm: "Before the app's public releases,
we conduct testing on physical devices to uncover the remaining bugs, which are
mostly related to vendor-specific system services or drivers (§5.2). Since our
continuous testing has captured most app-level bugs (which account for 93% of
all bugs), tests on physical devices are much less frequently interrupted by
test failures." [&lt;a href="#ref-Lin2023"&gt;25&lt;/a&gt;].&lt;/p&gt;
&lt;p&gt;In addition to the work in mobile testing, there is a large body of work
assessing the feasibility of porting x86 code bases to Arm [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;, &lt;a href="#ref-Beck2023"&gt;26&lt;/a&gt;]. We do not attempt
to assess Google's overall migration effort here (see Christopher &lt;em&gt;et al.&lt;/em&gt;
paper [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;]), but note that there are significant architectural differences between
x86 and Arm that lead to correctness violations. These violations require
precise changes to rectify, as they often involve synchronization between
threads. We note that before a program is (initially) eligible to run on the
Arm architecture it goes through additional qualification beyond its test suite [&lt;a href="#ref-Christopher2025"&gt;1&lt;/a&gt;].
One example of research on automatic migration is Beck &lt;em&gt;et al.&lt;/em&gt;'s work [&lt;a href="#ref-Beck2023"&gt;26&lt;/a&gt;]. They
use static analysis to automatically translate synchronization patterns to safe
and performant Arm equivalents during compilation.&lt;/p&gt;
&lt;p&gt;Finally, our empirical assessment on changes to Breakage Detection Latency
relied on our past work on TAP [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;, &lt;a href="#ref-Henderson2024"&gt;5&lt;/a&gt;, &lt;a href="#ref-Kondareddy2025"&gt;7&lt;/a&gt;]. In 2023, we introduced a highly accurate
culprit finder, and more importantly, a methodology for automatically assessing
its accuracy [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;]. Culprit finding simply identifies which changes introduced a
test breakage into the repository. This is made challenging by flaky and
non-hermetic tests. We conduct extensive reruns (as documented in [&lt;a href="#ref-Henderson2023"&gt;4&lt;/a&gt;]) to automatically verify
the output of the culprit finder. In Kondareddy &lt;em&gt;et al.&lt;/em&gt;'s 2025 paper, we hand
re-verified a sample of the output and determined our verification strategy is
99.2 &amp;plusmn; 3.3% accurate. This verified dataset provides our definitive source of
truth (&amp;plusmn; 3%) on breakages and enables us to accurately report Breakage
Detection Latency while accounting for flakiness to the best of our ability.&lt;/p&gt;
&lt;h1 id="sec:conclusion"&gt;VIII. Conclusion&lt;/h1&gt;

&lt;p&gt;Automated configuration, &lt;em&gt;variants&lt;/em&gt;, and &lt;em&gt;Target Comprehensive&lt;/em&gt; (TC) testing
cycles were introduced to enable large scale adoption of the Arm architecture
at Google. A naive approach of double testing would have been unsustainable,
doubling compute costs and potentially increasing friction from additional
flaky failures. Further, requiring all projects to modify their individual
configuration files was infeasible.&lt;/p&gt;
&lt;p&gt;Our solution enabled the adoption of Arm throughout the organization by
controlling machine costs and minimizing human toil. We saved 90%+ human
migration effort. We saved ~25% of the machine costs. Even though we don't
execute all the tests all the time, the delays in breakage detection were
marginal (4 per day) over the total number of breakages across the repository.
Finally, our final safety net (Late Stage Testing) only detects a failure in
fewer than 0.1% of production promotion attempts, a negligible amount and
dwarfed by other reasons a production promotion may be aborted. Collectively,
this work demonstrates the feasibility of large scale adoption of heterogeneous
computing platforms without doubling the cost of testing.&lt;/p&gt;
&lt;h4&gt;Contributions and Acknowledgments&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Primary Author:&lt;/em&gt; Tim A. D. Henderson, &lt;em&gt;Secondary Author:&lt;/em&gt; Sushmita Azad&lt;/p&gt;
&lt;p&gt;Additional authors, alphabetic:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Data Analysis for Empirical Evaluation:&lt;/em&gt; Chandrakanth Chittappa, Ali
    Esmaeeli, Laura Macaddino, Sam Manfreda, David Margolin, Dharma Naidu,
    Sabuj Pattanayek, Sachin Sable, Ruslan Sakevych&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Drafting and Editing:&lt;/em&gt; Dushyant Acharya, Adrian Berding, Kevin Crossnan,
    Wolff Dobson, Avi Kondareddy, Abhayendra Singh&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, we would also like to thank the following people for their
technical contributions towards the success of this effort. In alphabetic
order: Michael Adelemoni, David Alfonso, Sterling Augustine, Mark Balch, Leeann
Bent, Paul Bethe, Lexi Bromfield, Eric Burnett, Saahithi Chillara, Brian Chiu,
Dan Cho, Eric Christopher, Eduardo Colaco, Nicolo Davis, Rumeet Dhindsa, Paul
Diebold, Bobby Dorward, Pat Doyle, Ákos Frohner, Charlie Fu, Russell
Gottfried, Mark Halberstadt, Minh Hoang, Jung Woo Hong, JaJan Hsu, Jin Huang,
Xin Huang, Kevin Jiang, Pranav Kant, Danial Klimkin, Gregory Kwok, Leon Lee,
Chris Lewis, Drew Lewis, Jordan Lin, Kevin Liston, Sean Luchen, David
Michaelson, Dominic Mitchell, Morgan Mitchell, Maksym Motornyy, Katherine
Nadell, Danny Nguyen, Denis Nikitin, John Penix, Evelyn Price, Daniel Rall,
Emma Rapati, Ashley Richter, Alberto Rojas, Daniel Romero Sanchez, Carly
Schaeffer, Aaron Schooley, Alexander Schrepfer, Will Schwarz, Markus Schwenk,
Manish Shah, Santanu Sinha, Peter Spragins, Arvind Sundararajan, Xenia Tay,
Greg Tener, Marjorie Thibodaux, Dima Tsumarau, Shanid Seerae Valappil, Sri
Raga Velagapudi, Andrew Vorwald, Shu-Chun Weng, Michael Wexler, DJ Whang, Jeff
Xia, Anthony Xiang, and Jun Xiang Yak.&lt;/p&gt;
&lt;h1 id="references"&gt;References&lt;/h1&gt;

&lt;ul&gt;
&lt;div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list"&gt;
  &lt;li&gt;
  &lt;div id="ref-Christopher2025" class="csl-entry" role="listitem"&gt;
    [1] E. Christopher, K. Crossan, W. Dobson, C. Kennelly, D. Lewis, K. Lin, M. Maas, P. Ranganathan, E. Rapati, and B. Yang, "Instruction Set Migration at Warehouse Scale," Oct. 2025. [Online]. Available: &lt;a href="http://arxiv.org/abs/2510.14928"&gt;http://arxiv.org/abs/2510.14928&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Memon2017" class="csl-entry" role="listitem"&gt;
    [2] A. Memon, Zebao Gao, Bao Nguyen, S. Dhanda, E. Nickell, R. Siemborski, and J. Micco, "Taming Google-scale continuous testing," in &lt;i&gt;2017 IEEE/ACM 39th International Conference on Software Engineering: Software Engineering in Practice Track (ICSE-SEIP)&lt;/i&gt;. Piscataway, NJ, USA: IEEE, May 2017, pp. 233-242.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Fowler2006" class="csl-entry" role="listitem"&gt;
    [3] M. Fowler, "Continuous Integration," 2006. [Online]. Available: &lt;a href="https://martinfowler.com/articles/continuousIntegration.html"&gt;https://martinfowler.com/articles/continuousIntegration.html&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Henderson2023" class="csl-entry" role="listitem"&gt;
    [4] T. A. D. Henderson, B. Dorward, Eric Nickell, C. Johnston, and Avi Kondareddy. "Flake Aware Culprit Finding," in &lt;i&gt;2023 IEEE Conference on Software Testing, Verification and Validation (ICST)&lt;/i&gt;. IEEE, Apr. 2023.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Henderson2024" class="csl-entry" role="listitem"&gt;
    [5] T. A. D. Henderson, Avi Kondareddy, Sushmita Azad, and Eric Nickell. "SafeRevert: When Can Breaking Changes be Automatically Reverted?" in &lt;i&gt;2024 IEEE Conference on Software Testing, Verification and Validation (ICST)&lt;/i&gt;. Toronto, ON, Canada: IEEE, May 2024, pp. 395-406.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Leong2019" class="csl-entry" role="listitem"&gt;
    [6] C. Leong, Abhayendra Singh, Mike Papadakis, Yves Le Traon, and J. Micco, "Assessing Transition-Based Test Selection Algorithms at Google," in &lt;i&gt;2019 IEEE/ACM 41st International Conference on Software Engineering: Software Engineering in Practice (ICSE-SEIP)&lt;/i&gt;. IEEE, May 2019, pp. 101-110.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Kondareddy2025" class="csl-entry" role="listitem"&gt;
    [7] Avi Kondareddy, Sushmita Azad, Abhayendra Singh, and T. A. D. Henderson, "Speculative Testing at Google with Transition Prediction," in &lt;i&gt;2025 IEEE Conference on Software Testing, Verification and Validation (ICST)&lt;/i&gt;. Napoli, Italy: IEEE, Mar. 2025, pp. 510-521.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Potvin2016" class="csl-entry" role="listitem"&gt;
    [8] R. Potvin and J. Levenberg, "Why google stores billions of lines of code in a single repository," &lt;i&gt;Communications of the ACM&lt;/i&gt;, vol. 59, no. 7, pp. 78-87, 2016.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Winters2020" class="csl-entry" role="listitem"&gt;
    [9] T. Winters, T. Manshreck, and H. Wright, &lt;i&gt;Software Engineering at Google: Lessons Learned from Programming over Time&lt;/i&gt;. Beijing: O'Reilly, 2020.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Wang2020" class="csl-entry" role="listitem"&gt;
    [10] K. Wang, G. Tener, V. Gullapalli, X. Huang, Ahmed Gad, and Daniel Rall. "Scalable build service system with smart scheduling service," in &lt;i&gt;Proceedings of the 29th ACM SIGSOFT International Symposium on Software Testing and Analysis&lt;/i&gt;. Virtual Event USA: ACM, Jul. 2020, pp. 452-462.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Wang2021" class="csl-entry" role="listitem"&gt;
    [11] K. Wang, Daniel Rall, Greg Tener, V. Gullapalli, X. Huang, and Ahmed Gad. "Smart Build Targets Batching Service at Google," in &lt;i&gt;2021 IEEE/ACM 43rd International Conference on Software Engineering: Software Engineering in Practice (ICSE-SEIP)&lt;/i&gt;. Madrid, ES: IEEE, May 2021, pp. 160-169.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Gupta2011" class="csl-entry" role="listitem"&gt;
    [12] P. Gupta, M. Ivey, and J. Penix, "Testing at the speed and scale of Google," 2011. [Online]. Available: &lt;a href="https://google-engtools.blogspot.com/2011/06/testing-at-speed-and-scale-of-google.html"&gt;https://google-engtools.blogspot.com/2011/06/testing-at-speed-and-scale-of-google.html&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Bland2012" class="csl-entry" role="listitem"&gt;
    [13] M. Bland, "The Chris/Jay Continuous Build," Jun. 2012. [Online]. Available: &lt;a href="https://mike-bland.com/2012/06/21/chris-jay-continuous-build.html"&gt;https://mike-bland.com/2012/06/21/chris-jay-continuous-build.html&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Micco2012" class="csl-entry" role="listitem"&gt;
    [14] J. Micco, "Tools for Continuous Integration at Google Scale," Google NYC, Jun. 2012. [Online]. Available: &lt;a href="https://youtu.be/KH2_sB1A6lA"&gt;https://youtu.be/KH2_sB1A6lA&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Micco2013" class="csl-entry" role="listitem"&gt;
    [15] J. Micco, "Continuous Integration at Google Scale," EclipseCon 2013, Mar. 2013. [Online]. Available: &lt;a href="https://web.archive.org/web/20140705215747/https://www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf"&gt;https://web.archive.org/web/20140705215747/https://www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Elbaum2014" class="csl-entry" role="listitem"&gt;
    [16] S. Elbaum, Gregg Rothermel, and J. Penix, "Techniques for improving regression testing in continuous integration development environments," in &lt;i&gt;Proceedings of the 22nd ACM SIGSOFT International Symposium on Foundations of Software Engineering - FSE 2014&lt;/i&gt;. New York, New York, USA: ACM Press, 2014, pp. 235-245.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Spragins2018" class="csl-entry" role="listitem"&gt;
    [17] P. Spragins, "Efficacy Presubmit," Sep. 2018. [Online]. Available: &lt;a href="https://testing.googleblog.com/2018/09/efficacy-presubmit.html"&gt;https://testing.googleblog.com/2018/09/efficacy-presubmit.html&lt;/a&gt;
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Hoang2024" class="csl-entry" role="listitem"&gt;
    [18] Minh Hoang and Adrian Berding, "Presubmit Rescue: Automatically Ignoring FlakyTest Executions," in &lt;i&gt;Proceedings of the 1st International Workshop on Flaky Tests&lt;/i&gt;. Lisbon Portugal: ACM, Apr. 2024, pp. 1-2.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Hesterberg2012" class="csl-entry" role="listitem"&gt;
    [19] T. Hesterberg, David S. Moore, S. Monaghan, A. Clipson, and R. Epstein, "Bootstrap Methods and Permutation Tests," in &lt;i&gt;Introduction to the Practice of Statistics&lt;/i&gt;, 7th ed. New York: W.H. Freeman, 2012.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Kuhn2013" class="csl-entry" role="listitem"&gt;
    [20] D. R. Kuhn, R. N. Kacker, and Y. Lei, &lt;i&gt;Introduction to Combinatorial Testing&lt;/i&gt;, ser. Chapman &amp; Hall / CRC Innovations in Software Engineering and Software Development. Boca Raton, FL: CRC Press, 2013.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Kuhn2015" class="csl-entry" role="listitem"&gt;
    [21] D. R. Kuhn, Rick Bryce, F. Duan, L. S. Ghandehari, Y. Lei, and R. N. Kacker, "Chapter one - combinatorial testing: Theory and practice," ser. Advances in Computers, A. Memon, Ed. Elsevier, 2015, vol. 99, pp. 1-66.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Vilkomir2015" class="csl-entry" role="listitem"&gt;
    [22] S. Vilkomir, K. Marszalkowski, C. Perry, and S. Mahendrakar, "Effectiveness of Multi-device Testing Mobile Applications," in &lt;i&gt;2015 2nd ACM International Conference on Mobile Software Engineering and Systems&lt;/i&gt;. Florence, Italy: IEEE, May 2015, pp. 44-47.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Vilkomir2018" class="csl-entry" role="listitem"&gt;
    [23] S. Vilkomir, "Multi-device coverage testing of mobile applications," &lt;i&gt;Software Quality Journal&lt;/i&gt;, vol. 26, no. 2, pp. 197-215, Jun. 2018.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Kowalczyk2018" class="csl-entry" role="listitem"&gt;
    [24] E. Kowalczyk, Myra B. Cohen, and Atif M. Memon, "Configurations in Android testing: They matter," in &lt;i&gt;Proceedings of the 1st International Workshop on Advances in Mobile App Analysis&lt;/i&gt;. Montpellier France: ACM, Sep. 2018, pp. 1-6.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Lin2023" class="csl-entry" role="listitem"&gt;
    [25] Jordan Lin, J. Qiu, H. Wang, Z. Li, L. Gong, D. Gao, Y. Liu, F. Qian, Z. Zhang, P. Yang, and T. Xu, "Virtual Device Farms for Mobile App Testing at Scale: A Pursuit for Fidelity, Efficiency, and Accessibility," in &lt;i&gt;Proceedings of the 29th Annual International Conference on Mobile Computing and Networking&lt;/i&gt;. Madrid Spain: ACM, Oct. 2023, pp. 1-17.
  &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;
  &lt;div id="ref-Beck2023" class="csl-entry" role="listitem"&gt;
    [26] Manuel Beck, K. Bhat, L. Stričević, G. Chen, D. Behrens, M. Fu, V. Vafeiadis, H. Chen, and H. Härtig, "AtoMig: Automatically Migrating Millions Lines of Code from TSO to WMM," in &lt;i&gt;Proceedings of the 28th ACM International Conference on Architectural Support for Programming Languages and Operating Systems, Volume 2&lt;/i&gt;. Vancouver BC Canada: ACM, Jan. 2023, pp. 61-73.
  &lt;/div&gt;
  &lt;/li&gt;
&lt;/div&gt;
&lt;/ul&gt;</content><category term="Paper"/></entry><entry><title>Speculative Testing at Google with Transition Prediction</title><link href="https://hackthology.com/speculative-testing-at-google-with-transition-prediction.html" rel="alternate"/><published>2025-04-02T00:00:00-04:00</published><updated>2025-04-02T00:00:00-04:00</updated><author><name>Avi Kondareddy, Sushmita Azad, Abhayendra Singh, and &lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;</name></author><id>tag:hackthology.com,2025-04-02:/speculative-testing-at-google-with-transition-prediction.html</id><summary type="html">&lt;p&gt;Avi Kondareddy, Sushmita Azad, Abhayendra Singh, and &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;.
&lt;em&gt;Speculative Testing at Google with Transition Prediction&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2025/icst-2025-industry/17/Speculative-Testing-at-Google-with-Transition-Prediction"&gt;ICST Industry Track 2025&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICST62969.2025.10988976"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2025.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/speculative-testing-at-google-with-transition-prediction.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2025.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Google's …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Avi Kondareddy, Sushmita Azad, Abhayendra Singh, and &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;.
&lt;em&gt;Speculative Testing at Google with Transition Prediction&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2025/icst-2025-industry/17/Speculative-Testing-at-Google-with-Transition-Prediction"&gt;ICST Industry Track 2025&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICST62969.2025.10988976"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2025.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/speculative-testing-at-google-with-transition-prediction.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2025.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Google's approach to testing includes both testing prior to code submission
(for fast validation) and after code submission (for comprehensive
validation). However, Google's ever growing testing demand has lead to
increased continuous integration cycle latency and machine costs. When the
post code submission continuous integration cycles get longer, it delays
detecting breakages in the main repository which increases developer friction
and lowers productivity. To mitigate this without increasing resource demand,
Google is implementing Postsubmit Speculative Cycles in their Test Automation
Platform (TAP). Speculative Cycles prioritize finding novel breakages faster.
In this paper we present our new test scheduling architecture and the machine
learning system (Transition Prediction) driving it. Both the ML system and the
end-to-end test scheduling system are empirically evaluated on 3-months of our
production data (120 billion test$\times$cycle pairs, 7.7 million breaking
targets, with $\sim$20 thousand unique breakages). Using Speculative Cycles we
observed a median (p50) reduction of approximately 65\% (from 107 to 37 
minutes) in the time taken to detect novel breaking targets.&lt;/p&gt;
&lt;h1 id="sec:introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Continuous integration (CI) coordinates the development activity of large numbers of
  developers &lt;span class="citation" data-cites="Fowler2006"&gt;(&lt;a href="#ref-Fowler2006" role=
  "doc-biblioref"&gt;Fowler 2006&lt;/a&gt;)&lt;/span&gt;. When two developers are working in the same portion of
  the code base, continuous integration ensures that conflicting changes combine into a
  conflict-free version before reaching the end user. In general, adopters of CI execute builds and
  tests to ensure that the final release artifact (server binary, mobile application, etc...)
  passes all relevant tests. These build and tests are executed frequently to reduce the amount of
  time conflicts are present in the code base. Continuous integration is both a system and a
  practice of automatically merging changes into a source of truth for an organization's source
  code and related artifacts.&lt;/p&gt;
&lt;p&gt;For small software repositories and organizations, the implementation of continuous
  integration is well supported by off-the-shelf software such as Github Actions, CircleCI,
  Jenkins, and numerous other tools. However, as the repository and organization scales up
  challenges emerge.&lt;/p&gt;
&lt;p&gt;As an organization adds projects and engineers, there are two distinct paths that emerge: the
  many-small-repository path and the single-mono-repository path. Both paths have distinct
  challenges and advantages. Neither path will enable organizations to use vanilla off-the-shelf
  solutions for their development environment. This paper is focused on a particular challenge
  faced in a mono-repository environment at Google, but similar problems arise in organizations
  with many small repositories that are strongly coupled together.&lt;/p&gt;
&lt;p&gt;Google, an early adopter of mono-repositories and continuous integration &lt;span class=
  "citation" data-cites="Potvin2016"&gt;(&lt;a href="#ref-Potvin2016" role="doc-biblioref"&gt;Potvin and
  Levenberg 2016&lt;/a&gt;)&lt;/span&gt;, faces an enormous ever expanding code base that is centrally tested
  by the Test Automation Platform (TAP) &lt;span class="citation" data-cites="Micco2012"&gt;(&lt;a href=
  "#ref-Micco2012" role="doc-biblioref"&gt;Micco 2012&lt;/a&gt;)&lt;/span&gt;. As the code base and company grows,
  so does the &lt;em&gt;demand&lt;/em&gt; for compute resources for continuous testing. Left unchecked, we have
  observed a double digit percentage organic demand growth rate year-over-year (compounding). Such
  a growth rate is untenable even for a large company like Google. To prevent this unchecked growth
  in resource demand, TAP has long had features that reduce demand by skipping some tests (before
  submission) and batching many versions together (after submission) to amortize the cost
  &lt;span class="citation" data-cites=
  "Gupta2011 Bland2012 Micco2012 Micco2013 Memon2017 Leong2019 Wang2020 Wang2021 Henderson2023 Henderson2024 Hoang2024"&gt;
  (&lt;a href="#ref-Gupta2011" role="doc-biblioref"&gt;Gupta, Ivey, and Penix 2011&lt;/a&gt;; &lt;a href=
  "#ref-Bland2012" role="doc-biblioref"&gt;Bland 2012&lt;/a&gt;; &lt;a href="#ref-Micco2012" role=
  "doc-biblioref"&gt;Micco 2012&lt;/a&gt;, &lt;a href="#ref-Micco2013" role="doc-biblioref"&gt;2013&lt;/a&gt;; &lt;a href=
  "#ref-Memon2017" role="doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;; &lt;a href="#ref-Leong2019" role=
  "doc-biblioref"&gt;Leong et al. 2019&lt;/a&gt;; &lt;a href="#ref-Wang2020" role="doc-biblioref"&gt;K. Wang et
  al. 2020&lt;/a&gt;, &lt;a href="#ref-Wang2021" role="doc-biblioref"&gt;2021&lt;/a&gt;; &lt;a href="#ref-Henderson2023"
  role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024" role=
  "doc-biblioref"&gt;2024&lt;/a&gt;; &lt;a href="#ref-Hoang2024" role="doc-biblioref"&gt;Hoang and Berding
  2024&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In this paper, we are primarily concerned with testing that occurs after the code has been
  submitted. We examine how to improve the developer experience by finding novel build/test
  breakages faster while continuing to control our resource footprint growth rate.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="the-google-development-environment"&gt;The Google Development Environment&lt;/h2&gt;
&lt;p&gt;Google's development environment uses a centralized repository &lt;span class="citation"
  data-cites="Potvin2016"&gt;(&lt;a href="#ref-Potvin2016" role="doc-biblioref"&gt;Potvin and Levenberg
  2016&lt;/a&gt;)&lt;/span&gt; where code changes are managed with Blaze/Bazel&lt;a href="#fn1" class=
  "footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; and automatically tested,
  primarily by TAP. Developers write code, build and test locally, then submit it for review via
  Critique &lt;span class="citation" data-cites="Sadowski2018"&gt;(&lt;a href="#ref-Sadowski2018" role=
  "doc-biblioref"&gt;Sadowski et al. 2018&lt;/a&gt;)&lt;/span&gt;, triggering Presubmit checks. After review and
  approval, changes undergo further checks before merging. Due to high submission rates, Presubmit
  testing is limited to avoid excessive resource consumption and delays.&lt;/p&gt;
&lt;h2 id="tap-postsubmit"&gt;TAP Postsubmit&lt;/h2&gt;
&lt;p&gt;When a developer's change gets submitted it may still have a bug that breaks an existing test
  or causes a compile breakage in another part of the repository. To find these bugs that have
  slipped through the pre-submission testing and validation process, TAP also has a
  "post-submission" mode (TAP Postsubmit).&lt;/p&gt;
&lt;p&gt;In Postsubmit, TAP periodically (subject to compute resource availability in the Build system)
  schedules &lt;em&gt;all&lt;/em&gt; tests that have been &lt;em&gt;affected&lt;/em&gt; (based on build dependencies) since
  the last run. We refer this execution cycle as &lt;em&gt;Comprehensive Testing Cycle&lt;/em&gt;. Previously,
  this cycle has also been referred as Milestones &lt;span class="citation" data-cites=
  "Memon2017"&gt;(&lt;a href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;)&lt;/span&gt;. There
  are two primary objectives for the Comprehensive Cycle:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;Uncover all test failures at the version comprehensive testing was conducted at.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Provide project health signals for downstream services to trigger more expensive testing
      and/or start production rollout by triggering release automation&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;p&gt;As of today's writing, it takes &lt;span class="math inline"&gt;∼&lt;/span&gt;1-2 hours for a test broken
  by a developer's change to start failing in TAP Postsubmit. Once the failure is detected
  automatic culprit finders &lt;span class="citation" data-cites="Henderson2023"&gt;(&lt;a href=
  "#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt; and rollback system
  &lt;span class="citation" data-cites="Henderson2024"&gt;(&lt;a href="#ref-Henderson2024" role=
  "doc-biblioref"&gt;Henderson et al. 2024&lt;/a&gt;)&lt;/span&gt; will spring into action to help keep the
  repository healthy and our developers productive. Automatically rolling back the change (after
  the first breakage was detected) might take as little as 30 minutes or as long as several hours
  depending on a number of factors. Thus, it could be 4 hours or more before our developer learns
  they have broken a test and either been notified or automatically had their change rolled
  back.&lt;/p&gt;
&lt;h2 id="cost-of-breakages"&gt;Cost of Breakages&lt;/h2&gt;
&lt;p&gt;The longer it takes to identify and fix a code breakage, the more challenging and expensive
  the remediation process becomes. This delay can lead to a loss of context for the original
  developer, potentially requiring teammates to resolve the issue. Additionally, a bad change can
  affect other developers, especially if it occurs in widely used parts of the code base. When
  interrupted by such a failure programmers need to distinguish between the change they are making
  and existing fault in the repository. Ultimately, prolonged breakages can disrupt release
  automation and even delay production releases.&lt;/p&gt;
&lt;h2 id="our-contributions-and-findings"&gt;Our Contributions and Findings&lt;/h2&gt;
&lt;p&gt;In this paper we are looking to increase developer productivity by reducing their friction
  with respect to broken code in the main code base. Specifically we are solving the following
  problem.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;How can CI minimize the time between the submission of a faulty change and its
  identification within a continuous integration (CI) system to accelerate the detection and
  mitigation of bugs?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To solve the problem, we propose a new scheduling mode to our CI system, Speculative Testing
  Cycles, that opportunistically runs a small subset of tests to uncover novel failures and reduce
  the mean time to detection (MTTD) for new failures. Speculative Cycle prioritizes finding novel
  breakages by identifying tests that are very likely to fail. The new scheduling mode is driven by
  a &lt;em&gt;Transition Prediction&lt;/em&gt; model that predicts when tests are likely to (newly) fail. It
  utilizes shallow machine-learning to run a smaller batch of tests predicted to be more likely to
  be broken at higher frequency in order to find breakages faster. We discuss both the design and
  constraints on the production Speculative Cycle system and the shallow machine-learning model
  (Transition Prediction) that powers this predictive test selection.&lt;/p&gt;
&lt;p&gt;While the production system is highly tied to Google's unique development environment and
  organizational constraints (i.e.: large monorepos with centralized CI infrastructure), our ML
  model presents a very coarse-grain approach to prediction for test selection using test and
  code-under-test metadata that has equivalents in most development environments and is
  language/framework agnostic.&lt;/p&gt;
&lt;p&gt;Our contributions in this paper are therefore:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;Speculative Cycles: A system for frequent / cost-aware batch testing.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Transition Prediction (TRANSPRED): Predicting target status transitions (Pass to Fail) for
      arbitrary build &amp;amp; test targets. With a budget of 25% of the total targets, Transition
      Prediction achieves a 85% recall rate in detecting breakages.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;A very large scale study (utilizing 3-months of production data: 120 billion
      test&lt;span class="math inline"&gt;×&lt;/span&gt;cycle pairs, 7.7 million breaking targets, and
      &lt;span class="math inline"&gt;∼&lt;/span&gt;20,000 unique breakages) on the efficacy of Speculative
      Testing using Transition Prediction evaluating its performance against randomized
      testing.&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;A comparative assessment of dataset and training configurations for Transition Prediction,
      determining that the selection of features and the length of the training window
      substantially influence the system's performance.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;h1 id="background"&gt;Background&lt;/h1&gt;
&lt;h2 id="developer-services"&gt;Developer Services&lt;/h2&gt;
&lt;h3 id="bazel"&gt;Bazel&lt;/h3&gt;
&lt;p&gt;Google uses Bazel as its build system monorepo wide. Bazel allows specifying build/test
  "targets" that depend on other targets. Each target is comprised of a set of "actions" to be
  executed. Therefore, the execution of a target corresponds to a Directed Acyclic Graph (DAG) of
  actions. Given Bazel makes dependency management declarative and all dependencies are built at
  the same version of the codebase, builds are ostensibly held to be hermetic - builds at the same
  version of the codebase should produce the same output for each action. This opens up the
  possibility for massive compute savings through caching of intermediate actions across multiple
  builds.&lt;/p&gt;
&lt;h3 id="forge"&gt;Forge&lt;/h3&gt;
&lt;p&gt;Build/Test actions at Google run under a centralized compute cluster called Forge which
  attempts to cache these intermediate actions to avoid recomputation at the same version of the
  codebase. For Postsubmit testing, we make use of this caching by batching builds/tests at single
  versions every hour or so.&lt;/p&gt;
&lt;h2 id="comprehensive-testing-cycles"&gt;Comprehensive Testing Cycles&lt;/h2&gt;
&lt;p&gt;In the standard case, TAP Postsubmit performs each Comprehensive Testing Cycle once the
  previous cycle's active consumption of resources drops below a threshold of their allocated build
  system resources. This cycle consists of picking a recent change(snapshot of the repository), at
  which we batch and run a "comprehensive" set of tests. Comprehensive cycles run all tests that
  are "affected" since the previous cycle. "Affected" is our term for dependence as implied by the
  build system's package graph, allowing us to perform a degree of static test selection at a
  coarse granularity.&lt;/p&gt;
&lt;h2 id="ancillary-systems-for-build-gardening"&gt;Ancillary Systems For Build Gardening&lt;/h2&gt;
&lt;p&gt;The development life cycle explained above relies on Postsubmit testing to make up for the
  lack of comprehensive testing prior to submission. This introduces the concept of &lt;em&gt;Postsubmit
  breakages&lt;/em&gt; which are caught sometime after submission. The process of detecting the breakage,
  identifying the cause of the breakage (culprit finding), and fixing the breakage (sometimes via a
  rollback) is called "Build Gardening" at Google.&lt;/p&gt;
&lt;h3 id="culprit-finding"&gt;Culprit Finding&lt;/h3&gt;
&lt;p&gt;We have previously outlined Google's culprit finding approach in &lt;span class="citation"
  data-cites="Henderson2023 Henderson2024"&gt;(&lt;a href="#ref-Henderson2023" role=
  "doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024" role=
  "doc-biblioref"&gt;2024&lt;/a&gt;)&lt;/span&gt;. To formulate the problem, we are given a test/build "target"
  and must determine at which change &lt;span class="math inline"&gt;&lt;em&gt;C&lt;/em&gt;&lt;/span&gt; over a range of
  sequential changes &lt;span class="math inline"&gt;[&lt;em&gt;A&lt;/em&gt;, &lt;em&gt;B&lt;/em&gt;]&lt;/span&gt; did the target start
  breaking. The change &lt;em&gt;C&lt;/em&gt; is referred as a &lt;em&gt;Culprit Change&lt;/em&gt; or simply
  &lt;em&gt;Culprit&lt;/em&gt;. Given the presence of build/test non-determinism ("flakes"), we want to find
  the change at which the test was "truly" failing but "truly" passing at the previous change. Our
  previous work explores how we do this in a time and run-efficient manner using a historical flake
  rate aware Bayesian model to sample runs.&lt;/p&gt;
&lt;h3 id="sec:verifier"&gt;Culprit Verifier&lt;/h3&gt;
&lt;p&gt;Unfortunately, persistent flakiness and non-determinism can still slip by the culprit finders.
  The pathological case is that of build system non-determinism. Google's build system Bazel
  assumes that builds are hermetic and should produce the same output at the same version. This
  assumption means that unlike tests, failed actions are cached by the build system so immediate
  reruns will continue to assert what could potentially be a flaky build failure. The culprit
  verifier does extensive reruns on a subset of culprit conclusions produced by the culprit
  finders. We sample from two different sampling frames: (1) a simple random sample of all
  conclusions produced and (2) the first conclusion produced for each uniquely blamed culprit. For
  details on the design of the verification system, see the Flake Aware Culprit Finding paper
  &lt;span class="citation" data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023" role=
  "doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt; and the SafeRevert paper &lt;span class="citation"
  data-cites="Henderson2024"&gt;(&lt;a href="#ref-Henderson2024" role="doc-biblioref"&gt;Henderson et al.
  2024&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Although the verifier is fallible, the dataset it produces is still the most accurate
  representation of true breakages at Google. We know it fails because we have seen specific
  examples of its failures. But, from a measurement perspective, bounding its accuracy is
  challenging because its failure rate is low enough that it exceeds our ability to accurately
  measure. We have recently conducted manual verification while launching a new version of our Auto
  Rollback system on all culprits rolled back during the "dogfood" phase (an opt-in beta). Out of
  250+ hand verified culprits: 5 were incorrect culprits from the culprit finder, 2 incorrect
  culprits were incorrectly verified correct by the verifier. This gives us an estimated culprit
  finding accuracy of 98% (matching verifier produced accuracy dashboard) and a verifier accuracy
  of 99.2%. Given the low sample size the confidence interval on that measurement is &lt;span class=
  "math inline"&gt;99.2 ± 3.3%&lt;/span&gt; which is too wide. To get sufficient power to accurately
  estimate the verifier accuracy, we would need to hand verify at least 5000 culprits.&lt;/p&gt;
&lt;p&gt;Thus, while we are confident in the overall accuracy measurements provided by the verifier, we
  acknowledge that "ground truth" is difficult to obtain. We utilize the dataset produced by the
  verifier to label the culprits to train our prediction model (detailed below). This approach
  vastly reduces the impact of flakiness on our model training data.&lt;/p&gt;
&lt;h3 id="sec:autorollback"&gt;Autorollback&lt;/h3&gt;
&lt;p&gt;At Google, there is a developer guideline to prefer rollbacks to fix forwards. Given this
  context, it is appropriate to automatically roll back a change if someone is confident that the
  change broke the build. Unfortunately, given the accuracy issue of the culprit finder described
  above, we can't immediately rollback upon a culprit finding completion for one target. In the
  SafeRevert paper &lt;span class="citation" data-cites="Henderson2024"&gt;(&lt;a href="#ref-Henderson2024"
  role="doc-biblioref"&gt;Henderson et al. 2024&lt;/a&gt;)&lt;/span&gt;, we discussed how we attempt to determine
  the amount of evidence needed to proceed with a rollback. In practice, we currently restrict
  rollbacks to changes that break at least 10 targets.&lt;/p&gt;
&lt;h2 id="the-evolution-of-tap"&gt;The Evolution of TAP&lt;/h2&gt;
&lt;p&gt;Prior to development of TAP, Google had a more traditional continuous integration system.
  Primarily, the decision to run continuous integration was left up to individual teams and the
  system that existed was federated: teams brought their own capacity (machines, possibly under
  their desks) and had to configure and run the CI system(s). TAP, upon launch in 2009, was a
  massive improvement from setup and continuous maintenance perspective alone. Unlike the previous
  systems, TAP ran all builds centrally and only required a small amount of configuration: it
  simply required users to specify which paths they would like to test and where the (failure)
  notifications should go.&lt;/p&gt;
&lt;p&gt;The central builds and low configuration overhead made TAP immediately successful. Within a
  few years it had completely displaced the prior system. But, success came at a price: it was
  plagued by build capacity limitations and scalability challenges stemming from design decisions
  of running tests on each change in the initial implementation. By 2012 (following a full launch
  in 2010) Google was running low on machine capacity to run TAP. The testing model had naively
  assumed that the build dependence based test selection would be enough to control demand; It was
  not.&lt;/p&gt;
&lt;p&gt;TAP both pre- and post-submit were thus rewritten (multiple times). TAP Presubmit now has
  several different modes, adapts to resource availability, uses machine learning driven test
  selection, and has "advisors" which can ignore or rerun tests on failure &lt;span class="citation"
  data-cites="Hoang2024"&gt;(&lt;a href="#ref-Hoang2024" role="doc-biblioref"&gt;Hoang and Berding
  2024&lt;/a&gt;)&lt;/span&gt;. Unfortunately for you (the reader) discussing these innovations is out of scope
  for this manuscript.&lt;/p&gt;
&lt;p&gt;Today, TAP Postsubmit no longer runs on every change. It waits for there to be capacity in the
  Build System &lt;span class="citation" data-cites="Wang2020 Wang2021"&gt;(&lt;a href="#ref-Wang2020" role=
  "doc-biblioref"&gt;K. Wang et al. 2020&lt;/a&gt;, &lt;a href="#ref-Wang2021" role=
  "doc-biblioref"&gt;2021&lt;/a&gt;)&lt;/span&gt; and then enqueues all tests that have been affected since their
  last definitive status. At Google's scale and growth rate, we have had to continuously innovate
  and rewrite core parts of TAP just to maintain this model. However, we have long known that just
  using build-graph dependency based test selection in Postsubmit was untenable in the long term
  &lt;span class="citation" data-cites="Memon2017 Leong2019"&gt;(&lt;a href="#ref-Memon2017" role=
  "doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;; &lt;a href="#ref-Leong2019" role="doc-biblioref"&gt;Leong et al.
  2019&lt;/a&gt;)&lt;/span&gt;. It is only now that we have both the high-accuracy culprit finding
  infrastructure &lt;span class="citation" data-cites="Henderson2023 Henderson2024"&gt;(&lt;a href=
  "#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024"
  role="doc-biblioref"&gt;2024&lt;/a&gt;)&lt;/span&gt; and the organizational will to fundamentally change (again)
  core assumptions for how TAP works.&lt;/p&gt;
&lt;h2 id="the-current-dilemma"&gt;The Current Dilemma&lt;/h2&gt;
&lt;p&gt;The cost of TAP Postsubmit's &lt;em&gt;comprehensive&lt;/em&gt; testing continues to rise due to
  ever-increasing compute demand, increasing fleet machine diversity, and evolving development
  practices. This means that with no systemic changes in our approach towards Postsubmit
  testing:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;Teams start needing to wait longer and longer for signal on their projects' health (or
      "greenness") from TAP blocking their releases which has significant monetary impact&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Developers are now alerted hours after they submit of a breaking change, creating
      developer toil&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;h1 id="speculative-testing-cycles"&gt;Speculative Testing Cycles&lt;/h1&gt;
&lt;p&gt;In order to protect release quality and improve developer productivity, TAP is introducing
  &lt;em&gt;Speculative Testing Cycles&lt;/em&gt; - a process by which we non-deterministically select a
  smaller subset of targets that we deem more likely to fail, and run this smaller set more
  frequently than traditional comprehensive cycles. For traditional comprehensive test cycles, we
  attempt to batch as many builds/tests together at the same change as possible to get the caching
  benefits from Forge. We do the same here for Speculative Cycles, picking a single change
  approximately every 20 minutes, Forge build resources allowing. As with Comprehensive Cycles, we
  first perform static build system level dependency analysis to find all targets which could have
  a status change.&lt;/p&gt;
&lt;h2 id="determining-breakage-likelihood"&gt;Determining Breakage Likelihood&lt;/h2&gt;
&lt;p&gt;We now have a set of statically-filtered targets &lt;span class="math inline"&gt;{&lt;em&gt;T&lt;/em&gt;}&lt;/span&gt;
  and a sequence of commits &lt;span class="math inline"&gt;{&lt;em&gt;C&lt;/em&gt;}&lt;/span&gt; consisting of all commits
  since the last Speculative Cycle. Our problem is then to determine for a given target
  &lt;span class="math inline"&gt;&lt;em&gt;t&lt;/em&gt; ∈ &lt;em&gt;T&lt;/em&gt;&lt;/span&gt;: what is the likelihood it was broken by
  a change &lt;span class="math inline"&gt;&lt;em&gt;c&lt;/em&gt; ∈ &lt;em&gt;C&lt;/em&gt;&lt;/span&gt; affecting it? For compute
  tractability, given the frequency of change submissions and number of targets in our codebase, we
  simplify by choosing to aggregate across C and ask: "Was target &lt;span class=
  "math inline"&gt;&lt;em&gt;t&lt;/em&gt;&lt;/span&gt; broken by any change in &lt;span class=
  "math inline"&gt;&lt;em&gt;C&lt;/em&gt;&lt;/span&gt;?" We identify this problem formulation and approaches to answer
  it as &lt;em&gt;Transition Prediction&lt;/em&gt;, and discuss it in detail in the next section.&lt;/p&gt;
&lt;h2 id="making-scheduling-decisions"&gt;Making Scheduling Decisions&lt;/h2&gt;
&lt;p&gt;Our Transition Prediction model gives us "scores" from 0 to 1 indicating the propensity of
  this target to be newly broken. Given that we rely on machine learning models for these
  predictions, we must be careful to note that these scores do not meaningfully represent
  probabilities. They are the product of an algorithm attempting to minimize a loss function
  relative to its training dataset. While they can be colloquially understood to imply likelihood
  and allow relative comparison, moving the threshold at which scores map onto decisions to (not)
  schedule will produce non-linear changes to the actual observed probability of finding a breakage
  ("recall") or scheduling false positives ("false positive rate").&lt;/p&gt;
&lt;p&gt;Given this fact and our desire to have stable execution cost/latency under our scheduling
  scheme, we choose to primarily rank targets and schedule the top-k highest ranking targets under
  some top K parameter. For the purpose of this paper, this is our main parameter for tuning the
  Speculative Cycle system while the remaining knobs exist in feature selection and training
  configuration for the Transition Prediction ML model.&lt;/p&gt;
&lt;h2 id="goal-of-finding-test-breakages"&gt;Goal of Finding Test Breakages&lt;/h2&gt;
&lt;p&gt;As we've discussed, Postsubmit testing feeds into both Release pipelines and the breakage
  triage/fixing workflow (what we call "Build Gardening"). Release implications of Speculative
  Cycle(s) depend on many several other projects at play which are outside the scope of this paper.
  The direct outcome is that newly detected build/test failures will now propagate to Build
  Gardening consumers faster, namely:&lt;/p&gt;
&lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;Developers directly through emails sent upon detection of a failure&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Automated Culprit Finders that attempt to identify the specific culprit change&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Auto-Rollback reverts changes once it acquires enough evidence from culprit finders&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;

&lt;p&gt;&lt;span id="fig:culprit-prop" label="fig:culprit-prop"&gt;
    &lt;a href="images/icst-2025/fig1.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Figure 1" src="images/icst-2025/fig1.png"&gt;&lt;/a&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A developer or the automated culprit finders may only need a single target breakage (We will
  denote this criterion as &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(1)&lt;/span&gt;)
  to consider investigating and to identify a breaking change that needs to be reverted. But given
  the non-determinism issues discussed above, auto-rollback requires a stronger signal - at least
  &lt;span class="math inline"&gt;&lt;em&gt;N&lt;/em&gt;&lt;/span&gt; distinct targets were culprit-found to the same
  change (&lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(&lt;em&gt;N&lt;/em&gt;)&lt;/span&gt;).
  Both these goals are important to the health of the codebase, and while the former is a simple
  and more intuitive metric, there is a strong argument to be made for the latter - in that the
  number of distinct broken targets is a good proxy for the cost of that bad commit. The larger the
  number of broken targets, the larger the likelihood that it falls under a configured Presubmit
  testing directory, impacting developer productivity like we discussed above. Targets could belong
  to multiple release-level project groups, and more targets being broken is a higher cost to
  overall release health with more automation and production pushes being delayed or blocked.
  Figure &lt;a href="#fig:culprit-prop" data-reference-type="ref" data-reference=
  "fig:culprit-prop"&gt;[fig:culprit-prop]&lt;/a&gt; presents the total proportion of culprits remaining as
  we increase &lt;span class="math inline"&gt;&lt;em&gt;N&lt;/em&gt;&lt;/span&gt; which follows a power law
  distribution.&lt;/p&gt;
&lt;h2 id="evaluating-performance"&gt;Evaluating Performance&lt;/h2&gt;
&lt;p&gt;Culprit detection is then split between Comprehensive and Speculative Cycles. Under a specific
  scheduling scheme, Speculative Cycles successfully detect some proportion of culprits before
  Comprehensive Cycles. This proportion is the recall of the system. This recall in combination
  with the actual run frequency and execution runtime of the two cycles determines the actual
  reduction in culprit detection latency, where latency is defined relative to the submission time
  of the culprit change. Depending on the consumer, latency improvements will have non-linear
  marginal payoffs. For example, reduction from half a day to an hour may have measurable impacts
  on development friction caused by failing tests, but reduction from a half hour to 10 minutes may
  be negligible. Therefore, both metrics can be compared to the cost of a specific scheme in order
  to justify value / viability of the system.&lt;/p&gt;
&lt;h1 id="transition-prediction"&gt;Transition Prediction&lt;/h1&gt;
&lt;p&gt;Transition Prediction (or &lt;em&gt;TRANSPRED&lt;/em&gt; for short) attempts to predict transition
  likelihood every 20 minutes for millions of targets with a submission rate of over tens of
  thousands of changes per day. In order to make this tractable and most importantly
  cost-beneficial relative to simply running more tests, our predictions must be cheap and low
  latency. This informs using simple tree-based model techniques like Gradient Boosted Decision
  Trees and Random Forests. Tree-based models are used across industry for being low cost for
  inference, avoid over-fitting, and achieve high performance with simple coarse grained features
  like change and target metadata. We have found consistently throughout our work that Gradient
  Boosted Tree models perform best for Google's coarse grained test selection problems.&lt;/p&gt;
&lt;h2 id="features"&gt;Features&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:feature-collection" label="fig:feature-collection"&gt;
    &lt;a href="images/icst-2025/fig2.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 2&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Figure 2" src="images/icst-2025/fig2.png"&gt;&lt;/a&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure &lt;a href="#fig:feature-collection" data-reference-type="ref" data-reference=
  "fig:feature-collection"&gt;[fig:feature-collection]&lt;/a&gt; shows an overview of the structure of the
  feature vector. In a production system, only features that can be acquired quickly and reliably
  at scale can be used. The end-to-end latency of deciding which tests to run (including fetching
  the data, assembling the feature vectors, and running the prediction) needs to be well under 20
  minutes such that the current Speculative Cycle finishes before the next one begins. Thus, we are
  using simple, cheap to compute, coarse grained metadata features from targets and commits. The
  predictions are done per target so the features for one target are included in each feature
  vector. However, the predictions are not done for a single commit but across a range of commits.
  To increase the robustness of the commit based features, we only include commits that
  &lt;em&gt;affect&lt;/em&gt; the target. A commit affects a target if the target is reachable in the build
  graph from the files modified in the change.&lt;/p&gt;
&lt;p&gt;Target level features include static and dynamic characteristics. The static items are
  unchanging (or very rarely changing) and include target's programming language, whether it is a
  test or build target, and its Bazel rule type, etc. The dynamic items are based on historical
  execution data, such as the failure count in Postsubmit and Presubmit over several different time
  windows. Commit level features include: change metadata like lines of code modified, number of
  reviewers, number of linked bugs, description, etc. Finally, some features correspond to the
  relationship between the target and the changes in this specific cycle - specifically its build
  graph distance to the files modified and whether the target was run at Presubmit time.&lt;/p&gt;

&lt;p&gt;&lt;span id="table:featureDescription" label="table:featureDescription"&gt;
    &lt;a href="images/icst-2025/table1.png"&gt;&lt;em&gt;&lt;strong&gt;Table 1&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Table 1" src="images/icst-2025/table1.png"&gt;&lt;/a&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Table &lt;a href="#table:featureDescription" data-reference-type="ref" data-reference=
  "table:featureDescription"&gt;[table:featureDescription]&lt;/a&gt; contains details on the features used
  in the production model ('BASE') and those added for this paper ('AUG'), for augmented).&lt;/p&gt;
&lt;h2 id="labeling"&gt;Labeling&lt;/h2&gt;
&lt;p&gt;Our data set has a row/vector for each target in each Speculative Cycle. In order to train the
  model, we need to label each vector with whether or not that target should be run in the given
  Speculative Cycle. Optimally the targets should only be run when a new failure is introduced into
  the repository. We use the verified culprits data set described previously &lt;span class="citation"
  data-cites="Henderson2023 Henderson2024"&gt;(&lt;a href="#ref-Henderson2023" role=
  "doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024" role=
  "doc-biblioref"&gt;2024&lt;/a&gt;)&lt;/span&gt; as our source of truth on which commits introduced breakages.
  Unfortunately, the automated culprit finders de-prioritize comprehensiveness in favor of finding
  results quickly for active breakages blocking developers. This can leave some target level
  breakages with no culprit-identifying labels for up to two weeks after the failures was
  detected.&lt;/p&gt;
&lt;p&gt;In addition, some flakiness in tests and builds may be caused by something outside of the code
  and configuration checked into the repository. For example, a buggy compiler action may
  non-deterministically miscompile a file causing the linker to fail when it happens. Because the
  compile action "succeeds" (produces an output and no error code), the output of the compiler (the
  object file) will be cached. Subsequent builds will re-use the cached output and fail when
  attempting to link. However, if the cached item expires or the build happens in a different data
  center with a different cache the linker action may succeed (when the compiler behaved
  correctly). This type of flakiness is difficult to diagnose real-time with only build
  re-executions due to the multiple layers of caching. However, build executions separated in time
  have a better chance of identifying the flaky behavior.&lt;/p&gt;
&lt;p&gt;In order to protect against unavailability of data, we perform labeling a full week after the
  inference examples are acquired. As we've described, this still does not completely shield us
  from both incorrect positives and lack of coverage but is the best ground truth we have.&lt;/p&gt;
&lt;h2 id="super-extreme-class-imbalance"&gt;Super Extreme Class Imbalance&lt;/h2&gt;
&lt;p&gt;Postsubmit breakages are exceedingly rare. The only target-vector rows in our dataset that
  need to be scheduled are targets that are newly broken. This only occurs 0.0001% of the time. In
  model training, we refer to the class with fewer examples at the &lt;em&gt;minority class&lt;/em&gt; while
  the class with more examples is the &lt;em&gt;majority class&lt;/em&gt;. In our problem, the minority class
  is these newly broken targets just described.&lt;/p&gt;
&lt;p&gt;When there are too few examples in the minority class, the effectiveness of the many training
  algorithms is reduced. The "loss" (e.g. the function model training is optimizing) becomes biased
  towards the majority class. A classic pathological case is a model that trivially predicts the
  majority class - that is, predicts the majority class every time and never predicts the minority
  class. These models will actually minimize the loss function even though they never make useful
  predictions. Our approach must guard against these biases if we want to usefully predict which
  tests to run during a Speculative Cycle.&lt;/p&gt;
&lt;p&gt;For our system, we downsample the negative class (targets that are not newly failing). This
  reduces the imbalance between the classes. It also implicitly values the True Positives (new
  breakages) higher than the True Negatives. Every false negative (missed breakage) leads to
  developer toil as the detection of the breakage is delayed. Given the super extreme imbalance
  between the classes, we expect most targets run during a Speculative Cycle are to be False
  Negatives (and not indicate a new breakage).&lt;/p&gt;
&lt;h2 id="training-configuration"&gt;Training Configuration&lt;/h2&gt;
&lt;p&gt;For our model, we use the Yggdrasil Decision Forest library (YDF) &lt;span class="citation"
  data-cites="Guillame-Bert2023"&gt;(&lt;a href="#ref-Guillame-Bert2023" role=
  "doc-biblioref"&gt;Guillame-Bert et al. 2023&lt;/a&gt;)&lt;/span&gt;. YDF touts superior decision tree sampling
  and splitting algorithms over prior algorithms (such as XGBoost &lt;span class="citation"
  data-cites="chen2016xgboost"&gt;(&lt;a href="#ref-chen2016xgboost" role=
  "doc-biblioref"&gt;&lt;strong&gt;chen2016xgboost?&lt;/strong&gt;&lt;/a&gt;)&lt;/span&gt;) and provides better integration
  with Google's machine learning infrastructure.&lt;/p&gt;
&lt;p&gt;Conventional training schemes randomly shard their dataset between train, validation, and test
  splits or perhaps perform cross-validation with a set of parallel splits. For our problem,
  randomized splits are harmful and lead to us overestimating our performance as we leak
  time-dependent attributes of the repository across sets. Instead, we create time-ordered splits
  where the train set consists of the first &lt;span class="math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;/span&gt; days, the
  validation set the next &lt;span class="math inline"&gt;&lt;em&gt;B&lt;/em&gt;&lt;/span&gt; days, and the test set the
  final &lt;span class="math inline"&gt;&lt;em&gt;C&lt;/em&gt;&lt;/span&gt; days.&lt;/p&gt;
&lt;h1 id="sec:evaluation"&gt;Empirical Evaluation&lt;/h1&gt;
&lt;h2 id="evaluation"&gt;Evaluation&lt;/h2&gt;
&lt;p&gt;We empirically evaluated Speculative Cycles against a baseline random scheduler on
  culprit-detection recall and against an optimal algorithm for evaluating culprit detection
  latency improvements. We evaluated different dataset pruning/selection and training
  configurations to discover important hyper-parameters for the Transition Prediction model on a
  standard set of features. We examined three research questions:&lt;/p&gt;
&lt;h2 id="research-questions"&gt;Research Questions&lt;/h2&gt;
&lt;ol&gt;
    &lt;li&gt;
      &lt;p&gt;What is the performance of Speculative Cycles with Transition Prediction in terms of
      percentage of novel breakages detected (recall) in comparison to a baseline randomized
      testing approach?&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;Speculative cycles compete with full testing cycles for machine resources. Do speculative
      cycles improve productivity outcomes for Google developers?&lt;/p&gt;
    &lt;/li&gt;
    &lt;li&gt;
      &lt;p&gt;What aspects of the model design most impact system performance? Considered aspects
      include features selected, super-extreme class imbalance corrections, and training
      environment.&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;h2 id="measuring-performance-recall"&gt;Measuring Performance (Recall)&lt;/h2&gt;
&lt;p&gt;Speculative Cycles as a system attempts to detect bug introducing changes (culprits) through
  running and surfacing at least &lt;span class="math inline"&gt;&lt;em&gt;N&lt;/em&gt;&lt;/span&gt; newly failing targets.
  Specifically, the goal is to capture the majority of (newly failing) target results that detect
  novel bugs introduced into the repository with the faster Speculative Cycles instead of the
  slower Comprehensive Cycles. This naturally lends itself to measurement in the form of recall -
  the percentage of these events we capture.&lt;/p&gt;
&lt;p&gt;We additionally observe that our dataset is imperfect. Not every commit labeled as a "culprit"
  is indeed a bug introducing change. As discussed above, our datasets contains some inaccuracies
  particularly when a particular culprit commit only a few targets "blaming" it.&lt;a href="#fn2"
  class="footnote-ref" id="fnref2" role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; The distribution in the
  number of targets blaming a culprit follows a power law distribution. The majority of culprits
  are blamed by fewer than 10 targets. However, the lower the number of blamed targets the more
  likely it is that the culprit finding was inaccurate and that the commit does not in fact
  introduce a bug. In our labels, the signal is highest for culprits with many targets blaming them
  and lowest when there is only a single target. To protect our system from the noise these "small"
  culprits are filtered out during training.&lt;/p&gt;
&lt;p&gt;We use &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(&lt;em&gt;n&lt;/em&gt;)&lt;/span&gt;
  to denote the subset of culprits that have at least &lt;span class="math inline"&gt;&lt;em&gt;n&lt;/em&gt;&lt;/span&gt;
  targets blaming each culprit. In our evaluation, we provide recall over both (a) &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(1)&lt;/span&gt; -
  the set of all culprits and (b) &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt; -
  the set of culprits causing at least 10 target breakages where we successfully detect 10
  breakages. &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt;
  also ensures that we meet the (traditional) minimum required threshold (i.e. 10 failing targets)
  to trigger an automatic rollback. Speculative Cycles sees its highest value in terms of mean
  time-to-fix when automatic rollbacks are correctly triggered (especially for commits that have
  wider impact radius). Therefore, by assessing Recall using &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt;
  we also assess whether or not the Speculative Cycle can find enough evidence to trigger
  rollbacks.&lt;/p&gt;
&lt;h2 id="measuring-productivity-outcomes-latency-improvement"&gt;Measuring Productivity Outcomes
  (Latency Improvement)&lt;/h2&gt;
&lt;p&gt;Although recall is a concrete metric, our true goal is to improve productivity by reducing
  &lt;em&gt;friction&lt;/em&gt; caused by breakages that slipped into Postsubmit. Speculative Cycles focuses on
  early detection of breakages (and their culprit detection and fix) to reduce the friction caused
  by bad commits in Postsubmit. Its impact is measured by the reduction in "breakage detection
  latency". Early detection and fix also improves the mean time to fix latency for bad commits. We
  will evaluate the "breakage detection latency" decrease as a percentage relative to the current
  latency using empirically observed timings for running both Speculative and Comprehensive over
  the days present in our test dataset.&lt;/p&gt;
&lt;h2 id="high-priority-configuration-of-training-scheme"&gt;High Priority Configuration of Training
  Scheme&lt;/h2&gt;
&lt;p&gt;In general, it is considered good practice in machine learning to prioritize dataset quality
  over attempting to fine tune model level hyper-parameters. We have similarly observed little
  value in specific training parameters and use YDF's defaults for Gradient Boosted Trees for this
  work to show the general case performance expected. The more interesting questions that pertain
  to our dataset configuration are:&lt;/p&gt;
&lt;h3 id="training-split-window-size"&gt;Training Split / Window Size&lt;/h3&gt;
&lt;p&gt;As we use time based splitting to avoid the issue of "time-traveling" across the datasets, our
  training split configuration determines both the training "window size" and the "delay" between
  the training and test datasets.&lt;/p&gt;
&lt;p&gt;We hypothesized that the training data may have some recency bias. A shorter/ more recent
  look-back horizon on the training data may contain more useful signal for predicting the
  likelihood of a target transitioning. A longer window could dilute the usefulness of more recent
  breakages, while introducing noise from old breakages that have since been fixed and are less
  likely to reoccur. In order to test this hypothesis, we ran the model five times using the same
  feature set and configuration, only changing the number of weeks of data used during training.
  Note that our production pipeline uses a 3:1:1 week split for training:test:validation.&lt;/p&gt;
&lt;h3 id="downsampling-and-upweighting"&gt;Downsampling and Upweighting&lt;/h3&gt;
&lt;p&gt;Our extreme class imbalance of &lt;span class="math inline"&gt;40, 000 : 1&lt;/span&gt; necessitates
  downsampling our negative class to a ratio that is compute-efficient, but also avoids trivially
  predicting 0. Upweighting the positive class can be useful to appropriately value positive
  examples with respect to the loss function of the training algorithm. The ratios of down-sampling
  listed above reduced our class imbalance ratio to &lt;span class="math inline"&gt;400 : 1&lt;/span&gt;,
  &lt;span class="math inline"&gt;200 : 1&lt;/span&gt;, and &lt;span class="math inline"&gt;40 : 1&lt;/span&gt;
  respectively. For each case, we then upweighted the positive samples of target breaking commits
  by the new class imbalance ratio to see what effect, if any, it had on improving model
  performance.&lt;/p&gt;
&lt;h2 id="dataset"&gt;Dataset&lt;/h2&gt;
&lt;p&gt;Our evaluation dataset consists of roughly 3 months of Transition Prediction data split across
  Train, Validation, and Test sets. In total, the dataset consisted of 120 Billion target-cycle
  pairs, 7.7 million of which were breaking targets. This corresponds to &lt;span class=
  "math inline"&gt;∼&lt;/span&gt;20 thousand unique culprits. As mentioned above, we ensure that our splits
  are entirely sequential and disjoint to avoid cross contamination. The exact split and training
  configuration is varied while answering RQ3. We then fix our most performant model for evaluating
  RQ1 against the BASELINE random prediction and for RQ2 against latency in the CI environment with
  only Comprehensive Cycles.&lt;/p&gt;
&lt;h1 id="sec:results"&gt;Results&lt;/h1&gt;
&lt;h2 id="summary-of-results"&gt;Summary of Results&lt;/h2&gt;
&lt;li&gt;
  &lt;div class="tcolorbox"&gt;
    &lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: For RQ1 and RQ2, the model was trained using the 'AUG'
    feature set (Table &lt;a href="#table:featureDescription" data-reference-type="ref"
    data-reference="table:featureDescription"&gt;[table:featureDescription]&lt;/a&gt;), a 3-week training
    window, a 0.01 downsampling rate for the majority class, and no upweighting for the minority
    class. This configuration matches our production model, except for the feature set. RQ3
    explores performance across configurations.&lt;/p&gt;
  &lt;/div&gt;
  &lt;/li&gt;
&lt;h2 class="unnumbered" id=
  "rq1-what-is-the-performance-of-speculative-cycles-with-transition-prediction-in-terms-of-percentage-of-novel-breakages-detected-recall-in-comparison-to-a-baseline-randomized-testing-approach"&gt;
  &lt;strong&gt;RQ1&lt;/strong&gt;: What is the performance of Speculative Cycles with Transition Prediction in
  terms of percentage of novel breakages detected (recall) in comparison to a baseline randomized
  testing approach?&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:cl-level-recall" label="fig:cl-level-recall"&gt;
    &lt;a href="images/icst-2025/fig3.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 3&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Figure 3" src="images/icst-2025/fig3.png"&gt;&lt;/a&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;TRANSPRED demonstrates superior recall compared to the BASELINE model across all
  budgets (see Figure &lt;a href="#fig:cl-level-recall" data-reference-type="ref" data-reference=
  "fig:cl-level-recall"&gt;[fig:cl-level-recall]&lt;/a&gt;). At a budget of 25% of the total targets,
  TRANSPRED achieves a recall of 85%, greater than the BASELINE model's recall of 56%. This
  highlights the model's effectiveness in identifying breaking changes with limited
  resources.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the context of Transition Prediction, recall measures the percentage of breaking changes
  identified using a given budget. The budget parameterizes the recall metric as shown in Figure
  &lt;a href="#fig:cl-level-recall" data-reference-type="ref" data-reference=
  "fig:cl-level-recall"&gt;[fig:cl-level-recall]&lt;/a&gt;. To simplify the complex accounting of machine
  and test costs, we use the percentage of targets scheduled by TRANSPRED (versus a Comprehensive
  Cycle). Our budget for this assessment is 25% of the targets that would have been used by a
  Comprehensive Cycle. Recall is then defined as percentage of culprits identified out of the total
  set of culprits.&lt;/p&gt;
&lt;p&gt;Figure &lt;a href="#fig:cl-level-recall" data-reference-type="ref" data-reference=
  "fig:cl-level-recall"&gt;[fig:cl-level-recall]&lt;/a&gt; provides a visual representation of how recall
  changes as the percentage of scheduled targets varies, comparing the performance of TRANSPRED
  against the BASELINE model. For each model the figure shows the recall of both &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(1)&lt;/span&gt;
  and &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt;.
  &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(1)&lt;/span&gt;
  corresponds to finding any target for a breakage or informally, that breakages are at least
  "identified". The recall for &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt;
  concentrates on finding breakages with at least 10 targets broken - including scheduling at least
  10 of those broken targets to ensure auto rollback has enough evidence to trigger.&lt;/p&gt;
&lt;p&gt;For TRANSPRED, the &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(10)&lt;/span&gt;
  recall is higher than the &lt;span class=
  "math inline"&gt;&lt;em&gt;A&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;&lt;em&gt;L&lt;/em&gt;&lt;em&gt;e&lt;/em&gt;&lt;em&gt;a&lt;/em&gt;&lt;em&gt;s&lt;/em&gt;&lt;em&gt;t&lt;/em&gt;(1)&lt;/span&gt;
  recall. This indicates the model is better at catching bad commits that break 10 or more targets.
  It's intuitive that larger breakages would be better handled by the model as they are much better
  represented in the dataset, but an interesting result that we have is better coverage of them,
  i.e., consistently finding more individual targets broken by such commits. Culprits that only
  break a few tests are arguably less consequential than the few culprits that break a large number
  of tests. This strong performance on commits that break at least 10 targets indicates that when
  TRANSPRED does find a break, it has a good chance to be rolled back automatically.&lt;/p&gt;
&lt;p&gt;Both configurations for TRANSPRED outperform the BASELINE random model, indicating that the
  model is learning something useful from metadata and that the metadata alone (without considering
  the content of the changes) can be predictive of breakages. We look forward to future experiments
  utilizing the content of commits that compare both the efficacy and the model costs.&lt;/p&gt;
&lt;h2 class="unnumbered" id=
  "rq2-speculative-cycles-compete-with-full-testing-cycles-for-machine-resources-what-configurations-of-speculative-cycles-improve-productivity-outcomes-for-google-developers"&gt;
  &lt;strong&gt;RQ2&lt;/strong&gt;: Speculative Cycles compete with full testing cycles for machine resources,
  what configurations of Speculative Cycles improve productivity outcomes for Google
  developers?&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Speculative Cycles reduce the median (p50) breakage detection latency by 65% (70
  minutes) over the existing Comprehensive Cycles.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span id="fig:detection-latency" label="fig:detection-latency"&gt;
    &lt;a href="images/icst-2025/fig4.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 4&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Figure 4" src="images/icst-2025/fig4.png"&gt;&lt;/a&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Figure &lt;a href="#fig:detection-latency" data-reference-type="ref" data-reference=
  "fig:detection-latency"&gt;[fig:detection-latency]&lt;/a&gt; visualizes a histogram of the performance of
  the model in terms of &lt;em&gt;breakage detection latency&lt;/em&gt;. We consider this metric to be the
  "outcome metric" for this work as it is a proxy for improving overall developer productivity. It
  is known from internal work that developer productivity degrades when they need to debug build
  and test breakages they did not cause during interactive development. Productivity also degrades
  when they are interrupted to troubleshoot releases stalled due to breakages. By reducing the
  total time from culprit commit submission to detection, the model reduces the amount of friction
  developers experience from breakages.&lt;/p&gt;
&lt;p&gt;As with RQ1, we have fixed TRANSPRED to represent Speculative Cycles using the same Transition
  Prediction model and scheduling 25% of targets. In the visualization, the model (in black) is
  compared against two alternatives. The first labeled "Only Comprehensive" shows the distribution
  of time (in minutes) it takes the current TAP Postsubmit scheduling algorithm (Comprehensive
  Cycles) to detect breakages. The second alternative, "Optimal" imagines a perfect model that
  always correctly predicts which target need to be scheduled. Our model, TRANSPRED, falls between
  these two extremes of no-improvement to full-improvement. Observe that in comparison to "Only
  Comprehensive" the variance of breakage detection latency for TRANSPRED is substantially reduced.
  While, the new model isn't perfect (as shown in the figure), it is a welcome result that the
  Speculative Cycles reliably finds culprit commits in 37 minutes in the median case (p50), a 65%
  latency reduction over traditional Comprehensive Cycles that (p50) take 107 minutes.&lt;/p&gt;
&lt;h2 class="unnumbered" id=
  "rq3what-aspects-of-the-model-design-most-impact-performance-considered-aspects-include-features-selected-super-extreme-class-imbalance-corrections-and-training-environment."&gt;
  &lt;strong&gt;RQ3&lt;/strong&gt;:What aspects of the model design most impact performance? Considered aspects
  include features selected, super-extreme class imbalance corrections, and training
  environment.&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;The feature set used and the training window length had the greatest impact on model
  performance as measured by ROC AUC. Downsampling is critical for training speed but further
  downsampling hurts performance while upweighting has negligible impact.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To better understand how model design impacts performance, we ran multiple experiments across
  the different axes of decision making, including 1) feature selection, 2) training environment.
  and 3) different ways to correct for the super-extreme class imbalance&lt;/p&gt;
&lt;h3 id="feature-selection"&gt;Feature Selection&lt;/h3&gt;

&lt;p&gt;&lt;span id="table:samplingAndWeightTable" label="table:training-length"&gt;
  &lt;span id="table:training-length" label="table:training-length"&gt;
    &lt;a href="images/icst-2025/table2-3.png"&gt;&lt;em&gt;&lt;strong&gt;Tables 2 and 3&lt;/strong&gt;&lt;/em&gt;
    &lt;img alt="Tables 2 and 3" src="images/icst-2025/table2-3.png"&gt;&lt;/a&gt;
  &lt;/span&gt;
  &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Table &lt;a href="#table:training-length" data-reference-type="ref" data-reference=
  "table:training-length"&gt;[table:training-length]&lt;/a&gt; shows an improvement in performance when the
  model is trained on the 'AUGMENTED' feature set vs 'BASE' set, regardless of number of weeks
  considered for the training window. Critically, we see a lot of signal coming from the added
  target history features over longer time intervals.&lt;/p&gt;
&lt;h3 id="training-environment"&gt;Training Environment&lt;/h3&gt;
&lt;p&gt;Table &lt;a href="#table:training-length" data-reference-type="ref" data-reference=
  "table:training-length"&gt;[table:training-length]&lt;/a&gt; indicates our hypothesis was correct -
  performance starts to degrade as we increase or decrease the training window length from the
  optimal 3 weeks.&lt;/p&gt;
&lt;h3 id="correcting-for-super-extreme-class-imbalance"&gt;Correcting for Super-Extreme Class
  Imbalance&lt;/h3&gt;
&lt;p&gt;Production systems exhibit extremely low Postsubmit breakage rates (40,000:1 in our case).
  This class imbalance can hinder model training by biasing it towards the majority class. However,
  due to the asymmetric cost of false positives (unnecessary execution) versus false negatives
  (late breakage detection), prioritizing catching newly breaking targets at the cost of
  incorrectly scheduling some healthy targets is acceptable. This lets us experiment with some
  imbalance-correction techniques without being strictly bound to the true breakage rate, as shown
  in Table &lt;a href="#table:samplingAndWeightTable" data-reference-type="ref" data-reference=
  "table:samplingAndWeightTable"&gt;[table:samplingAndWeightTable]&lt;/a&gt;.&lt;/p&gt;
&lt;h1 id="related-work"&gt;Related Work&lt;/h1&gt;
&lt;p&gt;This paper explored the problem of reducing the time to discovery of novel test failures in
  continuous integration. This is a variation of the well studied problem of Test Case
  Prioritization and Selection &lt;span class="citation" data-cites=
  "Bates1993 Rothermel1997 Elbaum2000 Leon2003 Engstrom2010 Zhou2010 Singh2012 Gligoric2014 Mondal2015 Musa2015 DeS.CamposJunior2017 Najafi2019 Machalica2019 DeCastro-Cabrera2020 pan2022 Jin2023"&gt;
  (&lt;a href="#ref-Bates1993" role="doc-biblioref"&gt;Bates and Horwitz 1993&lt;/a&gt;; &lt;a href=
  "#ref-Rothermel1997" role="doc-biblioref"&gt;Rothermel and Harrold 1997&lt;/a&gt;; &lt;a href=
  "#ref-Elbaum2000" role="doc-biblioref"&gt;Elbaum, Malishevsky, and Rothermel 2000&lt;/a&gt;; &lt;a href=
  "#ref-Leon2003" role="doc-biblioref"&gt;Leon and Podgurski 2003&lt;/a&gt;; &lt;a href="#ref-Engstrom2010"
  role="doc-biblioref"&gt;Engström, Runeson, and Skoglund 2010&lt;/a&gt;; &lt;a href="#ref-Zhou2010" role=
  "doc-biblioref"&gt;Zhou 2010&lt;/a&gt;; &lt;a href="#ref-Singh2012" role="doc-biblioref"&gt;Singh et al.
  2012&lt;/a&gt;; &lt;a href="#ref-Gligoric2014" role="doc-biblioref"&gt;Gligoric et al. 2014&lt;/a&gt;; &lt;a href=
  "#ref-Mondal2015" role="doc-biblioref"&gt;Mondal, Hemmati, and Durocher 2015&lt;/a&gt;; &lt;a href=
  "#ref-Musa2015" role="doc-biblioref"&gt;Musa et al. 2015&lt;/a&gt;; &lt;a href="#ref-DeS.CamposJunior2017"
  role="doc-biblioref"&gt;de S. Campos Junior et al. 2017&lt;/a&gt;; &lt;a href="#ref-Najafi2019" role=
  "doc-biblioref"&gt;Najafi, Shang, and Rigby 2019&lt;/a&gt;; &lt;a href="#ref-Machalica2019" role=
  "doc-biblioref"&gt;Machalica et al. 2019&lt;/a&gt;; &lt;a href="#ref-DeCastro-Cabrera2020" role=
  "doc-biblioref"&gt;De Castro-Cabrera, García-Dominguez, and Medina-Bulo 2020&lt;/a&gt;; &lt;a href=
  "#ref-pan2022" role="doc-biblioref"&gt;Pan et al. 2022&lt;/a&gt;; &lt;a href="#ref-Jin2023" role=
  "doc-biblioref"&gt;Jin and Servant 2023&lt;/a&gt;)&lt;/span&gt; adapted to the CI environment &lt;span class=
  "citation" data-cites=
  "Chen2020 Saidani2020 Abdalkareem2021 Abdalkareem2021a Al-Sabbagh2022 Saidani2022 Saidani2022a Jin2023 Jin2024 Liu2023 Hong2024 Sun2024 Wang2024 Zeng2024"&gt;
  (&lt;a href="#ref-Chen2020" role="doc-biblioref"&gt;Chen et al. 2020&lt;/a&gt;; &lt;a href="#ref-Saidani2020"
  role="doc-biblioref"&gt;Saidani et al. 2020&lt;/a&gt;; &lt;a href="#ref-Abdalkareem2021" role=
  "doc-biblioref"&gt;Abdalkareem, Mujahid, and Shihab 2021&lt;/a&gt;; &lt;a href="#ref-Abdalkareem2021a" role=
  "doc-biblioref"&gt;Abdalkareem et al. 2021&lt;/a&gt;; &lt;a href="#ref-Al-Sabbagh2022" role=
  "doc-biblioref"&gt;Al-Sabbagh, Staron, and Hebig 2022&lt;/a&gt;; &lt;a href="#ref-Saidani2022" role=
  "doc-biblioref"&gt;Saidani, Ouni, and Mkaouer 2022a&lt;/a&gt;, &lt;a href="#ref-Saidani2022a" role=
  "doc-biblioref"&gt;2022b&lt;/a&gt;; &lt;a href="#ref-Jin2023" role="doc-biblioref"&gt;Jin and Servant 2023&lt;/a&gt;;
  &lt;a href="#ref-Jin2024" role="doc-biblioref"&gt;Jin et al. 2024&lt;/a&gt;; &lt;a href="#ref-Liu2023" role=
  "doc-biblioref"&gt;Liu et al. 2023&lt;/a&gt;; &lt;a href="#ref-Hong2024" role="doc-biblioref"&gt;Hong et al.
  2024&lt;/a&gt;; &lt;a href="#ref-Sun2024" role="doc-biblioref"&gt;Sun, Habchi, and McIntosh 2024&lt;/a&gt;;
  &lt;a href="#ref-Wang2024" role="doc-biblioref"&gt;G. Wang et al. 2024&lt;/a&gt;; &lt;a href="#ref-Zeng2024"
  role="doc-biblioref"&gt;Zeng et al. 2024&lt;/a&gt;)&lt;/span&gt;. Our approach is predicated on having highly
  accurate historical information on what causes breakages in the Google environment. We achieve
  this through culprit finding and verification &lt;span class="citation" data-cites=
  "Henderson2023 Henderson2024"&gt;(&lt;a href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
  2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024" role="doc-biblioref"&gt;2024&lt;/a&gt;)&lt;/span&gt;. Culprit finding
  &lt;span class="citation" data-cites=
  "Couder2008 Ziftci2013a Ziftci2017 Saha2017 Najafi2019a Beheshtian2022 keenan2019 An2021 Ocariza2022"&gt;
  (&lt;a href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;; &lt;a href="#ref-Ziftci2013a" role=
  "doc-biblioref"&gt;Ziftci and Ramavajjala 2013&lt;/a&gt;; &lt;a href="#ref-Ziftci2017" role=
  "doc-biblioref"&gt;Ziftci and Reardon 2017&lt;/a&gt;; &lt;a href="#ref-Saha2017" role="doc-biblioref"&gt;Saha
  and Gligoric 2017&lt;/a&gt;; &lt;a href="#ref-Najafi2019a" role="doc-biblioref"&gt;Najafi, Rigby, and Shang
  2019&lt;/a&gt;; &lt;a href="#ref-Beheshtian2022" role="doc-biblioref"&gt;Beheshtian, Bavand, and Rigby
  2022&lt;/a&gt;; &lt;a href="#ref-keenan2019" role="doc-biblioref"&gt;Keenan 2019&lt;/a&gt;; &lt;a href="#ref-An2021"
  role="doc-biblioref"&gt;An and Yoo 2021&lt;/a&gt;; &lt;a href="#ref-Ocariza2022" role="doc-biblioref"&gt;Ocariza
  2022&lt;/a&gt;)&lt;/span&gt; aims to identify the true "bug introducing commits" (BICs) &lt;span class=
  "citation" data-cites="Sliwerski2005 Rodriguez-Perez2018 Borg2019 Wen2019 An2023"&gt;(&lt;a href=
  "#ref-Sliwerski2005" role="doc-biblioref"&gt;Śliwerski, Zimmermann, and Zeller 2005&lt;/a&gt;; &lt;a href=
  "#ref-Rodriguez-Perez2018" role="doc-biblioref"&gt;Rodríguez-Pérez, Robles, and González-Barahona
  2018&lt;/a&gt;; &lt;a href="#ref-Borg2019" role="doc-biblioref"&gt;Borg et al. 2019&lt;/a&gt;; &lt;a href=
  "#ref-Wen2019" role="doc-biblioref"&gt;Wen et al. 2019&lt;/a&gt;; &lt;a href="#ref-An2023" role=
  "doc-biblioref"&gt;An et al. 2023&lt;/a&gt;)&lt;/span&gt; by rerunning tests over the search space of possible
  versions.&lt;/p&gt;
&lt;p&gt;The extensive amount of work on test selection and prioritization makes it difficult to fully
  summarize outside of a survey &lt;span class="citation" data-cites=
  "Engstrom2010 Singh2012 DeS.CamposJunior2017 DeCastro-Cabrera2020 pan2022"&gt;(&lt;a href=
  "#ref-Engstrom2010" role="doc-biblioref"&gt;Engström, Runeson, and Skoglund 2010&lt;/a&gt;; &lt;a href=
  "#ref-Singh2012" role="doc-biblioref"&gt;Singh et al. 2012&lt;/a&gt;; &lt;a href="#ref-DeS.CamposJunior2017"
  role="doc-biblioref"&gt;de S. Campos Junior et al. 2017&lt;/a&gt;; &lt;a href="#ref-DeCastro-Cabrera2020"
  role="doc-biblioref"&gt;De Castro-Cabrera, García-Dominguez, and Medina-Bulo 2020&lt;/a&gt;; &lt;a href=
  "#ref-pan2022" role="doc-biblioref"&gt;Pan et al. 2022&lt;/a&gt;)&lt;/span&gt;. Here are some highlights. Early
  work in test selection focused on selecting tests while maintaining test suite "adequacy"
  according to some (usually coverage based) criterion. For instance Bates and Horwitz &lt;span class=
  "citation" data-cites="Bates1993"&gt;(&lt;a href="#ref-Bates1993" role="doc-biblioref"&gt;Bates and
  Horwitz 1993&lt;/a&gt;)&lt;/span&gt; define a coverage criterion based on coverage of elements in the Program
  Dependence Graph (PDG) &lt;span class="citation" data-cites="Horwitz1988 Podgurski1989"&gt;(&lt;a href=
  "#ref-Horwitz1988" role="doc-biblioref"&gt;Horwitz, Prins, and Reps 1988&lt;/a&gt;; &lt;a href=
  "#ref-Podgurski1989" role="doc-biblioref"&gt;Podgurski and Clarke 1989&lt;/a&gt;)&lt;/span&gt; and Rothermel and
  Harrold developed a regression selection technique based on the PDG &lt;span class="citation"
  data-cites="Rothermel1997"&gt;(&lt;a href="#ref-Rothermel1997" role="doc-biblioref"&gt;Rothermel and
  Harrold 1997&lt;/a&gt;)&lt;/span&gt;. By 2000 papers such as Elbaum &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"
  data-cites="Elbaum2000"&gt;(&lt;a href="#ref-Elbaum2000" role="doc-biblioref"&gt;Elbaum, Malishevsky, and
  Rothermel 2000&lt;/a&gt;)&lt;/span&gt;'s were looking at prioritizing test cases based statement coverage to
  speed up test suite execution and evaluating performance based on the now standard &lt;em&gt;average
  percentage of faults detected&lt;/em&gt; (APFD) metric. By 2003, the community was starting to look for
  other sources of data to prioritize and filter test cases. For instance, Leon and Podgurski
  &lt;span class="citation" data-cites="Leon2003"&gt;(&lt;a href="#ref-Leon2003" role="doc-biblioref"&gt;Leon
  and Podgurski 2003&lt;/a&gt;)&lt;/span&gt; compared the bug finding efficacy (APFD) of coverage techniques
  versus techniques that prioritized diversity of basic block execution profiles (that included
  execution counts). In 2010 Engstrom &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation" data-cites=
  "Engstrom2010"&gt;(&lt;a href="#ref-Engstrom2010" role="doc-biblioref"&gt;Engström, Runeson, and Skoglund
  2010&lt;/a&gt;)&lt;/span&gt; surveyed the state of the test selection and documented 28 techniques.&lt;/p&gt;
&lt;p&gt;In 2017 the TAP team at Google began publishing on the problem &lt;span class="citation"
  data-cites="Memon2017 Leong2019"&gt;(&lt;a href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al.
  2017&lt;/a&gt;; &lt;a href="#ref-Leong2019" role="doc-biblioref"&gt;Leong et al. 2019&lt;/a&gt;)&lt;/span&gt; and
  separately a partner team had put into production an ML based test filtering system for TAP
  Presubmit. In contrast to this prior work by TAP, our current work is better grounded because of
  the verified culprits dataset we created in the last several years. For Memon &lt;em&gt;et al.&lt;/em&gt;
  &lt;span class="citation" data-cites="Memon2017"&gt;(&lt;a href="#ref-Memon2017" role=
  "doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;)&lt;/span&gt; TAP did not yet have a robust culprit finding
  system to precisely identify the bug introducing changes. Instead, that paper attempted to infer
  what commits might be the culprit. In Leong &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation" data-cites=
  "Leong2019"&gt;(&lt;a href="#ref-Leong2019" role="doc-biblioref"&gt;Leong et al. 2019&lt;/a&gt;)&lt;/span&gt; TAP did
  have a culprit finder but it was not as robust against flakiness and non-determinism as our
  current system. Our current culprit finder uses the Flake Aware algorithm (FACF) that adaptively
  deflakes the tests while performing culprit finding. Additionally, we further &lt;em&gt;verify&lt;/em&gt; all
  culprit commits by doing additional executions in patterns designed to catch flaky behavior
  &lt;span class="citation" data-cites="Henderson2023 Henderson2024"&gt;(&lt;a href="#ref-Henderson2023"
  role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;, &lt;a href="#ref-Henderson2024" role=
  "doc-biblioref"&gt;2024&lt;/a&gt;)&lt;/span&gt;. The FACF paper &lt;span class="citation" data-cites=
  "Henderson2023"&gt;(&lt;a href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
  2023&lt;/a&gt;)&lt;/span&gt; performed experiments that show the FACF algorithm is statistically
  significantly more accurate than the "deflaked variant" of the standard "bisect" algorithm used
  in the Leong paper. Specifically the experiments indicate FACF is &lt;span class=
  "math inline"&gt;&amp;gt;&lt;/span&gt;10% more accurate at identifying flaky breakages than Bisect with 8
  additional deflaking runs. By properly deflaking our training and evaluation labels, our model is
  much less likely to prioritize flaky tests and our evaluation more accurately reflects our
  desired productivity outcomes.&lt;/p&gt;
&lt;p&gt;Meanwhile in 2019, Machalica &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation" data-cites=
  "Machalica2019"&gt;(&lt;a href="#ref-Machalica2019" role="doc-biblioref"&gt;Machalica et al.
  2019&lt;/a&gt;)&lt;/span&gt; reported on a similar effort at Facebook in 2019 to develop a test selection
  system for their version of Presubmit testing. Conceptually, the Presubmit selection system at
  Facebook and the Presubmit selection system at Google have similarities. Both use shallow machine
  learning models with sets of features not dissimilar to the features presented in this work. Both
  systems (like this work) take a systematic approach to reducing the effect of flaky failures on
  developer productivity. The primary contribution of this paper versus this past work is the
  application and evaluation of selection techniques to the Postsubmit environment. In Postsubmit,
  the features must be necessarily adjusted as the prediction of whether or not a test will change
  behavior is not against a single commit but against a sequence of commits. Evaluation also
  changes: the concern is not just about recall but also latency of breakage detection and
  time-to-fix.&lt;/p&gt;
&lt;p&gt;Recently the wider field (outside of Google and Facebook) has produced compelling work
  &lt;span class="citation" data-cites=
  "Jin2023 Jin2024 Liu2023 Hong2024 Sun2024 Wang2024 Zeng2024"&gt;(&lt;a href="#ref-Jin2023" role=
  "doc-biblioref"&gt;Jin and Servant 2023&lt;/a&gt;; &lt;a href="#ref-Jin2024" role="doc-biblioref"&gt;Jin et al.
  2024&lt;/a&gt;; &lt;a href="#ref-Liu2023" role="doc-biblioref"&gt;Liu et al. 2023&lt;/a&gt;; &lt;a href=
  "#ref-Hong2024" role="doc-biblioref"&gt;Hong et al. 2024&lt;/a&gt;; &lt;a href="#ref-Sun2024" role=
  "doc-biblioref"&gt;Sun, Habchi, and McIntosh 2024&lt;/a&gt;; &lt;a href="#ref-Wang2024" role=
  "doc-biblioref"&gt;G. Wang et al. 2024&lt;/a&gt;; &lt;a href="#ref-Zeng2024" role="doc-biblioref"&gt;Zeng et al.
  2024&lt;/a&gt;)&lt;/span&gt;. We will note a few items here. Jin and Servant &lt;span class="citation"
  data-cites="Jin2023"&gt;(&lt;a href="#ref-Jin2023" role="doc-biblioref"&gt;Jin and Servant
  2023&lt;/a&gt;)&lt;/span&gt; presented HybridCISave which uses a shallow machine learning based approach to
  do both fine-grained (individual tests) and coarse grained (CI workflow builds) selection. By
  combining both selection types both cost savings and safety are improved. The authors evaluate
  their results using TravisTorrent &lt;span class="citation" data-cites="Beller2022"&gt;(&lt;a href=
  "#ref-Beller2022" role="doc-biblioref"&gt;Beller, Gousios, and Zaidman 2022&lt;/a&gt;)&lt;/span&gt;. This work
  is a good representative of the general approach of using shallow machine learning for selection
  outside of the mega-corp environment. Wang &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation" data-cites=
  "Wang2024"&gt;(&lt;a href="#ref-Wang2024" role="doc-biblioref"&gt;G. Wang et al. 2024&lt;/a&gt;)&lt;/span&gt; address
  the problem of feature selection by using a transformer based language model, GitSense, that
  automates statistic feature extraction. The authors evaluate their results using the dataset from
  Chen &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation" data-cites="Chen2020"&gt;(&lt;a href="#ref-Chen2020" role=
  "doc-biblioref"&gt;Chen et al. 2020&lt;/a&gt;)&lt;/span&gt;. Zeng &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"
  data-cites="Zeng2024"&gt;(&lt;a href="#ref-Zeng2024" role="doc-biblioref"&gt;Zeng et al. 2024&lt;/a&gt;)&lt;/span&gt;
  use mutation testing to better assess the safety of a commercial CI system (YourBase) that skips
  tests based on inferred dependencies. This use of mutation testing highlights one weakness of
  traditional safety evaluation, they only use historical faults and may miss novel bugs. By
  injecting mutation faults a more holistic view of the performance of the model can be obtained.
  Determining how to apply mutation testing to shallow machine learning approaches that use
  metadata features (such as ours) is an open problem.&lt;/p&gt;
&lt;h1 id="sec:conclusion"&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;In this paper, we presented a new scheduling system for Google's main test automation platform
  (TAP). The new scheduling system, Speculative Cycles, prioritizes finding novel test breakages
  faster. Speculative Cycles are powered by a new machine learning model, Transition Prediction,
  that predicts when tests are likely to fail. While the results are not perfect, they indicate
  that the new system reduces the breakage detection latency by 65% (70 minutes) on average. This
  reduction in breakage detection time leads to a reduction in developer friction and increased
  productivity. In terms of model design, the most impactful choice made was total amount of prior
  history used to train the model. As the training set size went from 1 week to 3 weeks model
  performance improved. But as the training set size further increased the model performance
  actually began to degrade. Only high level metadata features were used in this paper. In the
  future we look forward to experimenting with more complex models.&lt;/p&gt;

&lt;ul&gt;
  &lt;div id="refs" class="references csl-bib-body hanging-indent" data-entry-spacing="0" role="list"&gt;
    &lt;li&gt;
    &lt;div id="ref-Abdalkareem2021" class="csl-entry" role="listitem"&gt;
      Abdalkareem, Rabe, Suhaib Mujahid, and Emad Shihab. 2021. &lt;span&gt;"A &lt;span&gt;Machine Learning
      Approach&lt;/span&gt; to &lt;span&gt;Improve&lt;/span&gt; the &lt;span&gt;Detection&lt;/span&gt; of &lt;span&gt;CI Skip
      Commits&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 47 (12): 2740-54.
      &lt;a href=
      "https://doi.org/10.1109/TSE.2020.2967380"&gt;https://doi.org/10.1109/TSE.2020.2967380&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Abdalkareem2021a" class="csl-entry" role="listitem"&gt;
      Abdalkareem, Rabe, Suhaib Mujahid, Emad Shihab, and Juergen Rilling. 2021. &lt;span&gt;"Which
      &lt;span&gt;Commits Can Be CI Skipped&lt;/span&gt;?"&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software
      Engineering&lt;/em&gt; 47 (3): 448-63. &lt;a href=
      "https://doi.org/10.1109/TSE.2019.2897300"&gt;https://doi.org/10.1109/TSE.2019.2897300&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Al-Sabbagh2022" class="csl-entry" role="listitem"&gt;
      Al-Sabbagh, Khaled, Miroslaw Staron, and Regina Hebig. 2022. &lt;span&gt;"Predicting Build Outcomes
      in Continuous Integration Using Textual Analysis of Source Code Commits."&lt;/span&gt; In
      &lt;em&gt;Proceedings of the 18th &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Predictive
      Models&lt;/span&gt; and &lt;span&gt;Data Analytics&lt;/span&gt; in &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;,
      42-51. Singapore Singapore: ACM. &lt;a href=
      "https://doi.org/10.1145/3558489.3559070"&gt;https://doi.org/10.1145/3558489.3559070&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-An2023" class="csl-entry" role="listitem"&gt;
      An, Gabin, Jingun Hong, Naryeong Kim, and Shin Yoo. 2023. &lt;span&gt;"Fonte: &lt;span&gt;Finding Bug
      Inducing Commits&lt;/span&gt; from &lt;span&gt;Failures&lt;/span&gt;."&lt;/span&gt; arXiv. &lt;a href=
      "http://arxiv.org/abs/2212.06376"&gt;http://arxiv.org/abs/2212.06376&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-An2021" class="csl-entry" role="listitem"&gt;
      An, Gabin, and Shin Yoo. 2021. &lt;span&gt;"Reducing the Search Space of Bug Inducing Commits Using
      Failure Coverage."&lt;/span&gt; In &lt;em&gt;Proceedings of the 29th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on
      &lt;span&gt;European Software Engineering Conference&lt;/span&gt; and &lt;span&gt;Symposium&lt;/span&gt; on the
      &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 1459-62. Athens Greece:
      ACM. &lt;a href=
      "https://doi.org/10.1145/3468264.3473129"&gt;https://doi.org/10.1145/3468264.3473129&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Bates1993" class="csl-entry" role="listitem"&gt;
      Bates, Samuel, and Susan Horwitz. 1993. &lt;span&gt;"Incremental Program Testing Using Program
      Dependence Graphs."&lt;/span&gt; In &lt;em&gt;Proceedings of the 20th &lt;span&gt;ACM SIGPLAN-SIGACT&lt;/span&gt;
      Symposium on &lt;span&gt;Principles&lt;/span&gt; of Programming Languages - &lt;span&gt;POPL&lt;/span&gt; '93&lt;/em&gt;,
      384-96. Charleston, South Carolina, United States: ACM Press. &lt;a href=
      "https://doi.org/10.1145/158511.158694"&gt;https://doi.org/10.1145/158511.158694&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Beheshtian2022" class="csl-entry" role="listitem"&gt;
      Beheshtian, Mohammad Javad, Amir Hossein Bavand, and Peter C. Rigby. 2022. &lt;span&gt;"Software
      &lt;span&gt;Batch Testing&lt;/span&gt; to &lt;span&gt;Save Build Test Resources&lt;/span&gt; and to &lt;span&gt;Reduce
      Feedback Time&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 48 (8):
      2784-2801. &lt;a href=
      "https://doi.org/10.1109/TSE.2021.3070269"&gt;https://doi.org/10.1109/TSE.2021.3070269&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Beller2022" class="csl-entry" role="listitem"&gt;
      Beller, Moritz, Georgios Gousios, and Andy Zaidman. 2022.
      &lt;span&gt;"&lt;span&gt;TravisTorrent&lt;/span&gt;."&lt;/span&gt; figshare. &lt;a href=
      "https://doi.org/10.6084/M9.FIGSHARE.19314170.V1"&gt;https://doi.org/10.6084/M9.FIGSHARE.19314170.V1&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Bland2012" class="csl-entry" role="listitem"&gt;
      Bland, Mike. 2012. &lt;span&gt;"The &lt;span&gt;Chris&lt;/span&gt;/&lt;span&gt;Jay Continuous Build&lt;/span&gt;."&lt;/span&gt;
      Personal {{Website}}. &lt;em&gt;Mike Bland's Blog&lt;/em&gt;. &lt;a href=
      "https://mike-bland.com/2012/06/21/chris-jay-continuous-%20build.html"&gt;https://mike-bland.com/2012/06/21/chris-jay-continuous-
      build.html&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Borg2019" class="csl-entry" role="listitem"&gt;
      Borg, Markus, Oscar Svensson, Kristian Berg, and Daniel Hansson. 2019.
      &lt;span&gt;"&lt;span&gt;SZZ&lt;/span&gt; Unleashed: An Open Implementation of the &lt;span&gt;SZZ&lt;/span&gt; Algorithm -
      Featuring Example Usage in a Study of Just-in-Time Bug Prediction for the
      &lt;span&gt;Jenkins&lt;/span&gt; Project."&lt;/span&gt; In &lt;em&gt;Proceedings of the 3rd &lt;span&gt;ACM SIGSOFT
      International Workshop&lt;/span&gt; on &lt;span&gt;Machine Learning Techniques&lt;/span&gt; for &lt;span&gt;Software
      Quality Evaluation&lt;/span&gt; - &lt;span&gt;MaLTeSQuE&lt;/span&gt; 2019&lt;/em&gt;, 7-12. Tallinn, Estonia: ACM
      Press. &lt;a href=
      "https://doi.org/10.1145/3340482.3342742"&gt;https://doi.org/10.1145/3340482.3342742&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Chen2020" class="csl-entry" role="listitem"&gt;
      Chen, Bihuan, Linlin Chen, Chen Zhang, and Xin Peng. 2020. &lt;span&gt;"&lt;span&gt;BUILDFAST&lt;/span&gt;:
      &lt;span class="nocase"&gt;History-aware&lt;/span&gt; Build Outcome Prediction for Fast Feedback and
      Reduced Cost in Continuous Integration."&lt;/span&gt; In &lt;em&gt;2020 35th
      &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; International Conference on Automated Software Engineering
      (&lt;span&gt;ASE&lt;/span&gt;)&lt;/em&gt;, 42-53.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Couder2008" class="csl-entry" role="listitem"&gt;
      Couder, Christian. 2008. &lt;span&gt;"Fighting Regressions with Git Bisect."&lt;/span&gt; &lt;em&gt;The Linux
      Kernel Archives&lt;/em&gt; 4 (5). &lt;a href=
      "https://www.%20kernel.%20org/pub/software/scm/git/doc%20s/git-%20bisect-lk2009.html"&gt;https://www.
      kernel. org/pub/software/scm/git/doc s/git- bisect-lk2009.html&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-DeCastro-Cabrera2020" class="csl-entry" role="listitem"&gt;
      De Castro-Cabrera, M. Del Carmen, Antonio García-Dominguez, and Inmaculada Medina-Bulo. 2020.
      &lt;span&gt;"Trends in Prioritization of Test Cases: 2017-2019."&lt;/span&gt; &lt;em&gt;Proceedings of the ACM
      Symposium on Applied Computing&lt;/em&gt;, 2005-11. &lt;a href=
      "https://doi.org/10.1145/3341105.3374036"&gt;https://doi.org/10.1145/3341105.3374036&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-DeS.CamposJunior2017" class="csl-entry" role="listitem"&gt;
      de S. Campos Junior, Heleno, Marco Antônio P Araújo, José Maria N David, Regina Braga,
      Fernanda Campos, and Victor Ströele. 2017. &lt;span&gt;"Test &lt;span&gt;Case Prioritization&lt;/span&gt;:
      &lt;span&gt;A Systematic Review&lt;/span&gt; and &lt;span&gt;Mapping&lt;/span&gt; of the
      &lt;span&gt;Literature&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings of the 31st &lt;span&gt;Brazilian
      Symposium&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 34-43. New York, NY, USA: ACM.
      &lt;a href=
      "https://doi.org/10.1145/3131151.3131170"&gt;https://doi.org/10.1145/3131151.3131170&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Elbaum2000" class="csl-entry" role="listitem"&gt;
      Elbaum, Sebastian, Alexey G. Malishevsky, and Gregg Rothermel. 2000. &lt;span&gt;"Prioritizing Test
      Cases for Regression Testing."&lt;/span&gt; In &lt;em&gt;Proceedings of the 2000 &lt;span&gt;ACM SIGSOFT&lt;/span&gt;
      International Symposium on Software Testing and Analysis&lt;/em&gt;, 102-12. Issta '00. New York,
      NY, USA: Association for Computing Machinery. &lt;a href=
      "https://doi.org/10.1145/347324.348910"&gt;https://doi.org/10.1145/347324.348910&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Engstrom2010" class="csl-entry" role="listitem"&gt;
      Engström, Emelie, Per Runeson, and Mats Skoglund. 2010. &lt;span&gt;"A Systematic Review on
      Regression Test Selection Techniques."&lt;/span&gt; &lt;em&gt;Information and Software Technology&lt;/em&gt; 52
      (1): 14-30. &lt;a href=
      "https://doi.org/10.1016/j.infsof.2009.07.001"&gt;https://doi.org/10.1016/j.infsof.2009.07.001&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Fowler2006" class="csl-entry" role="listitem"&gt;
      Fowler, Martin. 2006. &lt;span&gt;"Continuous &lt;span&gt;Integration&lt;/span&gt;."&lt;/span&gt; &lt;a href=
      "https://martinfowler.com/articles/%20continuousIntegration.html"&gt;https://martinfowler.com/articles/
      continuousIntegration.html&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Gligoric2014" class="csl-entry" role="listitem"&gt;
      Gligoric, Milos, Rupak Majumdar, Rohan Sharma, Lamyaa Eloussi, and Darko Marinov. 2014.
      &lt;span&gt;"Regression &lt;span&gt;Test Selection&lt;/span&gt; for &lt;span&gt;Distributed Software
      Histories&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Computer &lt;span&gt;Aided Verification&lt;/span&gt;&lt;/em&gt;, edited by
      David Hutchison, Takeo Kanade, Josef Kittler, Jon M. Kleinberg, Alfred Kobsa, Friedemann
      Mattern, John C. Mitchell, et al., 8559:293-309. Cham: Springer International Publishing.
      &lt;a href=
      "https://doi.org/10.1007/978-3-319-08867-9_19"&gt;https://doi.org/10.1007/978-3-319-08867-9_19&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Guillame-Bert2023" class="csl-entry" role="listitem"&gt;
      Guillame-Bert, Mathieu, Sebastian Bruch, Richard Stotz, and Jan Pfeifer. 2023.
      &lt;span&gt;"Yggdrasil &lt;span&gt;Decision Forests&lt;/span&gt;: &lt;span&gt;A Fast&lt;/span&gt; and &lt;span&gt;Extensible
      Decision Forests Library&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings of the 29th &lt;span&gt;ACM SIGKDD
      Conference&lt;/span&gt; on &lt;span&gt;Knowledge Discovery&lt;/span&gt; and &lt;span&gt;Data Mining&lt;/span&gt;&lt;/em&gt;,
      4068-77. Long Beach CA USA: ACM. &lt;a href=
      "https://doi.org/10.1145/3580305.3599933"&gt;https://doi.org/10.1145/3580305.3599933&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Gupta2011" class="csl-entry" role="listitem"&gt;
      Gupta, Pooja, Mark Ivey, and John Penix. 2011. &lt;span&gt;"Testing at the Speed and Scale of
      &lt;span&gt;Google&lt;/span&gt;."&lt;/span&gt; &lt;a href=
      "https://google-engtools.blogspot.com/2011/06/testing-at-%20speed-and-scale-of-google.html"&gt;https://google-engtools.blogspot.com/2011/06/testing-at-
      speed-and-scale-of-google.html&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Henderson2023" class="csl-entry" role="listitem"&gt;
      Henderson, Tim A. D., Bobby Dorward, Eric Nickell, Collin Johnston, and Avi Kondareddy. 2023.
      &lt;span&gt;"Flake &lt;span&gt;Aware Culprit Finding&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;2023 &lt;span&gt;IEEE
      Conference&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Verification&lt;/span&gt; and
      &lt;span&gt;Validation&lt;/span&gt; (&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;. IEEE. &lt;a href=
      "https://doi.org/10.1109/ICST57152.2023.00041"&gt;https://doi.org/10.1109/ICST57152.2023.00041&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Henderson2024" class="csl-entry" role="listitem"&gt;
      Henderson, Tim A. D., Avi Kondareddy, Sushmita Azad, and Eric Nickell. 2024.
      &lt;span&gt;"&lt;span&gt;SafeRevert&lt;/span&gt;: &lt;span&gt;When Can Breaking Changes&lt;/span&gt; Be &lt;span&gt;Automatically
      Reverted&lt;/span&gt;?"&lt;/span&gt; In &lt;em&gt;2024 &lt;span&gt;IEEE Conference&lt;/span&gt; on &lt;span&gt;Software
      Testing&lt;/span&gt;, &lt;span&gt;Verification&lt;/span&gt; and &lt;span&gt;Validation&lt;/span&gt;
      (&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;, 395-406. Toronto, ON, Canada: IEEE. &lt;a href=
      "https://doi.org/10.1109/ICST60714.2024.00043"&gt;https://doi.org/10.1109/ICST60714.2024.00043&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Hoang2024" class="csl-entry" role="listitem"&gt;
      Hoang, Minh, and Adrian Berding. 2024. &lt;span&gt;"Presubmit &lt;span&gt;Rescue&lt;/span&gt;:
      &lt;span&gt;Automatically Ignoring FlakyTest Executions&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings of the
      1st &lt;span&gt;International Workshop&lt;/span&gt; on &lt;span&gt;Flaky Tests&lt;/span&gt;&lt;/em&gt;, 1-2. Lisbon
      Portugal: ACM. &lt;a href=
      "https://doi.org/10.1145/3643656.3643896"&gt;https://doi.org/10.1145/3643656.3643896&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Hong2024" class="csl-entry" role="listitem"&gt;
      Hong, Yang, Chakkrit Tantithamthavorn, Jirat Pasuksmit, Patanamon Thongtanunam, Arik
      Friedman, Xing Zhao, and Anton Krasikov. 2024. &lt;span&gt;"Practitioners' &lt;span&gt;Challenges&lt;/span&gt;
      and &lt;span&gt;Perceptions&lt;/span&gt; of &lt;span&gt;CI Build Failure Predictions&lt;/span&gt; at
      &lt;span&gt;Atlassian&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Companion &lt;span&gt;Proceedings&lt;/span&gt; of the 32nd
      &lt;span&gt;ACM International Conference&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
      Engineering&lt;/span&gt;&lt;/em&gt;, 370-81. Porto de Galinhas Brazil: ACM. &lt;a href=
      "https://doi.org/10.1145/3663529.3663856"&gt;https://doi.org/10.1145/3663529.3663856&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Horwitz1988" class="csl-entry" role="listitem"&gt;
      Horwitz, Susan, Jan Prins, and Thomas Reps. 1988. &lt;span&gt;"On the Adequacy of Program
      Dependence Graphs for Representing Programs."&lt;/span&gt; &lt;em&gt;ACM SIGPLAN-SIGACT Symposium on
      Principles of Programming Languages (POPL)&lt;/em&gt;, 146-57. &lt;a href=
      "https://doi.org/10.1145/73560.73573"&gt;https://doi.org/10.1145/73560.73573&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Jin2024" class="csl-entry" role="listitem"&gt;
      Jin, Xianhao, Yifei Feng, Chen Wang, Yang Liu, Yongning Hu, Yufei Gao, Kun Xia, and Luchuan
      Guo. 2024. &lt;span&gt;"&lt;span&gt;PIPELINEASCODE&lt;/span&gt;: &lt;span&gt;A CI&lt;/span&gt;/&lt;span&gt;CD Workflow Management
      System&lt;/span&gt; Through &lt;span&gt;Configuration Files&lt;/span&gt; at &lt;span&gt;ByteDance&lt;/span&gt;."&lt;/span&gt; In
      &lt;em&gt;2024 &lt;span&gt;IEEE International Conference&lt;/span&gt; on &lt;span&gt;Software Analysis&lt;/span&gt;,
      &lt;span&gt;Evolution&lt;/span&gt; and &lt;span&gt;Reengineering&lt;/span&gt; (&lt;span&gt;SANER&lt;/span&gt;)&lt;/em&gt;, 1011-22.
      Rovaniemi, Finland: IEEE. &lt;a href=
      "https://doi.org/10.1109/SANER60148.2024.00109"&gt;https://doi.org/10.1109/SANER60148.2024.00109&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Jin2023" class="csl-entry" role="listitem"&gt;
      Jin, Xianhao, and Francisco Servant. 2023. &lt;span&gt;"&lt;span&gt;HybridCISave&lt;/span&gt;: &lt;span&gt;A Combined
      Build&lt;/span&gt; and &lt;span&gt;Test Selection Approach&lt;/span&gt; in &lt;span&gt;Continuous
      Integration&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;ACM Transactions on Software Engineering and Methodology&lt;/em&gt;
      32 (4): 1-39. &lt;a href="https://doi.org/10.1145/3576038"&gt;https://doi.org/10.1145/3576038&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-keenan2019" class="csl-entry" role="listitem"&gt;
      Keenan, James. 2019. &lt;span&gt;"James &lt;span&gt;E&lt;/span&gt;. &lt;span&gt;Keenan&lt;/span&gt; -
      "&lt;span&gt;Multisection&lt;/span&gt;: &lt;span&gt;When Bisection Isn&lt;/span&gt;'t &lt;span&gt;Enough&lt;/span&gt; to
      &lt;span&gt;Debug&lt;/span&gt; a &lt;span&gt;Problem&lt;/span&gt;"."&lt;/span&gt; &lt;a href=
      "https://www.youtube.com/watch?v=05CwdTRt6AM"&gt;https://www.youtube.com/watch?v=05CwdTRt6AM&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Leon2003" class="csl-entry" role="listitem"&gt;
      Leon, D., and A. Podgurski. 2003. &lt;span&gt;"A Comparison of Coverage-Based and
      Distribution-Based Techniques for Filtering and Prioritizing Test Cases."&lt;/span&gt; In &lt;em&gt;14th
      &lt;span&gt;International Symposium&lt;/span&gt; on &lt;span&gt;Software Reliability Engineering&lt;/span&gt;, 2003.
      &lt;span&gt;ISSRE&lt;/span&gt; 2003.&lt;/em&gt;, 2003-Janua:442-53. IEEE. &lt;a href=
      "https://doi.org/10.1109/ISSRE.2003.1251065"&gt;https://doi.org/10.1109/ISSRE.2003.1251065&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Leong2019" class="csl-entry" role="listitem"&gt;
      Leong, Claire, Abhayendra Singh, Mike Papadakis, Yves Le Traon, and John Micco. 2019.
      &lt;span&gt;"Assessing &lt;span&gt;Transition-Based Test Selection Algorithms&lt;/span&gt; at
      &lt;span&gt;Google&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;2019 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st
      &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
      Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt; (&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 101-10. IEEE.
      &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP.2019.00019"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00019&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Liu2023" class="csl-entry" role="listitem"&gt;
      Liu, Bohan, He Zhang, Weigang Ma, Gongyuan Li, Shanshan Li, and Haifeng Shen. 2023.
      &lt;span&gt;"The &lt;span&gt;Why&lt;/span&gt;, &lt;span&gt;When&lt;/span&gt;, &lt;span&gt;What&lt;/span&gt;, and &lt;span&gt;How About
      Predictive Continuous Integration&lt;/span&gt;: &lt;span&gt;A Simulation-Based
      Investigation&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 49 (12):
      5223-49. &lt;a href=
      "https://doi.org/10.1109/TSE.2023.3330510"&gt;https://doi.org/10.1109/TSE.2023.3330510&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Machalica2019" class="csl-entry" role="listitem"&gt;
      Machalica, Mateusz, Alex Samylkin, Meredith Porth, and Satish Chandra. 2019.
      &lt;span&gt;"Predictive &lt;span&gt;Test Selection&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;2019
      &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International Conference&lt;/span&gt; on
      &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
      (&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 91-100. IEEE. &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP.2019.00018"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00018&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Memon2017" class="csl-entry" role="listitem"&gt;
      Memon, Atif, Zebao Gao, Bao Nguyen, Sanjeev Dhanda, Eric Nickell, Rob Siemborski, and John
      Micco. 2017. &lt;span&gt;"Taming &lt;span class="nocase"&gt;Google-scale&lt;/span&gt; Continuous
      Testing."&lt;/span&gt; In &lt;em&gt;2017 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 39th &lt;span&gt;International
      Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software Engineering&lt;/span&gt; in
      &lt;span&gt;Practice Track&lt;/span&gt; (&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 233-42. Piscataway, NJ, USA: IEEE.
      &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP.2017.16"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.16&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Micco2012" class="csl-entry" role="listitem"&gt;
      Micco, John. 2012. &lt;span&gt;"Tools for &lt;span&gt;Continuous Integration&lt;/span&gt; at &lt;span&gt;Google
      Scale&lt;/span&gt;."&lt;/span&gt; Tech {{Talk}}. Google NYC. &lt;a href=
      "https://youtu.be/KH2_sB1A6lA"&gt;https://youtu.be/KH2_sB1A6lA&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Micco2013" class="csl-entry" role="listitem"&gt;
      ---. 2013. &lt;span&gt;"Continuous &lt;span&gt;Integration&lt;/span&gt; at &lt;span&gt;Google Scale&lt;/span&gt;."&lt;/span&gt;
      Lecture. EclipseCon 2013. &lt;a href=
      "https://web.archive.org/web/20140705215747/https://%20www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-%2003-24%20Continuous%20Integration%20at%20Google%20Scale.pdf"&gt;
      https://web.archive.org/web/20140705215747/https://
      www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-
      03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Mondal2015" class="csl-entry" role="listitem"&gt;
      Mondal, Debajyoti, Hadi Hemmati, and Stephane Durocher. 2015. &lt;span&gt;"Exploring Test Suite
      Diversification and Code Coverage in Multi-Objective Test Case Selection."&lt;/span&gt; &lt;em&gt;2015
      IEEE 8th International Conference on Software Testing, Verification and Validation, ICST 2015
      - Proceedings&lt;/em&gt;, 1-10. &lt;a href=
      "https://doi.org/10.1109/ICST.2015.7102588"&gt;https://doi.org/10.1109/ICST.2015.7102588&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Musa2015" class="csl-entry" role="listitem"&gt;
      Musa, Samaila, Abu Bakar Md Sultan, Abdul Azim Bin Abd-Ghani, and Salmi Baharom. 2015.
      &lt;span&gt;"Regression &lt;span&gt;Test Cases&lt;/span&gt; Selection for &lt;span&gt;Object-Oriented Programs&lt;/span&gt;
      Based on &lt;span&gt;Affected Statements&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;International Journal of Software
      Engineering and Its Applications&lt;/em&gt; 9 (10): 91-108. &lt;a href=
      "https://doi.org/10.14257/ijseia.2015.9.10.10"&gt;https://doi.org/10.14257/ijseia.2015.9.10.10&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Najafi2019a" class="csl-entry" role="listitem"&gt;
      Najafi, Armin, Peter C. Rigby, and Weiyi Shang. 2019. &lt;span&gt;"Bisecting Commits and Modeling
      Commit Risk During Testing."&lt;/span&gt; In &lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint
      Meeting&lt;/span&gt; on &lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
      &lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
      Engineering&lt;/span&gt;&lt;/em&gt;, 279-89. New York, NY, USA: ACM. &lt;a href=
      "https://doi.org/10.1145/3338906.3338944"&gt;https://doi.org/10.1145/3338906.3338944&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Najafi2019" class="csl-entry" role="listitem"&gt;
      Najafi, Armin, Weiyi Shang, and Peter C. Rigby. 2019. &lt;span&gt;"Improving &lt;span&gt;Test
      Effectiveness Using Test Executions History&lt;/span&gt;: &lt;span&gt;An Industrial Experience
      Report&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;2019 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st
      &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
      Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt; (&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 213-22. IEEE.
      &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP.2019.00031"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00031&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Ocariza2022" class="csl-entry" role="listitem"&gt;
      Ocariza, Frolin S. 2022. &lt;span&gt;"On the &lt;span&gt;Effectiveness&lt;/span&gt; of &lt;span&gt;Bisection&lt;/span&gt;
      in &lt;span&gt;Performance Regression Localization&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;Empirical Software
      Engineering&lt;/em&gt; 27 (4): 95. &lt;a href=
      "https://doi.org/10.1007/s10664-022-10152-3"&gt;https://doi.org/10.1007/s10664-022-10152-3&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-pan2022" class="csl-entry" role="listitem"&gt;
      Pan, Rongqi, Mojtaba Bagherzadeh, Taher A. Ghaleb, and Lionel Briand. 2022. &lt;span&gt;"Test Case
      Selection and Prioritization Using Machine Learning: A Systematic Literature Review."&lt;/span&gt;
      &lt;em&gt;Empirical Software Engineering&lt;/em&gt; 27 (2): 29. &lt;a href=
      "https://doi.org/10.1007/s10664-021-10066-6"&gt;https://doi.org/10.1007/s10664-021-10066-6&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Podgurski1989" class="csl-entry" role="listitem"&gt;
      Podgurski, A, and L Clarke. 1989. &lt;span&gt;"The &lt;span&gt;Implications&lt;/span&gt; of &lt;span&gt;Program
      Dependencies&lt;/span&gt; for &lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Debugging&lt;/span&gt;, and
      &lt;span&gt;Maintenance&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings of the &lt;span&gt;ACM SIGSOFT&lt;/span&gt; '89
      &lt;span&gt;Third Symposium&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Analysis&lt;/span&gt;, and
      &lt;span&gt;Verification&lt;/span&gt;&lt;/em&gt;, 168-78. New York, NY, USA: ACM. &lt;a href=
      "https://doi.org/10.1145/75308.75328"&gt;https://doi.org/10.1145/75308.75328&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Potvin2016" class="csl-entry" role="listitem"&gt;
      Potvin, Rachel, and Josh Levenberg. 2016. &lt;span&gt;"Why Google Stores Billions of Lines of Code
      in a Single Repository."&lt;/span&gt; &lt;em&gt;Communications of the ACM&lt;/em&gt; 59 (7): 78-87. &lt;a href=
      "https://doi.org/10.1145/2854146"&gt;https://doi.org/10.1145/2854146&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Rodriguez-Perez2018" class="csl-entry" role="listitem"&gt;
      Rodríguez-Pérez, Gema, Gregorio Robles, and Jesús M. González-Barahona. 2018.
      &lt;span&gt;"Reproducibility and Credibility in Empirical Software Engineering: &lt;span&gt;A&lt;/span&gt; Case
      Study Based on a Systematic Literature Review of the Use of the &lt;span&gt;SZZ&lt;/span&gt;
      Algorithm."&lt;/span&gt; &lt;em&gt;Information and Software Technology&lt;/em&gt; 99 (July): 164-76. &lt;a href=
      "https://doi.org/10.1016/j.infsof.2018.03.009"&gt;https://doi.org/10.1016/j.infsof.2018.03.009&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Rothermel1997" class="csl-entry" role="listitem"&gt;
      Rothermel, Gregg, and Mary Jean Harrold. 1997. &lt;span&gt;"A Safe, Efficient Regression Test
      Selection Technique."&lt;/span&gt; &lt;em&gt;ACM Transactions on Software Engineering and
      Methodology&lt;/em&gt; 6 (2): 173-210. &lt;a href=
      "https://doi.org/10.1145/248233.248262"&gt;https://doi.org/10.1145/248233.248262&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Sadowski2018" class="csl-entry" role="listitem"&gt;
      Sadowski, Caitlin, Emma Söderberg, Luke Church, Michal Sipko, and Alberto Bacchelli. 2018.
      &lt;span&gt;"Modern Code Review: A Case Study at Google."&lt;/span&gt; In &lt;em&gt;Proceedings of the 40th
      &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
      Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;&lt;/em&gt;, 181-90. Gothenburg Sweden: ACM. &lt;a href=
      "https://doi.org/10.1145/3183519.3183525"&gt;https://doi.org/10.1145/3183519.3183525&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Saha2017" class="csl-entry" role="listitem"&gt;
      Saha, Ripon, and Milos Gligoric. 2017. &lt;span&gt;"Selective &lt;span&gt;Bisection
      Debugging&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Fundamental &lt;span&gt;Approaches&lt;/span&gt; to &lt;span&gt;Software
      Engineering&lt;/span&gt;&lt;/em&gt;, edited by Marieke Huisman and Julia Rubin, 10202:60-77. Berlin,
      Heidelberg: Springer Berlin Heidelberg. &lt;a href=
      "https://doi.org/10.1007/978-3-662-54494-5_4"&gt;https://doi.org/10.1007/978-3-662-54494-5_4&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Saidani2020" class="csl-entry" role="listitem"&gt;
      Saidani, Islem, Ali Ouni, Moataz Chouchen, and Mohamed Wiem Mkaouer. 2020. &lt;span&gt;"Predicting
      Continuous Integration Build Failures Using Evolutionary Search."&lt;/span&gt; &lt;em&gt;Information and
      Software Technology&lt;/em&gt; 128 (December): 106392. &lt;a href=
      "https://doi.org/10.1016/j.infsof.2020.106392"&gt;https://doi.org/10.1016/j.infsof.2020.106392&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Saidani2022" class="csl-entry" role="listitem"&gt;
      Saidani, Islem, Ali Ouni, and Mohamed Wiem Mkaouer. 2022a. &lt;span&gt;"Improving the Prediction of
      Continuous Integration Build Failures Using Deep Learning."&lt;/span&gt; &lt;em&gt;Automated Software
      Engineering&lt;/em&gt; 29 (1): 21. &lt;a href=
      "https://doi.org/10.1007/s10515-021-00319-5"&gt;https://doi.org/10.1007/s10515-021-00319-5&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Saidani2022a" class="csl-entry" role="listitem"&gt;
      ---. 2022b. &lt;span&gt;"Detecting &lt;span&gt;Continuous Integration Skip Commits Using Multi-Objective
      Evolutionary Search&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 48
      (12): 4873-91. &lt;a href=
      "https://doi.org/10.1109/TSE.2021.3129165"&gt;https://doi.org/10.1109/TSE.2021.3129165&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Singh2012" class="csl-entry" role="listitem"&gt;
      Singh, Yogesh, Arvinder Kaur, Bharti Suri, and Shweta Singhal. 2012. &lt;span&gt;"Systematic
      Literature Review on Regression Test Prioritization Techniques."&lt;/span&gt; &lt;em&gt;Informatica
      (Slovenia)&lt;/em&gt; 36 (4): 379-408. &lt;a href=
      "https://doi.org/10.31449/inf.v36i4.420"&gt;https://doi.org/10.31449/inf.v36i4.420&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Sliwerski2005" class="csl-entry" role="listitem"&gt;
      Śliwerski, Jacek, Thomas Zimmermann, and Andreas Zeller. 2005. &lt;span&gt;"When Do Changes Induce
      Fixes?"&lt;/span&gt; &lt;em&gt;ACM SIGSOFT Software Engineering Notes&lt;/em&gt; 30 (4): 1. &lt;a href=
      "https://doi.org/10.1145/1082983.1083147"&gt;https://doi.org/10.1145/1082983.1083147&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Sun2024" class="csl-entry" role="listitem"&gt;
      Sun, Gengyi, Sarra Habchi, and Shane McIntosh. 2024. &lt;span&gt;"&lt;span&gt;RavenBuild&lt;/span&gt;:
      &lt;span&gt;Context&lt;/span&gt;, &lt;span&gt;Relevance&lt;/span&gt;, and &lt;span&gt;Dependency Aware Build Outcome
      Prediction&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;Proceedings of the ACM on Software Engineering&lt;/em&gt; 1 (FSE):
      996-1018. &lt;a href="https://doi.org/10.1145/3643771"&gt;https://doi.org/10.1145/3643771&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Wang2024" class="csl-entry" role="listitem"&gt;
      Wang, Guoqing, Zeyu Sun, Yizhou Chen, Yifan Zhao, Qingyuan Liang, and Dan Hao. 2024.
      &lt;span&gt;"Commit &lt;span&gt;Artifact Preserving Build Prediction&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings
      of the 33rd &lt;span&gt;ACM SIGSOFT International Symposium&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;
      and &lt;span&gt;Analysis&lt;/span&gt;&lt;/em&gt;, 1236-48. Vienna Austria: ACM. &lt;a href=
      "https://doi.org/10.1145/3650212.3680356"&gt;https://doi.org/10.1145/3650212.3680356&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Wang2021" class="csl-entry" role="listitem"&gt;
      Wang, Kaiyuan, Daniel Rall, Greg Tener, Vijay Gullapalli, Xin Huang, and Ahmed Gad. 2021.
      &lt;span&gt;"Smart &lt;span&gt;Build Targets Batching Service&lt;/span&gt; at &lt;span&gt;Google&lt;/span&gt;."&lt;/span&gt; In
      &lt;em&gt;2021 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 43rd &lt;span&gt;International Conference&lt;/span&gt; on
      &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
      (&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 160-69. Madrid, ES: IEEE. &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP52600.2021.00025"&gt;https://doi.org/10.1109/ICSE-SEIP52600.2021.00025&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Wang2020" class="csl-entry" role="listitem"&gt;
      Wang, Kaiyuan, Greg Tener, Vijay Gullapalli, Xin Huang, Ahmed Gad, and Daniel Rall. 2020.
      &lt;span&gt;"Scalable Build Service System with Smart Scheduling Service."&lt;/span&gt; In
      &lt;em&gt;Proceedings of the 29th &lt;span&gt;ACM SIGSOFT International Symposium&lt;/span&gt; on
      &lt;span&gt;Software Testing&lt;/span&gt; and &lt;span&gt;Analysis&lt;/span&gt;&lt;/em&gt;, 452-62. Virtual Event USA: ACM.
      &lt;a href=
      "https://doi.org/10.1145/3395363.3397371"&gt;https://doi.org/10.1145/3395363.3397371&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Wen2019" class="csl-entry" role="listitem"&gt;
      Wen, Ming, Rongxin Wu, Yepang Liu, Yongqiang Tian, Xuan Xie, Shing-Chi Cheung, and Zhendong
      Su. 2019. &lt;span&gt;"Exploring and Exploiting the Correlations Between Bug-Inducing and
      Bug-Fixing Commits."&lt;/span&gt; In &lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint
      Meeting&lt;/span&gt; on &lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
      &lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
      Engineering&lt;/span&gt;&lt;/em&gt;, 326-37. Tallinn Estonia: ACM. &lt;a href=
      "https://doi.org/10.1145/3338906.3338962"&gt;https://doi.org/10.1145/3338906.3338962&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Zeng2024" class="csl-entry" role="listitem"&gt;
      Zeng, Zhili, Tao Xiao, Maxime Lamothe, Hideaki Hata, and Shane Mcintosh. 2024. &lt;span&gt;"A
      &lt;span&gt;Mutation-Guided Assessment&lt;/span&gt; of &lt;span&gt;Acceleration Approaches&lt;/span&gt; for
      &lt;span&gt;Continuous Integration&lt;/span&gt;: &lt;span&gt;An Empirical Study&lt;/span&gt; of
      &lt;span&gt;YourBase&lt;/span&gt;."&lt;/span&gt; In &lt;em&gt;Proceedings of the 21st &lt;span&gt;International
      Conference&lt;/span&gt; on &lt;span&gt;Mining Software Repositories&lt;/span&gt;&lt;/em&gt;, 556-68. Lisbon Portugal:
      ACM. &lt;a href=
      "https://doi.org/10.1145/3643991.3644914"&gt;https://doi.org/10.1145/3643991.3644914&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Zhou2010" class="csl-entry" role="listitem"&gt;
      Zhou, Zhi Quan. 2010. &lt;span&gt;"Using Coverage Information to Guide Test Case Selection in
      &lt;span&gt;Adaptive Random Testing&lt;/span&gt;."&lt;/span&gt; &lt;em&gt;Proceedings - International Computer
      Software and Applications Conference&lt;/em&gt;, 208-13. &lt;a href=
      "https://doi.org/10.1109/COMPSACW.2010.43"&gt;https://doi.org/10.1109/COMPSACW.2010.43&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Ziftci2013a" class="csl-entry" role="listitem"&gt;
      Ziftci, Celal, and Vivek Ramavajjala. 2013. &lt;span&gt;"Finding &lt;span&gt;Culprits
      Automatically&lt;/span&gt; in &lt;span&gt;Failing Builds&lt;/span&gt; - i.e. &lt;span&gt;Who Broke&lt;/span&gt; the
      &lt;span&gt;Build&lt;/span&gt;?"&lt;/span&gt; &lt;a href=
      "https://www.youtube.com/watch?v=SZLuBYlq3OM"&gt;https://www.youtube.com/watch?v=SZLuBYlq3OM&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
    &lt;li&gt;
    &lt;div id="ref-Ziftci2017" class="csl-entry" role="listitem"&gt;
      Ziftci, Celal, and Jim Reardon. 2017. &lt;span&gt;"Who Broke the Build? &lt;span&gt;Automatically&lt;/span&gt;
      Identifying Changes That Induce Test Failures in Continuous Integration at Google
      Scale."&lt;/span&gt; &lt;em&gt;Proceedings - 2017 IEEE/ACM 39th International Conference on Software
      Engineering: Software Engineering in Practice Track, ICSE-SEIP 2017&lt;/em&gt;, 113-22. &lt;a href=
      "https://doi.org/10.1109/ICSE-SEIP.2017.13"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.13&lt;/a&gt;.
    &lt;/div&gt;
    &lt;/li&gt;
  &lt;/div&gt;
  &lt;/ul&gt;
&lt;section id="footnotes" class="footnotes footnotes-end-of-document" role="doc-endnotes"&gt;
    &lt;hr /&gt;
    &lt;ol&gt;
      &lt;li id="fn1"&gt;
        &lt;p&gt;&lt;a href="https://bazel.build/" class="uri"&gt;https://bazel.build/&lt;/a&gt;&lt;a href="#fnref1"
        class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
      &lt;/li&gt;
      &lt;li id="fn2"&gt;
        &lt;p&gt;When a target breaks we perform culprit finding. The conclusion of the culprit finding
        is the culprit commit. We colloquially say the target is blaming the culprit.&lt;a href=
        "#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;
      &lt;/li&gt;
    &lt;/ol&gt;
  &lt;/section&gt;</content><category term="Paper"/></entry><entry><title>SafeRevert: When Can Breaking Changes be Automatically Reverted?</title><link href="https://hackthology.com/saferevert-when-can-breaking-changes-be-automatically-reverted.html" rel="alternate"/><published>2024-05-27T00:00:00-04:00</published><updated>2024-05-27T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;,  Avi Kondareddy, Sushmita Azad, Eric Nickell</name></author><id>tag:hackthology.com,2024-05-27:/saferevert-when-can-breaking-changes-be-automatically-reverted.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Avi Kondareddy, Sushmita Azad, and Eric Nickell.
&lt;em&gt;SafeRevert: When Can Breaking Changes be Automatically Reverted?&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2024/icst-2024-industry/7/SafeRevert-When-Can-Breaking-Changes-be-Automatically-Reverted-"&gt;ICST Industry Track 2024&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICST60714.2024.00043"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2024.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/saferevert-when-can-breaking-changes-be-automatically-reverted.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2024.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Abstract …&lt;/h4&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Avi Kondareddy, Sushmita Azad, and Eric Nickell.
&lt;em&gt;SafeRevert: When Can Breaking Changes be Automatically Reverted?&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2024/icst-2024-industry/7/SafeRevert-When-Can-Breaking-Changes-be-Automatically-Reverted-"&gt;ICST Industry Track 2024&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICST60714.2024.00043"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2024.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/saferevert-when-can-breaking-changes-be-automatically-reverted.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2024.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;When bugs or defects are introduced into a large scale software repository,
they reduce productivity. Programmers working on related areas of the code
will encounter test failures, compile breakages, or other anomalous behavior.
On encountering these issues, they will need to troubleshoot and determine
that their changes were not the cause of the error and that another change is
at fault. They must then find that change and &lt;em&gt;revert it&lt;/em&gt; to return the
repository to a healthy state. In the past, our group has identified ways to
identify the root cause (or culprit) change that introduced a test failure
even when the test is flaky. This paper focuses on a related issue: at what
point does the Continuous Integration system have enough evidence to support
&lt;em&gt;automatically reverting a change&lt;/em&gt;? We will motivate the problem, provide
several methods to address it, and empirically evaluate our solution on a
large set (25,137) of real-world breaking changes that occurred at
Google. SafeRevert improved recall (number of changes recommend for reversion)
by 2x over the baseline method while meeting our safety criterion.&lt;/p&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h1 id="sec:introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Large scale software development is enabled by automatically
executing tests in a continuous integration environment. Continuous
integration (CI) &lt;span class="citation" data-cites="Fowler2006"&gt;(&lt;a
href="#ref-Fowler2006" role="doc-biblioref"&gt;Fowler 2006&lt;/a&gt;)&lt;/span&gt; is
the industrial practice of using automated systems to automatically
integrate changes into the source of truth for the software system or
repository. This improves collaboration by helping software developers
avoid breaking compilation, tests, or structure of the system that
others are relying on.&lt;/p&gt;
&lt;p&gt;Corporations and teams may engage in CI using adhoc tools across many
independent software repositories. For instance Github (github.com)
supports CI “Actions" which can be integrated into any repository.
However, many organizations are recognizing the value of using a
“mono-repository" (monorepo) development model where many or all teams
in the organization use a single shared software repository &lt;span
class="citation" data-cites="Potvin2016"&gt;(&lt;a href="#ref-Potvin2016"
role="doc-biblioref"&gt;Potvin and Levenberg 2016&lt;/a&gt;)&lt;/span&gt;. At the
largest organizations such as Google &lt;span class="citation"
data-cites="Potvin2016 Memon2017 Henderson2023"&gt;(&lt;a
href="#ref-Potvin2016" role="doc-biblioref"&gt;Potvin and Levenberg
2016&lt;/a&gt;; &lt;a href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al.
2017&lt;/a&gt;; &lt;a href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et
al. 2023&lt;/a&gt;)&lt;/span&gt;, Microsoft &lt;span class="citation"
data-cites="Herzig2015a"&gt;(&lt;a href="#ref-Herzig2015a"
role="doc-biblioref"&gt;Herzig and Nagappan 2015&lt;/a&gt;)&lt;/span&gt;, and Facebook
&lt;span class="citation" data-cites="Machalica2019"&gt;(&lt;a
href="#ref-Machalica2019" role="doc-biblioref"&gt;Machalica et al.
2019&lt;/a&gt;)&lt;/span&gt; large repositories are complimented by advanced
centralized CI systems.&lt;/p&gt;
&lt;p&gt;In these large, modern CI systems, the integration goes beyond just
ensuring the code textually merges. Compilations are invoked, tests are
executed, and additional static and dynamic verification steps are
performed. The demand for machine resources can exceed capacity for
build, test, and verification tasks desired by a large-scale CI system.
To combat this problem, test case selection or prioritization is used
&lt;span class="citation"
data-cites="Gupta2011 Micco2013 Machalica2019"&gt;(&lt;a href="#ref-Gupta2011"
role="doc-biblioref"&gt;Gupta, Ivey, and Penix 2011&lt;/a&gt;; &lt;a
href="#ref-Micco2013" role="doc-biblioref"&gt;Micco 2013&lt;/a&gt;; &lt;a
href="#ref-Machalica2019" role="doc-biblioref"&gt;Machalica et al.
2019&lt;/a&gt;)&lt;/span&gt; to select fewer tests to run.&lt;/p&gt;
&lt;p&gt;Additionally, CI steps are often invoked at multiple points in the
Software Development Life Cycle. In the past, it may have been assumed
that the tests were executed by the CI system once, at the time a commit
was created in the version control. Today, CI may execute tests multiple
times during development: when a change is sent for code review,
immediately prior to submission or integration into the main development
branch, after one or more changes has been integrated into the
development branch, and when a new release is created. &lt;em&gt;This paper is
primary concerned with testing that occurs after the code has been
integrated into the main development branch.&lt;/em&gt;&lt;/p&gt;
&lt;h2 id="why-is-testing-necessary-after-code-integration"&gt;Why is Testing
Necessary After Code Integration?&lt;/h2&gt;
&lt;p&gt;When deploying CI for the first time, many organizations primarily
focus on conducting testing at the time a change is merged into the main
branch. For instance, they may test when a Pull Request (PR) on Github
is going to be merged into the main branch. The PR is merged if the
tests pass and no changes have been made to the main branch since the
testing started. This strategy works well until the rate of PR
submission exceeds the average amount of time it takes to run all the
tests.&lt;/p&gt;
&lt;p&gt;At this point, organizations may do a stop gap fix such as adding
more machines to run tests in parallel or reducing the size of the test
suite. However, at some point, these measures will prove ineffective and
the rate that testing can be conducted will become a impediment to an
organization’s engineering velocity. To address this, one common
solution is to introduce a “submission queue" which batches changes
together for testing and merges them all if the tests pass &lt;span
class="citation" data-cites="Ananthanarayanan2019"&gt;(&lt;a
href="#ref-Ananthanarayanan2019" role="doc-biblioref"&gt;Ananthanarayanan
et al. 2019&lt;/a&gt;)&lt;/span&gt;. If the tests fail, the offending change must be
identified and the remaining changes in the batch must be retested (at
least doubling the total testing time) &lt;span class="citation"
data-cites="Najafi2019"&gt;(&lt;a href="#ref-Najafi2019"
role="doc-biblioref"&gt;Najafi, Shang, and Rigby 2019&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;As the submission rate continues to increase, the organization may
add conservative test selection based on file-level dependence analysis
&lt;span class="citation" data-cites="Ananthanarayanan2019"&gt;(&lt;a
href="#ref-Ananthanarayanan2019" role="doc-biblioref"&gt;Ananthanarayanan
et al. 2019&lt;/a&gt;)&lt;/span&gt;. But at this point, the organization will be
reaching the limit of what can be done to completely prevent any
breaking changes from being integrated into the main development branch
beyond just buying more and more machines to further parallelize the
testing.&lt;/p&gt;
&lt;p&gt;And what about just buying more machines? Won’t this effectively
solve the problem? It would until the submission rate exceeds the time
it takes to run the slowest test. At this point, the number of machines
purchased can only partially control impact to developer productivity.
Even with a very large budget for testing, the number of changes per
batch will continue to grow as increases in the number of machines will
not reduce the batch size but only keep the testing time per batch
relatively constant. The larger the batch size, the more likely that a
developer will experience conflicts with another change when attempting
to submit. These conflicts (either at the syntactical or semantic level)
will make it difficult for developers to reliably submit their changes
and require them to constantly monitor the submission process. This
monitoring will hurt overall developer productivity.&lt;/p&gt;
&lt;p&gt;At the highest submission rates seen in industry today, using
submission queues that guarantee zero breaking changes becomes
infeasible both from a machine cost perspective and from a developer
productivity perspective. Therefore, many organizations relax the
requirement that an integrated change will never break a test. Even
while using submit queues to gate contributions for a single team,
Google has relied on postsubmit testing for mission-critical software
since the early 2000s as documented by Mike Bland &lt;span class="citation"
data-cites="Bland2012"&gt;(&lt;a href="#ref-Bland2012"
role="doc-biblioref"&gt;Bland 2012&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="post-submission-testing"&gt;Post Submission Testing&lt;/h2&gt;
&lt;p&gt;The purpose of testing after a change has been integrated (called
&lt;em&gt;Post-Submission&lt;/em&gt; Testing or &lt;em&gt;Postsubmit&lt;/em&gt; Testing
hereafter) is to identify defects that slipped through testing that
occurred prior to integration. Typically, organizations are unable to
run all tests at every integrated change. Instead, testing is conducted
periodically. In this paper we will refer to this periodic testing as
&lt;em&gt;Testing Cycles&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Figure &lt;a href="#fig:ci-timeline" data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt; is a simplified
view of the postsubmit testing strategy used at Google. The test
scheduler waits until our Build System &lt;span class="citation"
data-cites="Wang2020"&gt;(&lt;a href="#ref-Wang2020" role="doc-biblioref"&gt;Wang
et al. 2020&lt;/a&gt;)&lt;/span&gt; has capacity to start a test cycle. It then
schedules tests and then waits until the system has capacity again. When
scheduling tests, certain tests may be temporarily skipped or throttled
to conserve resources. As shown in Figure &lt;a href="#fig:ci-timeline"
data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt;, this leads to
the system usually detecting new failures some time after the version
that introduced them had been integrated. This leads to the problem of
“Culprit Finding."&lt;/p&gt;
&lt;h2 id="culprit-finding"&gt;Culprit Finding&lt;/h2&gt;
&lt;p&gt;Culprit finding is conceptually simple: given a list of versions that
may have introduced a fault, locate the offending change. One may solve
this problem with a variety of techniques: Zeller’s Delta Debugging
&lt;span class="citation" data-cites="Zeller1999"&gt;(&lt;a
href="#ref-Zeller1999" role="doc-biblioref"&gt;Zeller 1999&lt;/a&gt;)&lt;/span&gt;,
Git’s bisection algorithm &lt;span class="citation"
data-cites="Couder2008"&gt;(&lt;a href="#ref-Couder2008"
role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;, or Google’s Flake Aware
Culprit Finding (FACF) algorithm &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt;. Every technique
used to identify the offending change will have some error rate in
industrial practice.&lt;/p&gt;
&lt;p&gt;But wait! How can a binary search or delta debugging have an “error
rate"? The answer is that old nemesis of industrial practice: flaky or
non-deterministic test behavior &lt;span class="citation"
data-cites="parry2022"&gt;(&lt;a href="#ref-parry2022"
role="doc-biblioref"&gt;Parry et al. 2022&lt;/a&gt;)&lt;/span&gt;. Flaky tests can be
caused both by problems in the production code (ex: race conditions
causing rare errors), in the test code (ex: use of “sleep") and by
infrastructure problems (ex: unreliable machine with bad ram or network
congestion). All of these problems behave in &lt;em&gt;version
non-hermetic&lt;/em&gt; ways, where failures may not be strictly linked to the
version of code executed. Furthermore, even when the test is fully
&lt;em&gt;version hermetic&lt;/em&gt; the flakiness may not obey a Bernoulli
distribution as subsequent executions may not be fully independent of
the prior ones.&lt;/p&gt;
&lt;p&gt;The above issues mean that even culprit finding algorithms such as
FACF &lt;span class="citation" data-cites="Henderson2023"&gt;(&lt;a
href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
2023&lt;/a&gt;)&lt;/span&gt; that have been purpose-built to mitigate flakiness will
have some error rate. While that error rate will be much less than a
naive algorithm, it may still be high enough to cause problems when
deployed in certain environments.&lt;/p&gt;
&lt;h2 id="intro:auto-revert"&gt;Automatically Reverting Changes&lt;/h2&gt;
&lt;p&gt;Once an organization has a reliable and high performance culprit
finding system, it is natural to use it to automatically revert (undo,
roll back) changes that introduce defects into the main development
branch. By automatically undoing these changes, the system decreases the
amount of time developers working with impacted tests will experience
breakages that are unrelated to the changes they are working on. It will
also increase the number of versions that are viable to be used to make
software releases. Reducing development friction and increasing the
number of release candidates improves developer productivity by reducing
the amount of time developers spend troubleshooting tests that were
broken by someone else.&lt;/p&gt;
&lt;p&gt;Unfortunately, naively integrating FACF directly into a system that
immediately reverts all changes it identifies will lead to unhappy
developers. This is because even though Google’s FACF has a measured
&lt;em&gt;per-test accuracy&lt;/em&gt; of 99.54%, when aggregated (grouped) by
blamed change, the accuracy &lt;em&gt;per-change&lt;/em&gt; is only 77.37% in the
last 28 day window as of this writing.&lt;a href="#fn1"
class="footnote-ref" id="fnref1" role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;
This would translate into &lt;em&gt;incorrectly reverting&lt;/em&gt; approximately
20-130 changes per day out of an approximately of 300-500 total changes
per day reverted (see Figure &lt;a href="#fig:baseline"
data-reference-type="ref"
data-reference="fig:baseline"&gt;[fig:baseline]&lt;/a&gt;). At Google, we find
the cost of incorrectly reverting a change is extremely high in terms of
developer toil and frustration. Therefore, we need to reduce the rate of
bad reversions as much as possible. In this work, we aim to incorrectly
revert fewer than one change per day on average.&lt;/p&gt;
&lt;h2 id="our-contributions-and-findings"&gt;Our Contributions and
Findings&lt;/h2&gt;
&lt;p&gt;In this paper we propose a shallow machine-learning based method for
using the output of a culprit finding algorithm to automatically revert
(undo, rollback) a change that controls for potential errors from the
culprit finding algorithm. Our method is generic and can be used with
any culprit finding algorithm.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;SafeRevert: a method for using the output of any culprit finding
algorithm to automatically revert (undo) a change. SafeRevert controls
for the error rate while increasing total number of reversions over
baseline methods.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;An ablation study on the models, designs and features used by the
machine learning system used in SafeRevert to identify the most
impactful features and best models.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A large scale study on SafeRevert’s efficacy using &lt;span
class="math inline"&gt;\(\thicksim\)&lt;/span&gt;25,137 potential culprit changes
identified by Google’s production culprit finder over a &lt;span
class="math inline"&gt;\(\sim\)&lt;/span&gt;3 month window yields a recall of
55.7%, &lt;span class="math inline"&gt;\(\sim2.1 \times\)&lt;/span&gt; higher than
the baseline method.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="background"&gt;Background&lt;/h1&gt;

&lt;p&gt;&lt;span id="fig:ci-timeline" label="fig:ci-timeline"&gt;
&lt;a href="images/icst-2024/fig1.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 1&lt;/strong&gt;&lt;/em&gt;
&lt;img alt="Figure 1" src="images/icst-2024/fig1.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The Test Automation Platform (TAP) is a proprietary Continuous
Integration (CI) system at Google. It runs tests that execute on a
single machine without the use of the network or external resources.&lt;a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; All tests on TAP are required to run
in under 15 minutes and exceeding that limit is considered a test
failure. TAP executes tests both before a user submits their changes and
after the user has submitted their change. This paper is only concerned
with the testing that has occurred after a user has submitted a change.
At Google, this is referred to as “Postsubmit Testing". The part of TAP
that does Postsubmit Testing is called TAP Postsubmit.&lt;/p&gt;
&lt;p&gt;TAP has appeared in the literature several times &lt;span
class="citation"
data-cites="Gupta2011 Micco2012 Micco2013 Memon2017 Leong2019 Wang2020 Henderson2023"&gt;(&lt;a
href="#ref-Gupta2011" role="doc-biblioref"&gt;Gupta, Ivey, and Penix
2011&lt;/a&gt;; &lt;a href="#ref-Micco2012" role="doc-biblioref"&gt;Micco 2012&lt;/a&gt;,
&lt;a href="#ref-Micco2013" role="doc-biblioref"&gt;2013&lt;/a&gt;; &lt;a
href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;; &lt;a
href="#ref-Leong2019" role="doc-biblioref"&gt;Leong et al. 2019&lt;/a&gt;; &lt;a
href="#ref-Wang2020" role="doc-biblioref"&gt;Wang et al. 2020&lt;/a&gt;; &lt;a
href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
2023&lt;/a&gt;)&lt;/span&gt; and there has been gradual evolution its testing
strategy over the years. However, in general TAP uses a combination of
static and dynamic Test Selection, execution throttling, and
just-in-time scheduling to control testing load. A simplified diagram of
TAP Postsubmit testing is visualized in Figure &lt;a
href="#fig:ci-timeline" data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt;. Tests are
periodically run in Testing Cycles.&lt;a href="#fn3" class="footnote-ref"
id="fnref3" role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; During a cycle, Projects
that are eligible to run their test in the cycle are selected. Tests
from those projects are included if some file was modified since that
test’s last execution can influence their behavior via inspection of a
dependence graph at the Build Target and File level granularity &lt;span
class="citation" data-cites="Gupta2011 Micco2012"&gt;(&lt;a
href="#ref-Gupta2011" role="doc-biblioref"&gt;Gupta, Ivey, and Penix
2011&lt;/a&gt;; &lt;a href="#ref-Micco2012" role="doc-biblioref"&gt;Micco
2012&lt;/a&gt;)&lt;/span&gt;. When breakages inevitably occur culprit finding is
conducted using the FACF algorithm to locate the offending change &lt;span
class="citation" data-cites="Henderson2023"&gt;(&lt;a
href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
2023&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;FACF operates on a single test target at a time. For simplicity, we
use the term “test” both for a target which executes test code or for a
“build targets” which verifies that a binary can compile. Conceptually,
FACF performs a “Noisy Binary Search” &lt;span class="citation"
data-cites="Rivest1978"&gt;(&lt;a href="#ref-Rivest1978"
role="doc-biblioref"&gt;Rivest, Meyer, and Kleitman 1978&lt;/a&gt;)&lt;/span&gt; (also
called a Rényi-Ulam game &lt;span class="citation"
data-cites="Pelc2002"&gt;(&lt;a href="#ref-Pelc2002" role="doc-biblioref"&gt;Pelc
2002&lt;/a&gt;)&lt;/span&gt;) which FACF models under the Bayesian Search Framework
&lt;span class="citation" data-cites="Ben-Or2008"&gt;(&lt;a
href="#ref-Ben-Or2008" role="doc-biblioref"&gt;Ben-Or and Hassidim
2008&lt;/a&gt;)&lt;/span&gt;. The input to FACF includes the suspect changes
(“suspects”) that may have broken the test and an estimate collected by
an independent system of how likely it is to fail non-deterministically
without the presence of a deterministic bug, it’s “flakiness”. Much like
a normal binary search, it then divides the search space, executes
tests, and updates a probability distribution based on the outcomes.
Eventually, the system will determine that one of the suspects is above
a set probability threshold (.9999) and is the source of the test
failure, or that none of the suspects is at fault and the original
failure was spurious, due to a flake (non-deterministic failure).&lt;/p&gt;
&lt;h2 id="culprit-finding-accuracy"&gt;Culprit Finding Accuracy&lt;/h2&gt;
&lt;p&gt;Now some caveats: The math behind FACF &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt; assumes that
individual test executions of the same test at either the same version
or different versions are independent statistical events. That is, a
prior or concurrent execution of a test cannot influence a subsequent
execution. Unfortunately, while this assumption is theoretically sound,
in practice this property does not always hold. External factors outside
a program’s code can also influence a test’s execution behavior. For
example, the time of day, day of year, load on the machine, etc., can
all influence the outcome of certain tests. Thus, while we have
configured FACF to have an accuracy of 99.99%, in practice we do not
observe this level of accuracy. As noted in the Introduction, our
observed accuracy was 99.54% in the last 28 day window as of this
writing. This level of accuracy is consistent with the empirical study
conducted in the 2023 paper &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;How was accuracy “observed”? What was the ground truth used? By what
measurement technique? At Google, we continuously randomly sample a
subset of culprit finding execution results as they are completed. The
selected sample is then cross checked by performing extensive reruns
that demand a higher level of accuracy and assume a worse flakiness rate
for the test than used for culprit finding. Additionally, more reruns
are scheduled for a later time to control for time-based effects.
Finally, execution ordering effects are controlled for by ensuring that
executions at versions that should fail can fail both before and after
versions that should pass are executed. Full details on our methods for
verification can be found in the FACF paper &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt;. Even with
extensive reruns there remains a small probability of error. While our
method of verification is imperfect, it allows for continuously
computing a statistical estimate on the accuracy of the culprit
finder.&lt;/p&gt;
&lt;p&gt;Measurements of FACF accuracy reported in the 2023 paper were
performed per test breakage. That is, culprit finding is performed on a
test &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; when it has an observed
failure at some version &lt;span class="math inline"&gt;\(\beta\)&lt;/span&gt; when
it was previously passing at a prior version &lt;span
class="math inline"&gt;\(\alpha\)&lt;/span&gt;. The range &lt;span
class="math inline"&gt;\((\alpha, \beta]\)&lt;/span&gt; is referred to as the
&lt;em&gt;search-range&lt;/em&gt; and the key &lt;span class="math inline"&gt;\(\{t \times
(\alpha, \beta]\}\)&lt;/span&gt; is the &lt;em&gt;search-key&lt;/em&gt;. For a given
search-key, the culprit finder first filters the search-range to changes
on which &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; has a transitive build
dependence, which we call the &lt;em&gt;suspect-set&lt;/em&gt;. A culprit &lt;span
class="math inline"&gt;\(\kappa\)&lt;/span&gt; is identified somewhere between
&lt;span class="math inline"&gt;\(\beta\)&lt;/span&gt; and &lt;span
class="math inline"&gt;\(\alpha\)&lt;/span&gt; (e.g. &lt;span
class="math inline"&gt;\(\alpha \sqsubset \kappa \sqsubseteq \beta\)&lt;/span&gt;
where &lt;span class="math inline"&gt;\(a
\sqsubset b\)&lt;/span&gt; indicates version &lt;span
class="math inline"&gt;\(a\)&lt;/span&gt; is before version &lt;span
class="math inline"&gt;\(b\)&lt;/span&gt;). It is possible that there are
multiple &lt;span class="math inline"&gt;\(\kappa_t\)&lt;/span&gt; for different
&lt;span class="math inline"&gt;\(t\)&lt;/span&gt; w.r.t. the same search range,
which we can call the &lt;em&gt;culprit-set&lt;/em&gt; of the search range. What is
measured is whether or not &lt;span class="math inline"&gt;\(\kappa\)&lt;/span&gt;
is correct (true or false) for a given &lt;span
class="math inline"&gt;\(t\)&lt;/span&gt; and search range &lt;span
class="math inline"&gt;\(\alpha \sqsubset \beta\)&lt;/span&gt;. Accuracy is the
total correct measurements over the total number of measurements
taken.&lt;/p&gt;
&lt;h2 id="applying-culprit-finding-results-to-change-reversion"&gt;Applying
Culprit Finding Results to Change Reversion&lt;/h2&gt;
&lt;p&gt;When breaking changes get merged into the main development branch
they impede development productivity. At Google we term impediments to
productivity as “friction.” Breaking changes impact three types of
friction tracked at Google: Release Friction, Presubmit Friction and
Development Friction. Release Friction occurs when breaking changes that
merge into the main development branch impede automated releases and
require manual intervention by the primary team’s on-duty engineer.
Presubmit Friction occurs when pre-submission (“presubmit”) testing in
TAP fails due to a broken test in the main development branch.
Development Friction occurs when a developer manually triggers the
execution of a test broken on the main branch during active code
development. All three types of friction can steal time from developers
and reduce productivity.&lt;/p&gt;
&lt;p&gt;To reduce friction, changes that break tests can be automatically
reverted (“rolled back”). However, auto-revert (“auto-rollback”) only
improves developer productivity if the changes reverted actually broke
tests. Let’s consider for a moment what happens when a change is
incorrectly reverted. The developer who authored the change now needs to
go on a wholly different troubleshooting journey to determine why their
change didn’t stay submitted, and they are faced with the same
damning-but-incorrect evidence used to revert their change. The
developer is frustrated and must now debug tests that their team doesn’t
own and which their changes should not affect.&lt;/p&gt;
&lt;p&gt;Some changes are particularly difficult to submit with a buggy
auto-revert system: those that change core libraries. These changes have
the potential to break a large number of tests and impact a large number
of other developers. But, at the same time they are also more likely to
be incorrectly blamed (as TAP tracks what tests are affected by each
change and uses this as an input to culprit finding). Past auto-revert
systems that have been too inaccurate have caused core library authors
to opt their changes out of auto reversion as the productivity cost to
the core library teams has been too great to bear.&lt;/p&gt;
&lt;h2 id="accuracy-of-auto-revert-versus-culprit-finding"&gt;Accuracy of
Auto-Revert versus Culprit Finding&lt;/h2&gt;
&lt;p&gt;A change &lt;span class="math inline"&gt;\(\kappa\)&lt;/span&gt; that breaks a
test may have broken more than one. If so, then multiple independent
executions of the culprit finding algorithm (one for each broken test)
will blame the version &lt;span class="math inline"&gt;\(\kappa\)&lt;/span&gt; as
the culprit. As explored above, the algorithms have an error rate. A
change &lt;span class="math inline"&gt;\(\kappa\)&lt;/span&gt; that breaks &lt;span
class="math inline"&gt;\(n\)&lt;/span&gt; tests will have &lt;span
class="math inline"&gt;\(m \le n\)&lt;/span&gt; culprit finding conclusions that
correctly identify &lt;span class="math inline"&gt;\(\kappa\)&lt;/span&gt; as the
culprit.&lt;/p&gt;
&lt;p&gt;Our concern with auto-revert isn’t the accuracy of culprit finding
per search-key &lt;span class="math inline"&gt;\(\{t \times (\alpha,
\beta]\}\)&lt;/span&gt; but rather per culprit change &lt;span
class="math inline"&gt;\(\kappa\)&lt;/span&gt;. Let &lt;span
class="math inline"&gt;\(K\)&lt;/span&gt; be the set of all changes in the
repository blamed as culprits by the culprit finding system. Let &lt;span
class="math inline"&gt;\(c \subseteq K\)&lt;/span&gt; be the subset of the
culprits that are correct and &lt;span class="math inline"&gt;\(\overline{c}
\subseteq K\)&lt;/span&gt; be the subset of culprits that are incorrect. Then
if every culprit in &lt;span class="math inline"&gt;\(K\)&lt;/span&gt; was
automatically reverted, the accuracy of the auto-revert system would be
&lt;span class="math inline"&gt;\({\left|{c}\right|} /
{\left|{K}\right|}\)&lt;/span&gt;. In the introduction, we noted that the
accuracy &lt;em&gt;per change&lt;/em&gt; was 77.37% which equals &lt;span
class="math inline"&gt;\({\left|{c}\right|} /
{\left|{K}\right|}\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Why is the auto-revert accuracy (77.37%) lower than the culprit
finding accuracy (99.54%)? Because there are many more tests than
culprits and because correctly identified culprit changes may have
broken more than one test. The chance of finding that culprit is higher
because there are more chances to find it. Additionally, all of the
culprit finding conclusions that identify one of those changes that
break many tests will be correct. The set of incorrectly identified
culprit &lt;span class="math inline"&gt;\(\overline{c}\)&lt;/span&gt; tends to
contain mostly changes that are blamed by a fewer number of tests than
those in set &lt;span class="math inline"&gt;\(c\)&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="problem-statement"&gt;Problem Statement&lt;/h2&gt;
&lt;p&gt;Identify a method for selecting as many as possible changes from the
set of culprits &lt;span class="math inline"&gt;\(K\)&lt;/span&gt; that can be
safely reverted. A change is safe to revert if it is a true culprit.
Safety can be defined in terms of probability as well: A change is safe
to revert if the chance it is a true culprit is &lt;span
class="math inline"&gt;\(&amp;gt;99\%\)&lt;/span&gt;. The number of changes selected
should be maximized (while maintaining safety) to ensure the methods
performs reversions rather than safely doing nothing at all.&lt;/p&gt;
&lt;h1 id="automatically-reverting-changes"&gt;Automatically Reverting
Changes&lt;/h1&gt;

&lt;p&gt;&lt;span id="fig:baseline" label="fig:baseline"&gt;
&lt;a href="images/icst-2024/fig2.png"&gt;&lt;em&gt;&lt;strong&gt;Figure 2&lt;/strong&gt;&lt;/em&gt;
&lt;img alt="Figure 2" src="images/icst-2024/fig2.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We will describe several methods for selecting changes to revert
while maintaining the intended safety property. The first method is a
simple “baseline” method that the more complex methods will be evaluated
against. The other methods use shallow machine learning systems to take
advantage of metadata available at revert time.&lt;/p&gt;
&lt;p&gt;&lt;span id="sec:baseline" label="sec:baseline"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Our baseline method is based on a single observation: a change &lt;span
class="math inline"&gt;\(\kappa_0\)&lt;/span&gt; that is identified as the
culprit by culprit finding on many tests is more likely to be a culprit
than a change &lt;span class="math inline"&gt;\(\kappa_1\)&lt;/span&gt; that is only
blamed by a few tests. Therefore, the simplest heuristic approach to
selecting changes to revert is to threshold on a minimum number of tests
identifying the change. BASELINE(N) will refer to this method with
selecting changes with at least N blaming targets. Figure &lt;a
href="#fig:baseline" data-reference-type="ref"
data-reference="fig:baseline"&gt;[fig:baseline]&lt;/a&gt; shows the performance
of this method at various minimum number of targets. The most
conservative, BASELINE(50) can avoid most false positives while
reverting only a &lt;span class="math inline"&gt;\(\sim\)&lt;/span&gt;13% of true
culprits. We choose BASELINE(10) for our final evaluation as this is the
heuristic Google has historically used. Additionally, 10 is the lowest
configuration of BASELINE that generally (although not always) meets the
desired safety criteria.&lt;/p&gt;
&lt;h2 id="subsec:ml-models"&gt;Predicting Auto-Revert Correctness using
Machine Learning&lt;/h2&gt;
&lt;p&gt;Instead of choosing just one suggestive feature – the number of
blaming tests – to decide on a reversion, our proposed method uses
multiple features and shallow machine learning models to improve
performance relative to the baseline method. A selection of easily
obtainable coarse-grained metadata on the changes, tests, and culprit
finding process are used as features to the models. As these features
are mainly simple numerical, categorical, and textual features about the
code, we use simple model architectures to control for over-fitting.
Architectures examined are: Random Forests (RF) and AdaBoost (ADA) (both
provided by scikit-learn&lt;a href="#fn4" class="footnote-ref" id="fnref4"
role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt; &lt;span class="citation"
data-cites="scikit-learn"&gt;(&lt;a href="#ref-scikit-learn"
role="doc-biblioref"&gt;Pedregosa et al. 2011&lt;/a&gt;)&lt;/span&gt;), and XGBoost
(XGB)&lt;a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; &lt;span class="citation"
data-cites="Chen2016a"&gt;(&lt;a href="#ref-Chen2016a"
role="doc-biblioref"&gt;Chen and Guestrin 2016&lt;/a&gt;)&lt;/span&gt;. These
tree-based model architectures are easy to use, have low computational
costs, and are robust to the feature representation versus alternatives
that require more preprocessing.&lt;/p&gt;
&lt;h2 id="features-used"&gt;Features Used&lt;/h2&gt;
&lt;p&gt;A suspect change is one that has been identified by at least one
culprit-finder in the process of culprit finding a test. We can consider
this the test &lt;em&gt;blaming&lt;/em&gt; the change. For any suspect, we have one
or more blaming tests. Then, we have a few sources of information that
may be valuable for predicting a true breakage: characteristics of the
change itself and characteristics of the blaming tests or culprit
finding results. Table &lt;a href="#table:features-table"
data-reference-type="ref" data-reference="table:features-table"&gt;1&lt;/a&gt;
contains the grouping of the features against their logical feature
category, arrived at using the Pearson correlation between numerical
features and lift analysis for non-numeric features.&lt;/p&gt;
&lt;h2 id="feature-representation"&gt;Feature Representation&lt;/h2&gt;
&lt;h3 id="categorical-features"&gt;Categorical Features&lt;/h3&gt;
&lt;p&gt;Given a set of categories, we can create a fixed length
representation by encoding a choice of category as a one-hot vector.
When we have a variable number of categories per instance, such as
language per test, this trivially becomes a multi-hot representation by
summing the vectors.&lt;/p&gt;
&lt;h3 id="numerical-features"&gt;Numerical Features&lt;/h3&gt;
&lt;p&gt;Singular numerical fields are integrated without preprocessing or
normalization, as we expect decision trees to be robust to
value-scaling. Variable-length numerical fields are turned into
variable-length categorical fields by generating bins representing
quantiles of the training set distribution of that value. Then,
bin-mapped values can be condensed into a fixed-length multi-hot
encoding as above.&lt;/p&gt;
&lt;h3 id="token-set-features"&gt;Token Set Features&lt;/h3&gt;
&lt;p&gt;Token Sets correspond to variable-length categorical features where
the list of categories is not known in advance. A good example of such a
feature is compiler flags which should be dealt with adaptively by the
model. We handle this issue by building a vocabulary per token-set
feature on the training set parameterized by a minimum and maximum
across-instance frequency. The change description, while potentially
better dealt with through doc2vec or a more sophisticated NLP embedding
approach, is treated like a token set and the resulting multi-hot
encoding, having each field normalized by document frequency
(TF-IDF).&lt;/p&gt;
&lt;p&gt; &lt;span id="table:features-table"
label="table:features-table"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="center"&gt;
&lt;div id="table:features-table"&gt;
&lt;table&gt;
&lt;caption&gt; &lt;span class="smallcaps"&gt;Features for Machine Learning
Model.&lt;/span&gt; &lt;/caption&gt;
&lt;thead&gt;
&lt;tr class="header"&gt;
&lt;th style="text-align: left;"&gt;Category&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Features&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;BASE&lt;/td&gt;
&lt;td style="text-align: left;"&gt;# of Blaming Tests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td rowspan="3" style="text-align: left;"&gt;CHANGE_CONTENT&lt;/td&gt;
&lt;td style="text-align: left;"&gt;LOC (changed, added, deleted, total)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;# of Files Changed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="text-align: left;"&gt;File Extensions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td rowspan="3" style="text-align: left;"&gt;CHANGE_METADATA&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Reviewer/Approver Count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="text-align: left;"&gt;Issue/Bug Count&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Robot Author&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td rowspan="2" style="text-align: left;"&gt;CHANGE_TOKENS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Directory Tokens&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td rowspan="2" style="text-align: left;"&gt;CULPRIT_FINDER&lt;/td&gt;
&lt;td style="text-align: left;"&gt;&lt;span
class="math inline"&gt;\(|\)&lt;/span&gt;Suspect-Set&lt;span
class="math inline"&gt;\(|\)&lt;/span&gt; of Search-Key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;&lt;span
class="math inline"&gt;\(|\)&lt;/span&gt;Culprit-Set&lt;span
class="math inline"&gt;\(|\)&lt;/span&gt; of Search-Range&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td rowspan="2" style="text-align: left;"&gt;FLAKINESS&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Historical Flaky Identification Count
(Build/Test)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Historical Execution Flake Rate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td rowspan="6" style="text-align: left;"&gt;TEST_ATTRIBUTES&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Type of Test (Test vs Build)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Bazel Rule (Ex: “java_test”)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="text-align: left;"&gt;Machine Types (Ex: gpu)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Test Language (Ex: java, c++, etc)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td style="text-align: left;"&gt;Compiler Flags (ex: sanitizers)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td style="text-align: left;"&gt;Average Machine Cost&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;/p&gt;
&lt;h2 id="feature-grouping"&gt;Feature Grouping&lt;/h2&gt;
&lt;h3 id="logical-sub-grouping-for-feature-lift-analysis"&gt;Logical
Sub-Grouping for Feature Lift Analysis&lt;/h3&gt;
&lt;p&gt;In order to avoid crowding out the evaluation and analysis with too
many combinations of features, we’ve grouped them in Table &lt;a
href="#table:features-table" data-reference-type="ref"
data-reference="table:features-table"&gt;1&lt;/a&gt; into logical groups of
features based off of conceptual categories and to reflect cross-feature
correlations for numerical features, computed via pearsons correlation
coefficient. As our “Token Set" features represent a distinct class of
features both in terms of encoding method and granularity (highly
specific to individual changes), we separate them from the coarse-grain
change features. These logical groups will allow us to clearly convey
the individual signal being provided by each class of feature during our
feature analysis.&lt;/p&gt;
&lt;h3 id="subsec:avail-group-features"&gt;Availability Sub-Grouping for Model
Comparison Analysis&lt;/h3&gt;
&lt;p&gt;Separately, we define the feature sets F = {&lt;em&gt;BASE&lt;/em&gt;,
&lt;em&gt;AHEAD-OF-TIME&lt;/em&gt;, &lt;em&gt;REAL-TIME&lt;/em&gt;, &lt;em&gt;ALL&lt;/em&gt;} to distinguish
between features available at any potential inference time&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;BASE&lt;/em&gt; is just the number of blaming tests. This
corresponds to the BASELINE heuristic method.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;AHEAD-OF-TIME&lt;/em&gt; features are properties of the change
under suspicion, and are therefore available immediately. Features under
CHANGE_CONTENT, CHANGE_METADATA, and CHANGE_TOKENS from Table &lt;a
href="#table:features-table" data-reference-type="ref"
data-reference="table:features-table"&gt;1&lt;/a&gt; belong here.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;REAL-TIME&lt;/em&gt; features are available only as a result of
culprit finding processes at play continuously during the decision
window, and can become available at different times based on different
sources of generation, often after a change has already been suspected
by a culprit finder – all other features from Table &lt;a
href="#table:features-table" data-reference-type="ref"
data-reference="table:features-table"&gt;1&lt;/a&gt; fall in this set.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;ALL&lt;/em&gt; features is the union of &lt;em&gt;AHEAD-OF-TIME&lt;/em&gt; and
&lt;em&gt;REAL-TIME&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This distinction is important: the usefulness of automatically
reverting changes is critically dependent on its latency from the point
of discovering that a breakage exists. The longer we take to
automatically revert the change, the more friction experienced by
developers, and the more likely a developer would have had to manually
intervene.&lt;/p&gt;
&lt;h3 id="subsubsec:feature-min"&gt;Feature Minimization&lt;/h3&gt;
&lt;p&gt;Given the demonstrated feature lift, we’re also interested in
minimizing the features needed to achieve similar performance levels
without over-fitting on redundant features. We’ll elaborate on the exact
minimized feature sets in the evaluation section for feature analysis,
where we use representative features from each logical sub-groups that
provide significant lift individually. Thus we have 3 further feature
sets, MIN(f) for &lt;span class="math inline"&gt;\(f \in F\)&lt;/span&gt;.
Representative features are determined over the test set based on
individual feature comparison, left out for brevity in the analysis,
rather than the logical category evaluation presented here. We evaluate
RF(f), ADA(f), XGB(f), RF(MIN(f)), ADA(MIN(f)), and XGB(MIN(f)) for each
feature set &lt;span class="math inline"&gt;\(f \in F\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;h2
id="thresholding-to-use-model-prediction-score-for-selection"&gt;Thresholding
to use Model Prediction Score for Selection&lt;/h2&gt;&lt;/p&gt;
&lt;p&gt;Models produce an output probability score from 0 to 1. To discretize
these scores into actual change selections. We dynamically pick a
threshold using the TEST dataset to select the threshold that minimizes
the bad revert rate while maximizing a positive, non-zero recall.&lt;/p&gt;
&lt;h2 id="hyperparams-for-ml-models"&gt;Hyperparams for ML Models&lt;/h2&gt;
&lt;p&gt;Using scikit-learn, we define RF as the RandomForestClassifier
parameterized with a depth of 16 and ADA as the AdaBoostClassifier with
default parameters, each of which provide discretized predictions with
the above threshold selection procedure. XGBoost is configured with:
objective=‘binary:logistic’, eta=0.05, and max_delta_step = 1.&lt;/p&gt;
&lt;h1 id="sec:evaluation"&gt;Empirical Evaluation&lt;/h1&gt;
&lt;p&gt;We empirically evaluated SafeRevert (the ML based method) against the
BASELINE heuristic method. We evaluate: the overall performance of the
different ML models considered, the importance features used, and
compare the BASELINE method to a selected ML model.&lt;/p&gt;
&lt;h2 id="research-questions"&gt;Research Questions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;What is the safety and performance of studied methods in the
context of the developer workflow?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What is the marginal benefit provided by each feature?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Did the chosen method significantly improve performance over the
baseline method while maintaining required safety levels?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="sec:safety"&gt;Measuring Safety&lt;/h2&gt;
&lt;p&gt;As mentioned in section &lt;a href="#intro:auto-revert"
data-reference-type="ref" data-reference="intro:auto-revert"&gt;1.4&lt;/a&gt;, an
incorrectly reverted change causes unacceptably high developer toil.
Safety is the likelihood that a method will produce a false positive
result by incorrectly categorizing a change as being a culprit and
reverting it. This is a referred to as a &lt;em&gt;Bad Revert&lt;/em&gt; while
correctly reverting a change that introduced a bug is a &lt;em&gt;Good
Revert&lt;/em&gt;. The total number of reverts is &lt;em&gt;Bad Reverts&lt;/em&gt; +
&lt;em&gt;Good Reverts&lt;/em&gt;. A change that should have been reverted but
wasn’t is a &lt;em&gt;Missed Good Revert&lt;/em&gt; and a change that was correctly
not reverted is a &lt;em&gt;Avoided Bad Revert&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In terms of classic terminology for evaluating binary
classifiers:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Good Revert&lt;/em&gt; = True Positive (TP)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Bad Revert&lt;/em&gt; = False Positive (FP)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Avoided Bad Revert&lt;/em&gt; = True Negative (TN)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;Missed Good Revert&lt;/em&gt; = False Negative (FN)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The safety properties we are most interested are (a) the total number
of bad reverts, (b) total number of bad reverts per day, and (c) the bad
revert rate. The bad revert rate (BRR) is the percentage of bad reverts
out of the total number of reverts &lt;span class="math inline"&gt;\(=
\frac{FP}{TP + FP}\)&lt;/span&gt;. This is otherwise known as the False
Discovery Rate (FDR). Note, that &lt;span class="math inline"&gt;\(FDR = 1 -
Precision = 1 - \frac{TP}{TP + FP}\)&lt;/span&gt;. Thus, safety can either be
stated in terms of precision (ex. precision must be above 99%) or in
terms of bad revert rate (ex. bad revert rate must be below 1%).&lt;/p&gt;
&lt;p&gt;&lt;em&gt;In this evaluation we will consider a method safe if its bad
revert rate is below 1%, there are fewer than 14 bad reverts in the
final validation set, and there are no more than 5 bad reverts per
day.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Why these numbers?&lt;/em&gt; Our end goal is a production SafeRevert.
Our small team supports a large number of services and users of TAP. We
need to minimize toil for the 2 engineers per week who are “oncall” for
them. The numbers above were selected to be manageable for us in terms
of the overhead required for communicating with our users and
investigating the root cause of bad reverts. While these numbers are
subjective and dependent on our context, they are meaningful to our
team. We expect other teams supporting central CI systems would make
similar choices.&lt;/p&gt;
&lt;h2 id="sec:performance"&gt;Measuring Performance&lt;/h2&gt;
&lt;p&gt;If a method is deemed safe (meets above criteria) then it is an
eligible method to be used to pick changes to revert. To determine
whether one safe reversion method is better than another we look at the
how many &lt;em&gt;Good Reverts&lt;/em&gt; a method is able to achieve out of the
total possible good reverts. This corresponds to the metric known as
recall &lt;span class="math inline"&gt;\(= \frac{TP}{TP + FN}\)&lt;/span&gt;. The
higher a safe method’s recall the better it performs. As with safety, we
prefer methods that are consistent and have low variability in their
reversion recall per day. We then define performance as the number of
breaking changes successfully reverted both in total and per-day.&lt;/p&gt;
&lt;h2 id="sec:dataset"&gt;Evaluation Dataset&lt;/h2&gt;
&lt;p&gt;Our evaluation dataset consists of roughly 3.5 months of data split
between a training, test, and validation set and contains &lt;span
class="math inline"&gt;\(\thicksim\)&lt;/span&gt;25,137 unique changes identified
by the production culprit finder as culprits. Each row has a boolean
indicating whether followup verification confirmed the change was indeed
a culprit. This verification continues to be done in the manner
described in our 2023 paper &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;For training and evaluation we produce a time-based split: TRAIN
consists of the first 2.5 months, TEST the next &lt;span
class="math inline"&gt;\(\sim\)&lt;/span&gt;2 weeks, and VALIDATION the final
&lt;span class="math inline"&gt;\(\sim\)&lt;/span&gt;2 weeks. Time based splits
avoid cross-contaminating our training with diffuse information about
types of breakages that may be based on time-dependent attributes of the
codebase. It is important that the training data is uncontaminated with
any data from the time period where the evaluation occurs. If it is, the
evaluation will not reflect the performance observed in production.&lt;/p&gt;
&lt;p&gt;All comparative model and feature evaluation was performed against
the TEST set in order to determine our optimal ML model configuration,
OPTIMAL. We then evaluate OPTIMAL and BASELINE against the VALIDATION
set.&lt;/p&gt;

&lt;h1 id="sec:results"&gt;Results&lt;/h1&gt;

&lt;p&gt;&lt;span id="table:feature-ablation" label="table:feature-ablation"&gt;
&lt;span id="table:model-comparison" label="table:model-comparison"&gt;
&lt;span id="table:featureMinimization" label="table:featureMinimization"&gt;
&lt;span id="table:validation-evaluation" label="table:validation-evaluation"&gt;
&lt;a href="images/icst-2024/tables2-5.png"&gt;&lt;em&gt;&lt;strong&gt;Tables 2-5&lt;/strong&gt;&lt;/em&gt;
&lt;img alt="Tables 2-5" src="images/icst-2024/tables2-5.png"&gt;&lt;/a&gt;
&lt;/span&gt;
&lt;/span&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span id="fig:model-comparison" label="fig:model-comparison"&gt;
&lt;span id="fig:feature-group-contrib" label="fig:feature-group-contrib"&gt;
&lt;a href="images/icst-2024/fig3-4.png"&gt;&lt;em&gt;&lt;strong&gt;Figures 3-4&lt;/strong&gt;&lt;/em&gt;
&lt;img alt="Figures 3-4" src="images/icst-2024/fig3-4.png"&gt;&lt;/a&gt;
&lt;/span&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;RQ1&lt;/strong&gt;: What is the safety and performance of
studied methods in the context of the developer workflow?&lt;/em&gt; &lt;span
id="result:rq1" label="result:rq1"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/em&gt;: The XGB(ALL) was best overall,
with a recall of 61.2%, and a bad revert rate of .3%.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: This experiment was conducted on the
TEST data set as the VALIDATION set was reserved for RQ3.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Table &lt;a href="#table:model-comparison" data-reference-type="ref"
data-reference="table:model-comparison"&gt;[table:model-comparison]&lt;/a&gt;
summarizes the critical metrics for safety (bad revert rate) and
performance (recall) for the three model types considered: RandomForest
[RF], AdaBoost [ADA], and XGBoost [XGB]. Figure &lt;a
href="#fig:model-comparison" data-reference-type="ref"
data-reference="fig:model-comparison"&gt;[fig:model-comparison]&lt;/a&gt; shows
the Receiver Operator Curves (ROC) for all 3 model types and their
associated area under the curve (AUC) values. The ROC curve better
summarizes model performance over a wider range of target objectives
than the table which is focused on the safest configuration (minimizing
Bad Revert Rate). For instance if a different application had a higher
tolerance for bad reversion/false positives the ROC curves show that you
could achieve a 90% true positive rate with a 20% false positive
rate.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Safety&lt;/strong&gt;: In general, XGB and ADA both outperformed
the RF in terms of safety. Under none of the test configurations did the
RF have a safe configuration. XGB and ADA are safe (under our criteria,
see Section &lt;a href="#sec:safety" data-reference-type="ref"
data-reference="sec:safety"&gt;4.2&lt;/a&gt;) using all the features or the
REAL-TIME subset. The safest configuration was XGB(ALL) which had only 5
bad reverts and a bad revert rate of 0.003. XGB(REAL-TIME) and ADA(ALL)
has the same or smaller number of bad reverts but a worse rate due to
their lower recall.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt;: The highest performing configuration
was XGB(ALL) which had 1980 Good Reverts in the Test set and a recall of
63.2%. The recall rate of XGB(REAL-TIME) was 52.2% indicating that most
of the model performance is gained from the REAL-TIME features, not from
the AHEAD-OF-TIME features which performed much worse while being
unsafe. ADA(ALL) was safe but its recall rate was only 42.2% which lower
than both safe XGB configurations.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;
&lt;p&gt; &lt;em&gt;&lt;strong&gt;RQ2&lt;/strong&gt;: What is the marginal
benefit provided by each feature group&lt;/em&gt;? &lt;span id="result:rq2"
label="result:rq2"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/em&gt;: Historical flakiness data was the
most valuable feature set, boosting model recall by 17%, while change
metadata was the least important.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: This experiment was conducted on the
TEST data set as the VALIDATION set was reserved for RQ3.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;To determine marginal benefit we perform an ablation study to look at
the marginal benefit provided by each feature (as grouped in Table &lt;a
href="#table:features-table" data-reference-type="ref"
data-reference="table:features-table"&gt;1&lt;/a&gt;). The ablation study was
performed using the XGBoost model which was chosen over AdaBoost due to
its higher recall as seen in Table &lt;a href="#table:model-comparison"
data-reference-type="ref"
data-reference="table:model-comparison"&gt;[table:model-comparison]&lt;/a&gt;.
Three marginal benefit experiments were performed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Measure the performance of the model trained against
&lt;strong&gt;only&lt;/strong&gt; the features in a single feature set. We visualize
the results in Figure &lt;a href="#fig:feature-group-contrib"
data-reference-type="ref"
data-reference="fig:feature-group-contrib"&gt;[fig:feature-group-contrib]&lt;/a&gt;
as an ROC curve. Table &lt;a href="#table:feature-ablation"
data-reference-type="ref"
data-reference="table:feature-ablation"&gt;[table:feature-ablation]&lt;/a&gt;
contains the critical safety and performance metrics of Bad Reverts
(safety) and Recall (performance) as well as the AUC which summarizes
overall model predictive performance – generally a model with a higher
AUC will be more performant than one with a lower AUC.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measure the &lt;strong&gt;Positive(+) &lt;em&gt;Lift&lt;/em&gt;&lt;/strong&gt; provided
by adding a single feature group to our BASE feature (the number of
blaming tests). For instance, we would add the features in
CHANGE_CONTENT to create a XGB(CHANGE_CONTENT + BASE) model. The
&lt;strong&gt;+Lift&lt;/strong&gt; for Recall is computed as
Recall[XGB(CHANGE_CONTENT + BASE)] - Recall[XGB(BASE)] and similar for
AUC of the ROC curve. The results of this analysis are shown in Table &lt;a
href="#table:feature-ablation" data-reference-type="ref"
data-reference="table:feature-ablation"&gt;[table:feature-ablation]&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Measure the &lt;strong&gt;Negative(–) &lt;em&gt;Lift&lt;/em&gt;&lt;/strong&gt; provided
by removing a single feature group from out ALL feature set. For
instance we would remove the features in CHANGE_CONTENT to create a
XGB(ALL - CHANGE_CONTENT) model. The &lt;strong&gt;–Lift&lt;/strong&gt; for Recall
is computed as Recall[XGB(ALL)] - Recall[XGB(ALL - CHANGE_CONTENT)] and
similar for AUC of the ROC curve. The results of this analysis are shown
in Table &lt;a href="#table:feature-ablation" data-reference-type="ref"
data-reference="table:feature-ablation"&gt;[table:feature-ablation]&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;As discussed in section &lt;a href="#subsubsec:feature-min"
data-reference-type="ref"
data-reference="subsubsec:feature-min"&gt;3.4.3&lt;/a&gt;, we attempted to
minimize the feature subsets while providing comparable performance to
the full feature sets. Table &lt;a href="#table:featureMinimization"
data-reference-type="ref"
data-reference="table:featureMinimization"&gt;[table:featureMinimization]&lt;/a&gt;
contains a breakdown of the performance for these minimal subsets.&lt;/p&gt;
&lt;p&gt; &lt;em&gt;&lt;strong&gt;RQ3&lt;/strong&gt;:Did the chosen method
improve performance over the baseline method while maintaining required
safety levels?&lt;/em&gt; &lt;span id="result:rq3" label="result:rq3"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Summary&lt;/strong&gt;&lt;/em&gt;: XGB(ALL) improved overall recall
while meeting our safety requirements with a Bad Revert Rate under 1%
and an average of 0.6 Bad Reverts per Day. BASELINE(10) had a recall of
26.3% while XGB(ALL) had a recall of 55.7% – an improvement of &lt;span
class="math inline"&gt;\(\sim 2.1\times\)&lt;/span&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="tcolorbox"&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Note&lt;/strong&gt;&lt;/em&gt;: We used the reserved VALIDATION data
set for this research question.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Table &lt;a href="#table:validation-evaluation"
data-reference-type="ref"
data-reference="table:validation-evaluation"&gt;[table:validation-evaluation]&lt;/a&gt;
shows per day metrics comparing XGB(ALL) against the heuristic
BASELINE(10) method. XGB(ALL) was selected as our “OPTIMAL” model to
compare against the BASELINE method given its performance in the TEST
set as evaluated in RQ1. As a reminder the BASELINE method thresholds
the number of blaming tests to a fixed number. BASELINE(10)’s average
bad reverts per day is 0.86 and its total Bad Revert Rate (BRR) is 1.5%.
XGB(ALL) achieves the overall safety limit with a BRR of 0.5% and has an
average bad reverts per day of 0.6 which meets our safety threshold.&lt;/p&gt;
&lt;p&gt;XGB(ALL)’s bad revert rate outperforms BASELINE(10), with a recall
 2.1 times higher than BASELINE(10). XGB(ALL) made 1,823 total good
reverts in the validation set while BASELINE(10) performed 860 good
reverts. Based on the data in Table &lt;a
href="#table:validation-evaluation" data-reference-type="ref"
data-reference="table:validation-evaluation"&gt;[table:validation-evaluation]&lt;/a&gt;
XGB(ALL) is both safer and more performant than BASELINE(10) on the
validation data set.&lt;/p&gt;
&lt;h2 id="discussion"&gt;Discussion&lt;/h2&gt;
&lt;p&gt;The proposed method, SafeRevert, is generic and can be used with any
culprit finding algorithm. By grouping individual features from
different sources of data into logical feature sets (Table &lt;a
href="#table:features-table" data-reference-type="ref"
data-reference="table:features-table"&gt;1&lt;/a&gt;), performing a detailed
feature ablation study (Fig &lt;a href="#fig:feature-group-contrib"
data-reference-type="ref"
data-reference="fig:feature-group-contrib"&gt;[fig:feature-group-contrib]&lt;/a&gt;),
and running the model on a minimal set of features (Table &lt;a
href="#table:featureMinimization" data-reference-type="ref"
data-reference="table:featureMinimization"&gt;[table:featureMinimization]&lt;/a&gt;),
we hope to provide a template via which teams in other contexts build on
when adopting the approach we outline. In particular, while some
features used may be Google specific, our feature ablation study can be
replicated on different features in other software development
organizations. While we don’t expect a team implementing SafeRevert to
achieve the exact Recall and Bad Revert Rates we report we do expect
this method to out perform the BASELINE method once an appropriate set
of features is identified.&lt;/p&gt;
&lt;h2 id="threats-to-validity"&gt;Threats to Validity&lt;/h2&gt;
&lt;p&gt;Our dataset may misrepresent information available at inference time
in the forthcoming service as it may include information not available
to us at our decision time. This is due to using offline data in the
dataset as the production system based on this paper is currently under
construction. We adjust this threat by evaluating performance restricted
to features available independent of any culprit finding event and
restricting our real-time data to a time bound relative to change
submission time.&lt;/p&gt;
&lt;p&gt;The data presented in this final manuscript differs slightly than the
reviewed manuscript. At the time of review approximated 15% of the
dataset was lacking verification results (collected using the method
described by Henderson &lt;span class="citation"
data-cites="Henderson2023"&gt;(&lt;a href="#ref-Henderson2023"
role="doc-biblioref"&gt;Henderson et al. 2023&lt;/a&gt;)&lt;/span&gt;). This was
disclosed in this section to the reviewers and we made two conservative
assumptions: 1) any culprit change lacking verification results was
considered a false positive and 2) we assumed the BASELINE method was
correct for those changes (inflating the BASELINE methods performance
versus the studied ML methods for SafeRevert). Since the peer review was
completed, a bug in the verification system was identified and fixed.
The bug caused a proportion of incorrect culprit changes to “get stuck”
in a queue waiting for an additional test execution due to a typo in a
comparison (using &lt;code&gt;&amp;gt;&lt;/code&gt; instead of &lt;code&gt;&amp;gt;=&lt;/code&gt;). Once
the bug was fixed, the research team was able to rerun the study with
the additional label data.&lt;/p&gt;
&lt;p&gt;Post-rerun we observed: 1) the BASELINE method performed worse and 2)
the studied methods were robust to the change in labeling data. In the
reviewed manuscript, XGB(ALL) had the following results in RQ3: 13 Total
Bad Reverts, 1817 Good Reverts, 0.7% Bad Revert Rate, and 55.8% Recall;
BASELINE(5) was compared against and had 8 Total Bad Reverts, 1286 Good
Reverts, 0.6% Bad Revert Rate, and 39.4% Recall. Compare against Table
&lt;a href="#table:validation-evaluation" data-reference-type="ref"
data-reference="table:validation-evaluation"&gt;[table:validation-evaluation]&lt;/a&gt;
and Figure &lt;a href="#fig:baseline" data-reference-type="ref"
data-reference="fig:baseline"&gt;[fig:baseline]&lt;/a&gt;. We switched to using
BASELINE(10) for this final manuscript as it is the production method
currently used at Google.&lt;/p&gt;
&lt;h1 id="related-work"&gt;Related Work&lt;/h1&gt;
&lt;p&gt;In this paper, we are presenting what we believe to be a novel
problem to the wider software engineering community: how to safely
choose changes to revert with incomplete but suggestive evidence. This
problem relies on identifying these problematic changes. In our case we
identify the problematic changes to revert via automated culprit finding
&lt;span class="citation"
data-cites="Couder2008 Ziftci2013a Ziftci2017 Saha2017 Najafi2019a Beheshtian2022 keenan2019 An2021 Ocariza2022 Henderson2023"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;; &lt;a
href="#ref-Ziftci2013a" role="doc-biblioref"&gt;Ziftci and Ramavajjala
2013&lt;/a&gt;; &lt;a href="#ref-Ziftci2017" role="doc-biblioref"&gt;Ziftci and
Reardon 2017&lt;/a&gt;; &lt;a href="#ref-Saha2017" role="doc-biblioref"&gt;Saha and
Gligoric 2017&lt;/a&gt;; &lt;a href="#ref-Najafi2019a"
role="doc-biblioref"&gt;Najafi, Rigby, and Shang 2019&lt;/a&gt;; &lt;a
href="#ref-Beheshtian2022" role="doc-biblioref"&gt;Beheshtian, Bavand, and
Rigby 2022&lt;/a&gt;; &lt;a href="#ref-keenan2019" role="doc-biblioref"&gt;Keenan
2019&lt;/a&gt;; &lt;a href="#ref-An2021" role="doc-biblioref"&gt;An and Yoo
2021&lt;/a&gt;; &lt;a href="#ref-Ocariza2022" role="doc-biblioref"&gt;Ocariza
2022&lt;/a&gt;; &lt;a href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et
al. 2023&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Culprit finding’s development has often occurred outside of the
academic literature. The first reference to the process of using binary
search to identify a bug was in Yourdon’s 1975 book on Program Design:
Page 286, Figure 8.3 titled “A binary search for bugs” &lt;span
class="citation" data-cites="Yourdon1975"&gt;(&lt;a href="#ref-Yourdon1975"
role="doc-biblioref"&gt;Yourdon 1975&lt;/a&gt;)&lt;/span&gt;. The process is explained
in detail in the &lt;code&gt;BUG-HUNTING&lt;/code&gt; file in the Linux source tree
in 1996 by Larry McVoy &lt;span class="citation"
data-cites="McVoy1996 Cox2023"&gt;(&lt;a href="#ref-McVoy1996"
role="doc-biblioref"&gt;McVoy 1996&lt;/a&gt;; &lt;a href="#ref-Cox2023"
role="doc-biblioref"&gt;Cox, Ness, and McVoy 2023&lt;/a&gt;)&lt;/span&gt;. By 1997,
Brian Ness had created a binary search based system for use at Cray with
their “Unicos Source Manager” version control system &lt;span
class="citation" data-cites="Ness1997 Cox2023"&gt;(&lt;a href="#ref-Ness1997"
role="doc-biblioref"&gt;Ness and Ngo 1997&lt;/a&gt;; &lt;a href="#ref-Cox2023"
role="doc-biblioref"&gt;Cox, Ness, and McVoy 2023&lt;/a&gt;)&lt;/span&gt;. Previously
in &lt;span class="citation" data-cites="Henderson2023"&gt;(&lt;a
href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
2023&lt;/a&gt;)&lt;/span&gt; we had credited Linus Torvalds for the invention based
on lack of findable antecedent for his work on the
&lt;code&gt;git bisect&lt;/code&gt; command &lt;span class="citation"
data-cites="Couder2008"&gt;(&lt;a href="#ref-Couder2008"
role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;. We regret the error and
recognize the above individuals for their important contributions.&lt;/p&gt;
&lt;p&gt;Other methods for identifying buggy code or breaking changes have
been studied (some widely) in the literature. Fault Localization looks
to identify the buggy code that is causing either operational failure or
test failures &lt;span class="citation"
data-cites="Agarwal2014 Wong2016"&gt;(&lt;a href="#ref-Agarwal2014"
role="doc-biblioref"&gt;Agarwal and Agrawal 2014&lt;/a&gt;; &lt;a
href="#ref-Wong2016" role="doc-biblioref"&gt;Wong et al. 2016&lt;/a&gt;)&lt;/span&gt;.
Methods for fault localization include: delta debugging &lt;span
class="citation" data-cites="Zeller1999"&gt;(&lt;a href="#ref-Zeller1999"
role="doc-biblioref"&gt;Zeller 1999&lt;/a&gt;)&lt;/span&gt;, statistical coverage based
fault localization &lt;span class="citation"
data-cites="Jones2002 Jones2005 Lucia2014 Henderson2018 Henderson2019 Kucuk2021"&gt;(&lt;a
href="#ref-Jones2002" role="doc-biblioref"&gt;J. a. Jones, Harrold, and
Stasko 2002&lt;/a&gt;; &lt;a href="#ref-Jones2005" role="doc-biblioref"&gt;J. A.
Jones and Harrold 2005&lt;/a&gt;; &lt;a href="#ref-Lucia2014"
role="doc-biblioref"&gt;Lucia et al. 2014&lt;/a&gt;; &lt;a href="#ref-Henderson2018"
role="doc-biblioref"&gt;Henderson and Podgurski 2018&lt;/a&gt;; &lt;a
href="#ref-Henderson2019" role="doc-biblioref"&gt;Henderson, Podgurski, and
Kucuk 2019&lt;/a&gt;; &lt;a href="#ref-Kucuk2021" role="doc-biblioref"&gt;Kucuk,
Henderson, and Podgurski 2021&lt;/a&gt;)&lt;/span&gt;, information retrieval (which
may include historical information) &lt;span class="citation"
data-cites="Zhou2012 Youm2015 Ciborowska2022"&gt;(&lt;a href="#ref-Zhou2012"
role="doc-biblioref"&gt;J. Zhou, Zhang, and Lo 2012&lt;/a&gt;; &lt;a
href="#ref-Youm2015" role="doc-biblioref"&gt;Youm et al. 2015&lt;/a&gt;; &lt;a
href="#ref-Ciborowska2022" role="doc-biblioref"&gt;Ciborowska and Damevski
2022&lt;/a&gt;)&lt;/span&gt;, and program slicing &lt;span class="citation"
data-cites="Podgurski1990 Horwitz1992 Ren2004"&gt;(&lt;a
href="#ref-Podgurski1990" role="doc-biblioref"&gt;Podgurski and Clarke
1990&lt;/a&gt;; &lt;a href="#ref-Horwitz1992" role="doc-biblioref"&gt;Horwitz and
Reps 1992&lt;/a&gt;; &lt;a href="#ref-Ren2004" role="doc-biblioref"&gt;Ren et al.
2004&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Bug Prediction attempts to predict if a change, method, class, or
file is likely to contain a bug &lt;span class="citation"
data-cites="Lewis2013 Punitha2013 Osman2017"&gt;(&lt;a href="#ref-Lewis2013"
role="doc-biblioref"&gt;Lewis et al. 2013&lt;/a&gt;; &lt;a href="#ref-Punitha2013"
role="doc-biblioref"&gt;Punitha and Chitra 2013&lt;/a&gt;; &lt;a
href="#ref-Osman2017" role="doc-biblioref"&gt;Osman et al.
2017&lt;/a&gt;)&lt;/span&gt;. This idea has conceptual similarities to the work we
are doing in this paper where we are using similar metrics to predict
whether or not a change which has been implicated by culprit finding is
in fact the change that introduced the bug. Our methods could be
potentially improved by incorporating the additional features used in
the bug prediction work such as the change complexity, code complexity,
and object-oriented complexity metrics.&lt;/p&gt;
&lt;p&gt;Test Case Selection &lt;span class="citation"
data-cites="Leon2003 Engstrom2010 Zhou2010 Mondal2015 Musa2015 pan2022"&gt;(&lt;a
href="#ref-Leon2003" role="doc-biblioref"&gt;Leon and Podgurski 2003&lt;/a&gt;;
&lt;a href="#ref-Engstrom2010" role="doc-biblioref"&gt;Engström, Runeson, and
Skoglund 2010&lt;/a&gt;; &lt;a href="#ref-Zhou2010" role="doc-biblioref"&gt;Z. Q.
Zhou 2010&lt;/a&gt;; &lt;a href="#ref-Mondal2015" role="doc-biblioref"&gt;Mondal,
Hemmati, and Durocher 2015&lt;/a&gt;; &lt;a href="#ref-Musa2015"
role="doc-biblioref"&gt;Musa et al. 2015&lt;/a&gt;; &lt;a href="#ref-pan2022"
role="doc-biblioref"&gt;Pan et al. 2022&lt;/a&gt;)&lt;/span&gt; and Test Case
Prioritization &lt;span class="citation"
data-cites="Singh2012 DeS.CamposJunior2017 DeCastro-Cabrera2020 pan2022"&gt;(&lt;a
href="#ref-Singh2012" role="doc-biblioref"&gt;Singh et al. 2012&lt;/a&gt;; &lt;a
href="#ref-DeS.CamposJunior2017" role="doc-biblioref"&gt;de S. Campos
Junior et al. 2017&lt;/a&gt;; &lt;a href="#ref-DeCastro-Cabrera2020"
role="doc-biblioref"&gt;De Castro-Cabrera, García-Dominguez, and
Medina-Bulo 2020&lt;/a&gt;; &lt;a href="#ref-pan2022" role="doc-biblioref"&gt;Pan et
al. 2022&lt;/a&gt;)&lt;/span&gt; are related problems to the change reversion
problem we study. Instead of predicting whether or not a change caused a
known test failure in Test Case Selection/Prioritization often the
change is used to predict whether a given test will fail before it is
run. There is a large body work in that uses dynamic information from
past test executions (such as code coverage) to inform the selection
process. We believe this hints that such information could be highly
informative for the change reversion problem as well.&lt;/p&gt;
&lt;p&gt;Finally, there are a family of methods for finding bug inducing
commits for the purpose of supporting studies that data mine software
repositories &lt;span class="citation"
data-cites="Sliwerski2005 Rodriguez-Perez2018 Borg2019 Wen2019 An2023"&gt;(&lt;a
href="#ref-Sliwerski2005" role="doc-biblioref"&gt;Śliwerski, Zimmermann,
and Zeller 2005&lt;/a&gt;; &lt;a href="#ref-Rodriguez-Perez2018"
role="doc-biblioref"&gt;Rodríguez-Pérez, Robles, and González-Barahona
2018&lt;/a&gt;; &lt;a href="#ref-Borg2019" role="doc-biblioref"&gt;Borg et al.
2019&lt;/a&gt;; &lt;a href="#ref-Wen2019" role="doc-biblioref"&gt;Wen et al.
2019&lt;/a&gt;; &lt;a href="#ref-An2023" role="doc-biblioref"&gt;An et al.
2023&lt;/a&gt;)&lt;/span&gt;. These methods typically used to conduct a historical
analysis of a repository rather than as an online detection as in
culprit finding.&lt;/p&gt;
&lt;h1 id="sec:conclusion"&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;We presented: SafeRevert a method for improving systems that
automatically revert changes that break tests. SafeRevert was developed
as a way to improve the number bad changes automatically reverted while
maintaining safety (rarely reverting good changes). To evaluate
SafeRevert, we performed an empirical evaluation comparing the
performance of SafeRevert against the baseline method that is currently
utilized in production which utilizes a simple heuristic to determine if
a change is safe to revert: the number of tests which “blame” the
culprit change. When evaluating RQ3 in Section &lt;a href="#sec:results"
data-reference-type="ref" data-reference="sec:results"&gt;5&lt;/a&gt;, it was
observed that the XGB(ALL) configuration of SafeRevert doubled the
number changes reverted while reducing the number of bad reverts
performed (see Table &lt;a href="#table:validation-evaluation"
data-reference-type="ref"
data-reference="table:validation-evaluation"&gt;[table:validation-evaluation]&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;While it is unlikely that a replication study in a different
development environment would reproduce our exact results we do expect
based on the robust difference observed between SafeRevert and BASELINE
that SafeRevert (or similar ML based method) will be able to improve the
number of changes eligible for automatic reversion. We hope that by
introducing this problem to the larger software engineering community
that new and innovative approaches to solving it will be developed.&lt;/p&gt;

&lt;h1 id="sec:References"&gt;References&lt;/h1&gt;
&lt;div id="refs" class="references csl-bib-body hanging-indent"
role="doc-bibliography"&gt;
&lt;ol&gt;
&lt;li&gt;&lt;div id="ref-Agarwal2014" class="csl-entry" role="doc-biblioentry"&gt;
Agarwal, Pragya, and Arun Prakash Agrawal. 2014.
&lt;span&gt;“Fault-Localization &lt;span&gt;Techniques&lt;/span&gt; for &lt;span&gt;Software
Systems&lt;/span&gt;: &lt;span&gt;A Literature Review&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;SIGSOFT
Softw. Eng. Notes&lt;/em&gt; 39 (5): 1–8. &lt;a
href="https://doi.org/10.1145/2659118.2659125"&gt;https://doi.org/10.1145/2659118.2659125&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-An2023" class="csl-entry" role="doc-biblioentry"&gt;
An, Gabin, Jingun Hong, Naryeong Kim, and Shin Yoo. 2023. &lt;span&gt;“Fonte:
&lt;span&gt;Finding Bug Inducing Commits&lt;/span&gt; from
&lt;span&gt;Failures&lt;/span&gt;.”&lt;/span&gt; &lt;span&gt;arXiv&lt;/span&gt;. &lt;a
href="http://arxiv.org/abs/2212.06376"&gt;http://arxiv.org/abs/2212.06376&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-An2021" class="csl-entry" role="doc-biblioentry"&gt;
An, Gabin, and Shin Yoo. 2021. &lt;span&gt;“Reducing the Search Space of Bug
Inducing Commits Using Failure Coverage.”&lt;/span&gt; In &lt;em&gt;Proceedings of
the 29th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on &lt;span&gt;European Software
Engineering Conference&lt;/span&gt; and &lt;span&gt;Symposium&lt;/span&gt; on the
&lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;,
1459–62. &lt;span&gt;Athens Greece&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3468264.3473129"&gt;https://doi.org/10.1145/3468264.3473129&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ananthanarayanan2019" class="csl-entry"
role="doc-biblioentry"&gt;
Ananthanarayanan, Sundaram, Masoud Saeida Ardekani, Denis Haenikel,
Balaji Varadarajan, Simon Soriano, Dhaval Patel, and Ali Reza
Adl-Tabatabai. 2019. &lt;span&gt;“Keeping Master Green at Scale.”&lt;/span&gt;
&lt;em&gt;Proceedings of the 14th EuroSys Conference 2019&lt;/em&gt;. &lt;a
href="https://doi.org/10.1145/3302424.3303970"&gt;https://doi.org/10.1145/3302424.3303970&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Beheshtian2022" class="csl-entry" role="doc-biblioentry"&gt;
Beheshtian, Mohammad Javad, Amir Hossein Bavand, and Peter C. Rigby.
2022. &lt;span&gt;“Software &lt;span&gt;Batch Testing&lt;/span&gt; to &lt;span&gt;Save Build
Test Resources&lt;/span&gt; and to &lt;span&gt;Reduce Feedback Time&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 48 (8): 2784–2801. &lt;a
href="https://doi.org/10.1109/TSE.2021.3070269"&gt;https://doi.org/10.1109/TSE.2021.3070269&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ben-Or2008" class="csl-entry" role="doc-biblioentry"&gt;
Ben-Or, Michael, and Avinatan Hassidim. 2008. &lt;span&gt;“The &lt;span&gt;Bayesian
Learner&lt;/span&gt; Is &lt;span&gt;Optimal&lt;/span&gt; for &lt;span&gt;Noisy Binary
Search&lt;/span&gt; (and &lt;span&gt;Pretty Good&lt;/span&gt; for &lt;span&gt;Quantum&lt;/span&gt; as
&lt;span&gt;Well&lt;/span&gt;).”&lt;/span&gt; In &lt;em&gt;2008 49th &lt;span&gt;Annual IEEE
Symposium&lt;/span&gt; on &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Computer
Science&lt;/span&gt;&lt;/em&gt;, 221–30. &lt;span&gt;Philadelphia, PA, USA&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/FOCS.2008.58"&gt;https://doi.org/10.1109/FOCS.2008.58&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Bland2012" class="csl-entry" role="doc-biblioentry"&gt;
Bland, Mike. 2012. &lt;span&gt;“The &lt;span&gt;Chris&lt;/span&gt;/&lt;span&gt;Jay Continuous
Build&lt;/span&gt;.”&lt;/span&gt; Personal {{Website}}. &lt;em&gt;Mike Bland’s Blog&lt;/em&gt;.
&lt;a href="https://mike-bland.com/2012/06/21/chris-jay-continuous-
                  build.html"&gt;https://mike-bland.com/2012/06/21/chris-jay-continuous-
build.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Borg2019" class="csl-entry" role="doc-biblioentry"&gt;
Borg, Markus, Oscar Svensson, Kristian Berg, and Daniel Hansson. 2019.
&lt;span&gt;“&lt;span&gt;SZZ&lt;/span&gt; Unleashed: An Open Implementation of the
&lt;span&gt;SZZ&lt;/span&gt; Algorithm - Featuring Example Usage in a Study of
Just-in-Time Bug Prediction for the &lt;span&gt;Jenkins&lt;/span&gt;
Project.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 3rd &lt;span&gt;ACM SIGSOFT
International Workshop&lt;/span&gt; on &lt;span&gt;Machine Learning
Techniques&lt;/span&gt; for &lt;span&gt;Software Quality Evaluation&lt;/span&gt; -
&lt;span&gt;MaLTeSQuE&lt;/span&gt; 2019&lt;/em&gt;, 7–12. &lt;span&gt;Tallinn, Estonia&lt;/span&gt;:
&lt;span&gt;ACM Press&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3340482.3342742"&gt;https://doi.org/10.1145/3340482.3342742&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Chen2016a" class="csl-entry" role="doc-biblioentry"&gt;
Chen, Tianqi, and Carlos Guestrin. 2016. &lt;span&gt;“&lt;span&gt;XGBoost&lt;/span&gt;:
&lt;span&gt;A Scalable Tree Boosting System&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings
of the 22nd &lt;span&gt;ACM SIGKDD International Conference&lt;/span&gt; on
&lt;span&gt;Knowledge Discovery&lt;/span&gt; and &lt;span&gt;Data Mining&lt;/span&gt;&lt;/em&gt;,
785–94. &lt;span&gt;San Francisco California USA&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/2939672.2939785"&gt;https://doi.org/10.1145/2939672.2939785&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ciborowska2022" class="csl-entry" role="doc-biblioentry"&gt;
Ciborowska, Agnieszka, and Kostadin Damevski. 2022. &lt;span&gt;“Fast
Changeset-Based Bug Localization with &lt;span&gt;BERT&lt;/span&gt;.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 44th &lt;span&gt;International Conference&lt;/span&gt; on
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 946–57. &lt;span&gt;Pittsburgh
Pennsylvania&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3510003.3510042"&gt;https://doi.org/10.1145/3510003.3510042&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Couder2008" class="csl-entry" role="doc-biblioentry"&gt;
Couder, Christian. 2008. &lt;span&gt;“Fighting Regressions with Git
Bisect.”&lt;/span&gt; &lt;em&gt;The Linux Kernel Archives&lt;/em&gt; 4 (5). &lt;a
href="https://www. kernel. org/pub/software/scm/git/doc s/git-
                  bisect-lk2009.html"&gt;https://www. kernel.
org/pub/software/scm/git/doc s/git- bisect-lk2009.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Cox2023" class="csl-entry" role="doc-biblioentry"&gt;
Cox, Russ, Brian Ness, and Larry McVoy. 2023. &lt;span&gt;“Comp.lang.compilers
"Binary Search Debugging of Compilers".”&lt;/span&gt; &lt;a
href="https://groups.google.com/g/comp.compilers/c/vGh4s3HBQ-s/m/
                  Chvpu7vTAgAJ"&gt;https://groups.google.com/g/comp.compilers/c/vGh4s3HBQ-s/m/
Chvpu7vTAgAJ&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-DeCastro-Cabrera2020" class="csl-entry"
role="doc-biblioentry"&gt;
De Castro-Cabrera, M. Del Carmen, Antonio García-Dominguez, and
Inmaculada Medina-Bulo. 2020. &lt;span&gt;“Trends in Prioritization of Test
Cases: 2017-2019.”&lt;/span&gt; &lt;em&gt;Proceedings of the ACM Symposium on
Applied Computing&lt;/em&gt;, 2005–11. &lt;a
href="https://doi.org/10.1145/3341105.3374036"&gt;https://doi.org/10.1145/3341105.3374036&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-DeS.CamposJunior2017" class="csl-entry"
role="doc-biblioentry"&gt;
de S. Campos Junior, Heleno, Marco Antônio P Araújo, José Maria N David,
Regina Braga, Fernanda Campos, and Victor Ströele. 2017. &lt;span&gt;“Test
&lt;span&gt;Case Prioritization&lt;/span&gt;: &lt;span&gt;A Systematic Review&lt;/span&gt; and
&lt;span&gt;Mapping&lt;/span&gt; of the &lt;span&gt;Literature&lt;/span&gt;.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 31st &lt;span&gt;Brazilian Symposium&lt;/span&gt; on
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 34–43. &lt;span&gt;New York, NY,
USA&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3131151.3131170"&gt;https://doi.org/10.1145/3131151.3131170&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Engstrom2010" class="csl-entry" role="doc-biblioentry"&gt;
Engström, Emelie, Per Runeson, and Mats Skoglund. 2010. &lt;span&gt;“A
Systematic Review on Regression Test Selection Techniques.”&lt;/span&gt;
&lt;em&gt;Information and Software Technology&lt;/em&gt; 52 (1): 14–30. &lt;a
href="https://doi.org/10.1016/j.infsof.2009.07.001"&gt;https://doi.org/10.1016/j.infsof.2009.07.001&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Fowler2006" class="csl-entry" role="doc-biblioentry"&gt;
Fowler, Martin. 2006. &lt;span&gt;“Continuous
&lt;span&gt;Integration&lt;/span&gt;.”&lt;/span&gt; &lt;a
href="https://martinfowler.com/articles/
                  continuousIntegration.html"&gt;https://martinfowler.com/articles/
continuousIntegration.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Gupta2011" class="csl-entry" role="doc-biblioentry"&gt;
Gupta, Pooja, Mark Ivey, and John Penix. 2011. &lt;span&gt;“Testing at the
Speed and Scale of &lt;span&gt;Google&lt;/span&gt;.”&lt;/span&gt; &lt;a
href="http://google-engtools.blogspot.com/2011/06/testing-at-
                  speed-and-scale-of-google.html"&gt;http://google-engtools.blogspot.com/2011/06/testing-at-
speed-and-scale-of-google.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Henderson2023" class="csl-entry" role="doc-biblioentry"&gt;
Henderson, Tim A. D., Bobby Dorward, Eric Nickell, Collin Johnston, and
Avi Kondareddy. 2023. &lt;span&gt;“Flake &lt;span&gt;Aware Culprit
Finding&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2023 &lt;span&gt;IEEE Conference&lt;/span&gt; on
&lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Verification&lt;/span&gt; and
&lt;span&gt;Validation&lt;/span&gt; (&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;. &lt;span&gt;IEEE&lt;/span&gt;. 
&lt;a href="https://hackthology.com/flake-aware-culprit-finding.html"&gt;https://hackthology.com/flake-aware-culprit-finding.html&lt;/a&gt;.
&lt;a href="https://doi.org/10.1109/ICST57152.2023.00041"&gt;https://doi.org/10.1109/ICST57152.2023.00041&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Henderson2018" class="csl-entry" role="doc-biblioentry"&gt;
Henderson, Tim A. D., and Andy Podgurski. 2018. &lt;span&gt;“Behavioral
&lt;span&gt;Fault Localization&lt;/span&gt; by &lt;span&gt;Sampling Suspicious Dynamic
Control Flow Subgraphs&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2018 &lt;span&gt;IEEE&lt;/span&gt;
11th &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Software
Testing&lt;/span&gt;, &lt;span&gt;Verification&lt;/span&gt; and &lt;span&gt;Validation&lt;/span&gt;
(&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;, 93–104. &lt;span&gt;Vasteras&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. 
&lt;a href="https://hackthology.com/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html"&gt;https://hackthology.com/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html&lt;/a&gt;.
&lt;a href="https://doi.org/10.1109/ICST.2018.00019"&gt;https://doi.org/10.1109/ICST.2018.00019&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Henderson2019" class="csl-entry" role="doc-biblioentry"&gt;
Henderson, Tim A. D., Andy Podgurski, and Yigit Kucuk. 2019.
&lt;span&gt;“Evaluating &lt;span&gt;Automatic Fault Localization Using Markov
Processes&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019 19th &lt;span&gt;International Working
Conference&lt;/span&gt; on &lt;span&gt;Source Code Analysis&lt;/span&gt; and
&lt;span&gt;Manipulation&lt;/span&gt; (&lt;span&gt;SCAM&lt;/span&gt;)&lt;/em&gt;, 115–26.
&lt;span&gt;Cleveland, OH, USA&lt;/span&gt;: &lt;span&gt;IEEE&lt;/span&gt;.
&lt;a href="https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html"&gt;https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html&lt;/a&gt;
&lt;a href="https://doi.org/10.1109/SCAM.2019.00021"&gt;https://doi.org/10.1109/SCAM.2019.00021&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Herzig2015a" class="csl-entry" role="doc-biblioentry"&gt;
Herzig, Kim, and Nachiappan Nagappan. 2015. &lt;span&gt;“Empirically
&lt;span&gt;Detecting False Test Alarms Using Association
Rules&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2015 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt;
37th &lt;span&gt;IEEE International Conference&lt;/span&gt; on &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 39–48. &lt;span&gt;Florence, Italy&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE.2015.133"&gt;https://doi.org/10.1109/ICSE.2015.133&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Horwitz1992" class="csl-entry" role="doc-biblioentry"&gt;
Horwitz, S, and T Reps. 1992. &lt;span&gt;“The Use of Program Dependence
Graphs in Software Engineering.”&lt;/span&gt; In &lt;em&gt;International
&lt;span&gt;Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;,
9:349. &lt;span&gt;Springer&lt;/span&gt;. &lt;a
href="http://portal.acm.org/citation.cfm?id=24041&amp;amp;amp;dl="&gt;http://portal.acm.org/citation.cfm?id=24041&amp;amp;amp;dl=&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Jones2002" class="csl-entry" role="doc-biblioentry"&gt;
Jones, J.a., M. J. Harrold, and J. Stasko. 2002. &lt;span&gt;“Visualization of
Test Information to Assist Fault Localization.”&lt;/span&gt; &lt;em&gt;Proceedings
of the 24th International Conference on Software Engineering. ICSE
2002&lt;/em&gt;. &lt;a
href="https://doi.org/10.1145/581339.581397"&gt;https://doi.org/10.1145/581339.581397&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Jones2005" class="csl-entry" role="doc-biblioentry"&gt;
Jones, James A., and Mary Jean Harrold. 2005. &lt;span&gt;“Empirical
&lt;span&gt;Evaluation&lt;/span&gt; of the &lt;span class="nocase"&gt;Tarantula Automatic
Fault-localization Technique&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the
20th &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM International Conference&lt;/span&gt; on
&lt;span&gt;Automated Software Engineering&lt;/span&gt;&lt;/em&gt;, 273–82. &lt;span&gt;New
York, NY, USA&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/1101908.1101949"&gt;https://doi.org/10.1145/1101908.1101949&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-keenan2019" class="csl-entry" role="doc-biblioentry"&gt;
Keenan, James. 2019. &lt;span&gt;“James &lt;span&gt;E&lt;/span&gt;. &lt;span&gt;Keenan&lt;/span&gt; -
"&lt;span&gt;Multisection&lt;/span&gt;: &lt;span&gt;When Bisection Isn&lt;/span&gt;’t
&lt;span&gt;Enough&lt;/span&gt; to &lt;span&gt;Debug&lt;/span&gt; a
&lt;span&gt;Problem&lt;/span&gt;".”&lt;/span&gt; &lt;a
href="https://www.youtube.com/watch?v=05CwdTRt6AM"&gt;https://www.youtube.com/watch?v=05CwdTRt6AM&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Kucuk2021" class="csl-entry" role="doc-biblioentry"&gt;
Kucuk, Yigit, Tim A. D. Henderson, and Andy Podgurski. 2021.
&lt;span&gt;“Improving &lt;span&gt;Fault Localization&lt;/span&gt; by &lt;span&gt;Integrating
Value&lt;/span&gt; and &lt;span&gt;Predicate Based Causal Inference
Techniques&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2021
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 43rd &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;
(&lt;span&gt;ICSE&lt;/span&gt;)&lt;/em&gt;, 649–60. &lt;span&gt;Madrid, ES&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE43902.2021.00066"&gt;https://doi.org/10.1109/ICSE43902.2021.00066&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Leon2003" class="csl-entry" role="doc-biblioentry"&gt;
Leon, D., and A. Podgurski. 2003. &lt;span&gt;“A Comparison of Coverage-Based
and Distribution-Based Techniques for Filtering and Prioritizing Test
Cases.”&lt;/span&gt; In &lt;em&gt;14th &lt;span&gt;International Symposium&lt;/span&gt; on
&lt;span&gt;Software Reliability Engineering&lt;/span&gt;, 2003. &lt;span&gt;ISSRE&lt;/span&gt;
2003.&lt;/em&gt;, 2003-Janua:442–53. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ISSRE.2003.1251065"&gt;https://doi.org/10.1109/ISSRE.2003.1251065&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Leong2019" class="csl-entry" role="doc-biblioentry"&gt;
Leong, Claire, Abhayendra Singh, Mike Papadakis, Yves Le Traon, and John
Micco. 2019. &lt;span&gt;“Assessing &lt;span&gt;Transition-Based Test Selection
Algorithms&lt;/span&gt; at &lt;span&gt;Google&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 101–10. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2019.00019"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00019&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Lewis2013" class="csl-entry" role="doc-biblioentry"&gt;
Lewis, Chris, Zhongpeng Lin, Caitlin Sadowski, and Xiaoyan Zhu. 2013.
&lt;span&gt;“Does Bug Prediction Support Human Developers? Findings from a
Google Case Study.”&lt;/span&gt; In &lt;em&gt;Proceedings of the …&lt;/em&gt;, 372–81. &lt;a
href="http://dl.acm.org/citation.cfm?id=2486838"&gt;http://dl.acm.org/citation.cfm?id=2486838&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Lucia2014" class="csl-entry" role="doc-biblioentry"&gt;
Lucia, David Lo, Lingxiao Jiang, Ferdian Thung, and Aditya Budi. 2014.
&lt;span&gt;“Extended Comprehensive Study of Association Measures for Fault
Localization.”&lt;/span&gt; &lt;em&gt;Journal of Software: Evolution and
Process&lt;/em&gt; 26 (2): 172–219. &lt;a
href="https://doi.org/10.1002/smr.1616"&gt;https://doi.org/10.1002/smr.1616&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Machalica2019" class="csl-entry" role="doc-biblioentry"&gt;
Machalica, Mateusz, Alex Samylkin, Meredith Porth, and Satish Chandra.
2019. &lt;span&gt;“Predictive &lt;span&gt;Test Selection&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 91–100. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2019.00018"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00018&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-McVoy1996" class="csl-entry" role="doc-biblioentry"&gt;
McVoy, Larry. 1996. &lt;span&gt;“&lt;span&gt;BUG-HUNTING&lt;/span&gt;.”&lt;/span&gt;
&lt;span&gt;linux/1.3.73&lt;/span&gt;. &lt;a
href="https://elixir.bootlin.com/linux/1.3.73/source/
                  Documentation/BUG-HUNTING"&gt;https://elixir.bootlin.com/linux/1.3.73/source/
Documentation/BUG-HUNTING&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Memon2017" class="csl-entry" role="doc-biblioentry"&gt;
Memon, Atif, Zebao Gao, Bao Nguyen, Sanjeev Dhanda, Eric Nickell, Rob
Siemborski, and John Micco. 2017. &lt;span&gt;“Taming &lt;span
class="nocase"&gt;Google-scale&lt;/span&gt; Continuous Testing.”&lt;/span&gt; In
&lt;em&gt;2017 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 39th &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice Track&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 233–42. &lt;span&gt;Piscataway, NJ, USA&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2017.16"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.16&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Micco2012" class="csl-entry" role="doc-biblioentry"&gt;
Micco, John. 2012. &lt;span&gt;“Tools for &lt;span&gt;Continuous Integration&lt;/span&gt;
at &lt;span&gt;Google Scale&lt;/span&gt;.”&lt;/span&gt; Tech {{Talk}}. &lt;span&gt;Google
NYC&lt;/span&gt;. &lt;a
href="https://youtu.be/KH2_sB1A6lA"&gt;https://youtu.be/KH2_sB1A6lA&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Micco2013" class="csl-entry" role="doc-biblioentry"&gt;
———. 2013. &lt;span&gt;“Continuous &lt;span&gt;Integration&lt;/span&gt; at &lt;span&gt;Google
Scale&lt;/span&gt;.”&lt;/span&gt; Lecture. &lt;span&gt;EclipseCon 2013&lt;/span&gt;. &lt;a
href="https://web.archive.org/web/20140705215747/https://
                  www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-
                  03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf"&gt;https://web.archive.org/web/20140705215747/https://
www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-
03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Mondal2015" class="csl-entry" role="doc-biblioentry"&gt;
Mondal, Debajyoti, Hadi Hemmati, and Stephane Durocher. 2015.
&lt;span&gt;“Exploring Test Suite Diversification and Code Coverage in
Multi-Objective Test Case Selection.”&lt;/span&gt; &lt;em&gt;2015 IEEE 8th
International Conference on Software Testing, Verification and
Validation, ICST 2015 - Proceedings&lt;/em&gt;, 1–10. &lt;a
href="https://doi.org/10.1109/ICST.2015.7102588"&gt;https://doi.org/10.1109/ICST.2015.7102588&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Musa2015" class="csl-entry" role="doc-biblioentry"&gt;
Musa, Samaila, Abu Bakar Md Sultan, Abdul Azim Bin Abd-Ghani, and Salmi
Baharom. 2015. &lt;span&gt;“Regression &lt;span&gt;Test Cases&lt;/span&gt; Selection for
&lt;span&gt;Object-Oriented Programs&lt;/span&gt; Based on &lt;span&gt;Affected
Statements&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;International Journal of Software
Engineering and Its Applications&lt;/em&gt; 9 (10): 91–108. &lt;a
href="https://doi.org/10.14257/ijseia.2015.9.10.10"&gt;https://doi.org/10.14257/ijseia.2015.9.10.10&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Najafi2019a" class="csl-entry" role="doc-biblioentry"&gt;
Najafi, Armin, Peter C. Rigby, and Weiyi Shang. 2019. &lt;span&gt;“Bisecting
Commits and Modeling Commit Risk During Testing.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on
&lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
&lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 279–89. &lt;span&gt;New York, NY, USA&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3338906.3338944"&gt;https://doi.org/10.1145/3338906.3338944&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Najafi2019" class="csl-entry" role="doc-biblioentry"&gt;
Najafi, Armin, Weiyi Shang, and Peter C. Rigby. 2019. &lt;span&gt;“Improving
&lt;span&gt;Test Effectiveness Using Test Executions History&lt;/span&gt;: &lt;span&gt;An
Industrial Experience Report&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 213–22. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2019.00031"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00031&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ness1997" class="csl-entry" role="doc-biblioentry"&gt;
Ness, B., and V. Ngo. 1997. &lt;span&gt;“Regression Containment Through Source
Change Isolation.”&lt;/span&gt; In &lt;em&gt;Proceedings &lt;span&gt;Twenty-First Annual
International Computer Software&lt;/span&gt; and &lt;span&gt;Applications
Conference&lt;/span&gt; (&lt;span&gt;COMPSAC&lt;/span&gt;’97)&lt;/em&gt;, 616–21.
&lt;span&gt;Washington, DC, USA&lt;/span&gt;: &lt;span&gt;IEEE Comput. Soc&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/CMPSAC.1997.625082"&gt;https://doi.org/10.1109/CMPSAC.1997.625082&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ocariza2022" class="csl-entry" role="doc-biblioentry"&gt;
Ocariza, Frolin S. 2022. &lt;span&gt;“On the &lt;span&gt;Effectiveness&lt;/span&gt; of
&lt;span&gt;Bisection&lt;/span&gt; in &lt;span&gt;Performance Regression
Localization&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;Empirical Software Engineering&lt;/em&gt; 27
(4): 95. &lt;a
href="https://doi.org/10.1007/s10664-022-10152-3"&gt;https://doi.org/10.1007/s10664-022-10152-3&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Osman2017" class="csl-entry" role="doc-biblioentry"&gt;
Osman, Haidar, Mohammad Ghafari, Oscar Nierstrasz, and Mircea Lungu.
2017. &lt;span&gt;“An &lt;span&gt;Extensive Analysis&lt;/span&gt; of &lt;span&gt;Efficient Bug
Prediction Configurations&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 13th
&lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Predictive Models&lt;/span&gt;
and &lt;span&gt;Data Analytics&lt;/span&gt; in &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 107–16. &lt;span&gt;Toronto Canada&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3127005.3127017"&gt;https://doi.org/10.1145/3127005.3127017&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-pan2022" class="csl-entry" role="doc-biblioentry"&gt;
Pan, Rongqi, Mojtaba Bagherzadeh, Taher A. Ghaleb, and Lionel Briand.
2022. &lt;span&gt;“Test Case Selection and Prioritization Using Machine
Learning: A Systematic Literature Review.”&lt;/span&gt; &lt;em&gt;Empirical Software
Engineering&lt;/em&gt; 27 (2): 29. &lt;a
href="https://doi.org/10.1007/s10664-021-10066-6"&gt;https://doi.org/10.1007/s10664-021-10066-6&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-parry2022" class="csl-entry" role="doc-biblioentry"&gt;
Parry, Owain, Gregory M. Kapfhammer, Michael Hilton, and Phil McMinn.
2022. &lt;span&gt;“A &lt;span&gt;Survey&lt;/span&gt; of &lt;span&gt;Flaky Tests&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;ACM Transactions on Software Engineering and Methodology&lt;/em&gt; 31
(1): 1–74. &lt;a
href="https://doi.org/10.1145/3476105"&gt;https://doi.org/10.1145/3476105&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-scikit-learn" class="csl-entry" role="doc-biblioentry"&gt;
Pedregosa, F., G. Varoquaux, A. Gramfort, V. Michel, B. Thirion, O.
Grisel, M. Blondel, et al. 2011. &lt;span&gt;“Scikit-Learn:
&lt;span&gt;Machine&lt;/span&gt; Learning in &lt;span&gt;Python&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;Journal of Machine Learning Research&lt;/em&gt; 12: 2825–30.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Pelc2002" class="csl-entry" role="doc-biblioentry"&gt;
Pelc, Andrzej. 2002. &lt;span&gt;“Searching Games with Errorsfifty Years of
Coping with Liars.”&lt;/span&gt; &lt;em&gt;Theoretical Computer Science&lt;/em&gt; 270
(1-2): 71–109. &lt;a
href="https://doi.org/10.1016/S0304-3975(01)00303-6"&gt;https://doi.org/10.1016/S0304-3975(01)00303-6&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Podgurski1990" class="csl-entry" role="doc-biblioentry"&gt;
Podgurski, A, and L A Clarke. 1990. &lt;span&gt;“A &lt;span&gt;Formal Model&lt;/span&gt;
of &lt;span&gt;Program Dependences&lt;/span&gt; and &lt;span&gt;Its Implications&lt;/span&gt;
for &lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Debugging&lt;/span&gt;, and
&lt;span&gt;Maintenance&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;IEEE Transactions of Software
Engineering&lt;/em&gt; 16 (9): 965–79. &lt;a
href="https://doi.org/10.1109/32.58784"&gt;https://doi.org/10.1109/32.58784&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Potvin2016" class="csl-entry" role="doc-biblioentry"&gt;
Potvin, Rachel, and Josh Levenberg. 2016. &lt;span&gt;“Why Google Stores
Billions of Lines of Code in a Single Repository.”&lt;/span&gt;
&lt;em&gt;Communications of the ACM&lt;/em&gt; 59 (7): 78–87. &lt;a
href="https://doi.org/10.1145/2854146"&gt;https://doi.org/10.1145/2854146&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Punitha2013" class="csl-entry" role="doc-biblioentry"&gt;
Punitha, K., and S. Chitra. 2013. &lt;span&gt;“Software Defect Prediction
Using Software Metrics - &lt;span&gt;A&lt;/span&gt; Survey.”&lt;/span&gt; In &lt;em&gt;2013
&lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Information
Communication&lt;/span&gt; and &lt;span&gt;Embedded Systems&lt;/span&gt;
(&lt;span&gt;ICICES&lt;/span&gt;)&lt;/em&gt;, 555–58. &lt;span&gt;Chennai&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICICES.2013.6508369"&gt;https://doi.org/10.1109/ICICES.2013.6508369&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ren2004" class="csl-entry" role="doc-biblioentry"&gt;
Ren, Xiaoxia, Fenil Shah, Frank Tip, Barbara G. Ryder, and Ophelia
Chesley. 2004. &lt;span&gt;“Chianti: A Tool for Change Impact Analysis of Java
Programs.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 19th Annual &lt;span&gt;ACM
SIGPLAN&lt;/span&gt; Conference on &lt;span class="nocase"&gt;Object-oriented&lt;/span&gt;
Programming, Systems, Languages, and Applications&lt;/em&gt;, 432–48.
&lt;span&gt;Vancouver BC Canada&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/1028976.1029012"&gt;https://doi.org/10.1145/1028976.1029012&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Rivest1978" class="csl-entry" role="doc-biblioentry"&gt;
Rivest, R. L., A. R. Meyer, and D. J. Kleitman. 1978. &lt;span&gt;“Coping with
Errors in Binary Search Procedures (&lt;span&gt;Preliminary
Report&lt;/span&gt;).”&lt;/span&gt; In &lt;em&gt;Proceedings of the Tenth Annual
&lt;span&gt;ACM&lt;/span&gt; Symposium on &lt;span&gt;Theory&lt;/span&gt; of Computing -
&lt;span&gt;STOC&lt;/span&gt; ’78&lt;/em&gt;, 227–32. &lt;span&gt;San Diego, California, United
States&lt;/span&gt;: &lt;span&gt;ACM Press&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/800133.804351"&gt;https://doi.org/10.1145/800133.804351&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Rodriguez-Perez2018" class="csl-entry"
role="doc-biblioentry"&gt;
Rodríguez-Pérez, Gema, Gregorio Robles, and Jesús M. González-Barahona.
2018. &lt;span&gt;“Reproducibility and Credibility in Empirical Software
Engineering: &lt;span&gt;A&lt;/span&gt; Case Study Based on a Systematic Literature
Review of the Use of the &lt;span&gt;SZZ&lt;/span&gt; Algorithm.”&lt;/span&gt;
&lt;em&gt;Information and Software Technology&lt;/em&gt; 99 (July): 164–76. &lt;a
href="https://doi.org/10.1016/j.infsof.2018.03.009"&gt;https://doi.org/10.1016/j.infsof.2018.03.009&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Saha2017" class="csl-entry" role="doc-biblioentry"&gt;
Saha, Ripon, and Milos Gligoric. 2017. &lt;span&gt;“Selective &lt;span&gt;Bisection
Debugging&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Fundamental &lt;span&gt;Approaches&lt;/span&gt; to
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, edited by Marieke Huisman and
Julia Rubin, 10202:60–77. &lt;span&gt;Berlin, Heidelberg&lt;/span&gt;:
&lt;span&gt;Springer Berlin Heidelberg&lt;/span&gt;. &lt;a
href="https://doi.org/10.1007/978-3-662-54494-5_4"&gt;https://doi.org/10.1007/978-3-662-54494-5_4&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Singh2012" class="csl-entry" role="doc-biblioentry"&gt;
Singh, Yogesh, Arvinder Kaur, Bharti Suri, and Shweta Singhal. 2012.
&lt;span&gt;“Systematic Literature Review on Regression Test Prioritization
Techniques.”&lt;/span&gt; &lt;em&gt;Informatica (Slovenia)&lt;/em&gt; 36 (4): 379–408. &lt;a
href="https://doi.org/10.31449/inf.v36i4.420"&gt;https://doi.org/10.31449/inf.v36i4.420&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Sliwerski2005" class="csl-entry" role="doc-biblioentry"&gt;
Śliwerski, Jacek, Thomas Zimmermann, and Andreas Zeller. 2005.
&lt;span&gt;“When Do Changes Induce Fixes?”&lt;/span&gt; &lt;em&gt;ACM SIGSOFT Software
Engineering Notes&lt;/em&gt; 30 (4): 1. &lt;a
href="https://doi.org/10.1145/1082983.1083147"&gt;https://doi.org/10.1145/1082983.1083147&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wang2020" class="csl-entry" role="doc-biblioentry"&gt;
Wang, Kaiyuan, Greg Tener, Vijay Gullapalli, Xin Huang, Ahmed Gad, and
Daniel Rall. 2020. &lt;span&gt;“Scalable Build Service System with Smart
Scheduling Service.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 29th &lt;span&gt;ACM
SIGSOFT International Symposium&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;
and &lt;span&gt;Analysis&lt;/span&gt;&lt;/em&gt;, 452–62. &lt;span&gt;Virtual Event USA&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3395363.3397371"&gt;https://doi.org/10.1145/3395363.3397371&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wen2019" class="csl-entry" role="doc-biblioentry"&gt;
Wen, Ming, Rongxin Wu, Yepang Liu, Yongqiang Tian, Xuan Xie, Shing-Chi
Cheung, and Zhendong Su. 2019. &lt;span&gt;“Exploring and Exploiting the
Correlations Between Bug-Inducing and Bug-Fixing Commits.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on
&lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
&lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 326–37. &lt;span&gt;Tallinn Estonia&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3338906.3338962"&gt;https://doi.org/10.1145/3338906.3338962&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wong2016" class="csl-entry" role="doc-biblioentry"&gt;
Wong, W. Eric, Ruizhi Gao, Yihao Li, Rui Abreu, and Franz Wotawa. 2016.
&lt;span&gt;“A &lt;span&gt;Survey&lt;/span&gt; on &lt;span&gt;Software Fault
Localization&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software
Engineering&lt;/em&gt; 42 (8): 707–40. &lt;a
href="https://doi.org/10.1109/TSE.2016.2521368"&gt;https://doi.org/10.1109/TSE.2016.2521368&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Youm2015" class="csl-entry" role="doc-biblioentry"&gt;
Youm, Klaus Changsun, June Ahn, Jeongho Kim, and Eunseok Lee. 2015.
&lt;span&gt;“Bug &lt;span&gt;Localization Based&lt;/span&gt; on &lt;span&gt;Code Change
Histories&lt;/span&gt; and &lt;span&gt;Bug Reports&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2015
&lt;span&gt;Asia-Pacific Software Engineering Conference&lt;/span&gt;
(&lt;span&gt;APSEC&lt;/span&gt;)&lt;/em&gt;, 190–97. &lt;span&gt;New Delhi&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/APSEC.2015.23"&gt;https://doi.org/10.1109/APSEC.2015.23&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Yourdon1975" class="csl-entry" role="doc-biblioentry"&gt;
Yourdon, E. 1975. &lt;em&gt;Techniques of &lt;span&gt;Program Design&lt;/span&gt;&lt;/em&gt;.
&lt;span&gt;New Jersey&lt;/span&gt;: &lt;span&gt;Prentice-Hall&lt;/span&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Zeller1999" class="csl-entry" role="doc-biblioentry"&gt;
Zeller, Andreas. 1999. &lt;span&gt;“Yesterday, &lt;span&gt;My Program Worked&lt;/span&gt;.
&lt;span&gt;Today&lt;/span&gt;, &lt;span&gt;It Does Not&lt;/span&gt;. &lt;span&gt;Why&lt;/span&gt;?”&lt;/span&gt;
&lt;em&gt;SIGSOFT Softw. Eng. Notes&lt;/em&gt; 24 (6): 253–67. &lt;a
href="https://doi.org/10.1145/318774.318946"&gt;https://doi.org/10.1145/318774.318946&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Zhou2012" class="csl-entry" role="doc-biblioentry"&gt;
Zhou, Jian, Hongyu Zhang, and David Lo. 2012. &lt;span&gt;“Where Should the
Bugs Be Fixed? &lt;span&gt;More&lt;/span&gt; Accurate Information Retrieval-Based
Bug Localization Based on Bug Reports.”&lt;/span&gt; &lt;em&gt;Proceedings -
International Conference on Software Engineering&lt;/em&gt;, 14–24. &lt;a
href="https://doi.org/10.1109/ICSE.2012.6227210"&gt;https://doi.org/10.1109/ICSE.2012.6227210&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Zhou2010" class="csl-entry" role="doc-biblioentry"&gt;
Zhou, Zhi Quan. 2010. &lt;span&gt;“Using Coverage Information to Guide Test
Case Selection in &lt;span&gt;Adaptive Random Testing&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;Proceedings - International Computer Software and Applications
Conference&lt;/em&gt;, 208–13. &lt;a
href="https://doi.org/10.1109/COMPSACW.2010.43"&gt;https://doi.org/10.1109/COMPSACW.2010.43&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ziftci2013a" class="csl-entry" role="doc-biblioentry"&gt;
Ziftci, Celal, and Vivek Ramavajjala. 2013. &lt;span&gt;“Finding
&lt;span&gt;Culprits Automatically&lt;/span&gt; in &lt;span&gt;Failing Builds&lt;/span&gt; -
i.e. &lt;span&gt;Who Broke&lt;/span&gt; the &lt;span&gt;Build&lt;/span&gt;?”&lt;/span&gt; &lt;a
href="https://www.youtube.com/watch?v=SZLuBYlq3OM"&gt;https://www.youtube.com/watch?v=SZLuBYlq3OM&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ziftci2017" class="csl-entry" role="doc-biblioentry"&gt;
Ziftci, Celal, and Jim Reardon. 2017. &lt;span&gt;“Who Broke the Build?
&lt;span&gt;Automatically&lt;/span&gt; Identifying Changes That Induce Test Failures
in Continuous Integration at Google Scale.”&lt;/span&gt; &lt;em&gt;Proceedings -
2017 IEEE/ACM 39th International Conference on Software Engineering:
Software Engineering in Practice Track, ICSE-SEIP 2017&lt;/em&gt;, 113–22. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2017.13"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.13&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;/div&gt;
&lt;section class="footnotes footnotes-end-of-document"
role="doc-endnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;Both the &lt;em&gt;per-test&lt;/em&gt; error rate
and the &lt;em&gt;per-change&lt;/em&gt; error rates quoted above are drawn from the
same 28 day window. The Postsubmit result which triggers culprit finding
may itself have been a flake, so there were spurious suspect ranges in
the same period. These rates may differ slightly from the numbers
reported in &lt;span class="citation" data-cites="Henderson2023"&gt;(&lt;a
href="#ref-Henderson2023" role="doc-biblioref"&gt;Henderson et al.
2023&lt;/a&gt;)&lt;/span&gt; as they reflect our most recent data as of
2023-11-12.&lt;a href="#fnref1" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2" role="doc-endnote"&gt;&lt;p&gt;There are some legacy tests which are
allowed to use the network but there is an on-going effort to clean up
their usage.&lt;a href="#fnref2" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3" role="doc-endnote"&gt;&lt;p&gt;Previously, we referred to these
cycles as “Milestones” in most of the previous literature but we are
gradually changing our internal nomenclature as we evolve TAP
Postsubmit’s testing model.&lt;a href="#fnref3" class="footnote-back"
role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn4" role="doc-endnote"&gt;&lt;p&gt;https://scikit-learn.org/&lt;a
href="#fnref4" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn5" role="doc-endnote"&gt;&lt;p&gt;&lt;a
href="https://xgboost.readthedocs.io/en/stable/index.html"
class="uri"&gt;https://xgboost.readthedocs.io/en/stable/index.html&lt;/a&gt;&lt;a
href="#fnref5" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content><category term="Paper"/></entry><entry><title>Flake Aware Culprit Finding</title><link href="https://hackthology.com/flake-aware-culprit-finding.html" rel="alternate"/><published>2023-04-17T00:00:00-04:00</published><updated>2023-04-17T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, Bobby Dorward, Eric Nickell, Collin Johnston, Avi Kondareddy</name></author><id>tag:hackthology.com,2023-04-17:/flake-aware-culprit-finding.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Bobby Dorward, Eric Nickell, Collin Johnston, and Avi Kondareddy.
&lt;em&gt;Flake Aware Culprit Finding&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2023/icst-2023-industry/46/Flake-Aware-Culprit-Finding"&gt;ICST Industry Track 2023&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.dx.org/10.1109/ICST57152.2023.00041"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2023.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/flake-aware-culprit-finding.html"&gt;WEB&lt;/a&gt;.
&lt;a href="https://research.google/pubs/pub52048/"&gt;Google Research Preprint&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2023.pdf"&gt;pdf version …&lt;/a&gt;&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Bobby Dorward, Eric Nickell, Collin Johnston, and Avi Kondareddy.
&lt;em&gt;Flake Aware Culprit Finding&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icst-2023/icst-2023-industry/46/Flake-Aware-Culprit-Finding"&gt;ICST Industry Track 2023&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.dx.org/10.1109/ICST57152.2023.00041"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2023.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/flake-aware-culprit-finding.html"&gt;WEB&lt;/a&gt;.
&lt;a href="https://research.google/pubs/pub52048/"&gt;Google Research Preprint&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/icst-2023.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;When a change introduces a bug into a large software repository, there is
often a delay between when the change is committed and when bug is detected.
This is true even when the bug causes an existing test to fail! These delays
are caused by resource constraints which prevent the organization from running
all of the tests on every change. Due to the delay, a Continuous Integration
system needs to locate buggy commits. Locating them is complicated by flaky
tests that pass and fail non-deterministically. The flaky tests introduce
noise into the CI system requiring costly reruns to determine if a failure was
caused by a bad code change or caused by non-deterministic test behavior. This
paper presents an algorithm, &lt;em&gt;Flake Aware Culprit Finding&lt;/em&gt;, that locates
buggy commits more accurately than a traditional bisection search. The
algorithm is based on Bayesian inference and noisy binary search, utilizing
prior information about which changes are most likely to contain the bug. A
large scale empirical study was conducted at Google on 13,000+ test breakages.
The study evaluates the accuracy and cost of the new algorithm versus a
traditional deflaked bisection search.&lt;/p&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h1 id="sec:introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Fast, collaborative, large scale development is enabled by the use of
Continuous Integration in a &lt;em&gt;mono-repository&lt;/em&gt; (monorepo)
environment where all of the source code is stored in a single shared
repository &lt;span class="citation" data-cites="Potvin2016"&gt;(&lt;a
href="#ref-Potvin2016" role="doc-biblioref"&gt;Potvin and Levenberg
2016&lt;/a&gt;)&lt;/span&gt;. In a monorepo, all developers share a single source of
truth for the state of the code and most builds are made from “head”
(the most recent commit to the repository) using the source code for all
libraries and dependencies rather than versioned pre-compiled archives.
This enables (among other things) unified versioning, atomic changes,
large scale refactorings, code re-use, cross team collaboration, and
flexible code ownership boundaries.&lt;/p&gt;
&lt;p&gt;Very large scale monorepos (such as those at Google &lt;span
class="citation" data-cites="Potvin2016 Memon2017"&gt;(&lt;a
href="#ref-Potvin2016" role="doc-biblioref"&gt;Potvin and Levenberg
2016&lt;/a&gt;; &lt;a href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al.
2017&lt;/a&gt;)&lt;/span&gt;, Microsoft &lt;span class="citation"
data-cites="Herzig2015a"&gt;(&lt;a href="#ref-Herzig2015a"
role="doc-biblioref"&gt;Herzig and Nagappan 2015&lt;/a&gt;)&lt;/span&gt;, and Facebook
&lt;span class="citation" data-cites="Machalica2019"&gt;(&lt;a
href="#ref-Machalica2019" role="doc-biblioref"&gt;Machalica et al.
2019&lt;/a&gt;)&lt;/span&gt;) require advanced systems for ensuring changes
submitted to the repository are properly tested and validated.
&lt;em&gt;Continuous Integration&lt;/em&gt; (CI) &lt;span class="citation"
data-cites="Fowler2006"&gt;(&lt;a href="#ref-Fowler2006"
role="doc-biblioref"&gt;Fowler 2006&lt;/a&gt;)&lt;/span&gt; is a system and practice of
automatically integrating changes into the code repository that serves
as the source of truth for the organization. In modern environments,
integration involves not only performing the textual merge required to
add the change but also verification tasks such as ensuring the software
compiles and the automated tests pass both on the new change before it
is integrated &lt;em&gt;and after&lt;/em&gt; it has been incorporated into the main
development branch.&lt;/p&gt;

&lt;p&gt;&lt;span id="fig:ci-timeline" label="fig:ci-timeline"&gt;
&lt;a href="images/icst-2023/fig1.png"&gt;&lt;img alt="Figure 1" src="images/icst-2023/fig1.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Due to resource constraints, tests are only run at specific versions
(called &lt;em&gt;milestones&lt;/em&gt; at Google) and many tests may be skipped
because they were not affected by the intervening changes (as determined
by static build dependencies) &lt;span class="citation"
data-cites="Gupta2011"&gt;(&lt;a href="#ref-Gupta2011"
role="doc-biblioref"&gt;Gupta, Ivey, and Penix 2011&lt;/a&gt;)&lt;/span&gt;. This
process is illustrated in Figure &lt;a href="#fig:ci-timeline"
data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt;. A test is
considered passing at a version &lt;span class="math inline"&gt;\(b\)&lt;/span&gt;
if and only if it has a passing result at the most recent preceding
affecting version. Formally, if there exists a version &lt;span
class="math inline"&gt;\(a\)&lt;/span&gt; where the test is passing and &lt;span
class="math inline"&gt;\(a \le b\)&lt;/span&gt; and there does not exist an
intervening version &lt;span class="math inline"&gt;\(c\)&lt;/span&gt;, &lt;span
class="math inline"&gt;\(a &amp;lt; c \le b\)&lt;/span&gt;, which affects the test
then the test is passing at version &lt;span
class="math inline"&gt;\(a\)&lt;/span&gt;. A project’s status is considered
passing at a version &lt;span class="math inline"&gt;\(b\)&lt;/span&gt; if all tests
are passing (using the above definition) at version &lt;span
class="math inline"&gt;\(b\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;If a test &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; is failing
(consistently) at a milestone version &lt;span
class="math inline"&gt;\(m\)&lt;/span&gt;, it may not necessarily mean that
version &lt;span class="math inline"&gt;\(m\)&lt;/span&gt; introduced a change which
broke test &lt;span class="math inline"&gt;\(t\)&lt;/span&gt;. As shown in Figure &lt;a
href="#fig:ci-timeline" data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt; one or more
changes between &lt;span class="math inline"&gt;\(m\)&lt;/span&gt; and the previous
milestone at which test &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; was run
may have introduced a breaking change. Figuring out which version
introduced the &lt;em&gt;breakage&lt;/em&gt; is called &lt;em&gt;culprit finding&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Many companies now employ automated culprit finding systems. These
systems typically implement a (possibly n-way) “bisect search” similar
to the one built into the Git version control system &lt;span
class="citation" data-cites="Couder2008"&gt;(&lt;a href="#ref-Couder2008"
role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;. Git’s bisect command runs
a binary search on the versions between the first known breaking version
and the last known passing version to identify the version which broke
the test.&lt;/p&gt;
&lt;p&gt;In the Google environment, there are two problems with a traditional
bisection algorithm &lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;: (1)
it does not account for flaky (non-deterministic) tests, and (2) when
using &lt;span class="math inline"&gt;\(k\)&lt;/span&gt;-reruns to deflake the
search accuracy plateaus while build cost continues to increase
linearly. &lt;strong&gt;This paper proposes&lt;/strong&gt; a new method for culprit
finding which is both robust to non-deterministic (flaky) test behavior
and can identify the culprit with only logarithmic builds in the best
case by using prior information to accelerate the search.&lt;/p&gt;
&lt;h2 id="contributions"&gt;Contributions&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A Flake Aware Culprit Finding (FACF) algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A mathematical model for culprit finding adjusting for
non-deterministic test behavior.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A large scale empirical study of FACF on Google’s mono repository
comparing its performance against the traditional bisect
algorithm.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The study also evaluates the effectiveness: (a) optimizations for
FACF, and (b) adding deflaking runs to Bisect.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h1 id="background"&gt;Background&lt;/h1&gt;
&lt;p&gt;At Google, the Test Automation Platform (TAP) runs most tests that
can run on a single machine (and do not use the network except for the
loopback interface)&lt;a href="#fn1" class="footnote-ref" id="fnref1"
role="doc-noteref"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; and can run in under 15 minutes.&lt;a
href="#fn2" class="footnote-ref" id="fnref2"
role="doc-noteref"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; Figure &lt;a href="#fig:ci-timeline"
data-reference-type="ref"
data-reference="fig:ci-timeline"&gt;[fig:ci-timeline]&lt;/a&gt; illustrates at a
high level of how TAP works. First, (not illustrated) tests are grouped
into logical projects by the teams that own them. Then, (for accounting
and quota allocation purposes) those projects are grouped into very high
level groupings called Quota Buckets. Each Quota Bucket is scheduled
independently when build resources are available. This means that TAP
does not run every test at every version. Instead it only runs tests
periodically at select versions called “Milestones” &lt;span
class="citation" data-cites="Memon2017 Micco2013 Leong2019"&gt;(&lt;a
href="#ref-Memon2017" role="doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;; &lt;a
href="#ref-Micco2013" role="doc-biblioref"&gt;Micco 2013&lt;/a&gt;; &lt;a
href="#ref-Leong2019" role="doc-biblioref"&gt;Leong et al.
2019&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;When scheduling a Milestone, all the tests that are built and run
with the same command line flags to the build system&lt;a href="#fn3"
class="footnote-ref" id="fnref3" role="doc-noteref"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt; are
grouped into a set. That set is filtered to remove tests that haven’t
been affected by a change to themselves or a build level dependency
&lt;span class="citation" data-cites="Gupta2011 Micco2013 Micco2012"&gt;(&lt;a
href="#ref-Gupta2011" role="doc-biblioref"&gt;Gupta, Ivey, and Penix
2011&lt;/a&gt;; &lt;a href="#ref-Micco2013" role="doc-biblioref"&gt;Micco 2013&lt;/a&gt;,
&lt;a href="#ref-Micco2012" role="doc-biblioref"&gt;2012&lt;/a&gt;)&lt;/span&gt;. This is
a very coarse grained form of static dependence-based test selection
&lt;span class="citation" data-cites="Binkley1992 Horwitz1992 Tip1995"&gt;(&lt;a
href="#ref-Binkley1992" role="doc-biblioref"&gt;Binkley 1992&lt;/a&gt;; &lt;a
href="#ref-Horwitz1992" role="doc-biblioref"&gt;Horwitz and Reps 1992&lt;/a&gt;;
&lt;a href="#ref-Tip1995" role="doc-biblioref"&gt;Tip 1995&lt;/a&gt;)&lt;/span&gt;.
Google’s use of build dependence test selection has been influential and
it is now also used at a number of other corporations who have adopted
Bazel or similar tools &lt;span class="citation"
data-cites="Ananthanarayanan2019 Machalica2019"&gt;(&lt;a
href="#ref-Ananthanarayanan2019" role="doc-biblioref"&gt;Ananthanarayanan
et al. 2019&lt;/a&gt;; &lt;a href="#ref-Machalica2019"
role="doc-biblioref"&gt;Machalica et al. 2019&lt;/a&gt;)&lt;/span&gt;. Finally, that
(potentially very large) set of “affected” tests is sent to the Build
System &lt;span class="citation" data-cites="Wang2020"&gt;(&lt;a
href="#ref-Wang2020" role="doc-biblioref"&gt;Wang et al. 2020&lt;/a&gt;)&lt;/span&gt;
which batches them into efficiently sized groups and then builds and
runs them when there is capacity.&lt;/p&gt;
&lt;p&gt;Since tests are only run periodically even with accurate build level
dependence analysis to drive test selection, there are usually multiple
changes which may have introduced a fault in the software or a bug in
the test. Finding these “bug inducing changes” – which we call
&lt;strong&gt;culprits&lt;/strong&gt; – is the subject of this paper. The process of
finding these changes is aggravated by any non-deterministic behavior of
the tests and the build system running them.&lt;/p&gt;
&lt;h2 id="flaky-tests"&gt;Flaky Tests&lt;/h2&gt;
&lt;p&gt;When a test behaves non-deterministically, we refer to it, using the
standard term, as a &lt;em&gt;flaky test&lt;/em&gt;. A flaky test is one that passes
or fails non-deterministically with no changes to the code of either the
test or the system under test. At Google, we consider all tests to be at
least &lt;em&gt;slightly&lt;/em&gt; flaky as the machines that tests are running on
could fail in ways that get classified as a test failure (such as
resource exhaustion due to a noisy neighbor resulting in a test
exceeding its time limit). We encourage everyone to adopt this
conservative view for the purposes of identifying culprits.&lt;/p&gt;
&lt;p&gt;An important input to the culprit finding algorithm we are presenting
is an estimate of how flaky a test might be, as represented by an
estimated probability of the test failing due to a flaky failure. We
will denote the estimated probability of failure due to a flake for a
test &lt;span class="math inline"&gt;\(t\)&lt;/span&gt; as &lt;span
class="math inline"&gt;\(\hat{f}_t\)&lt;/span&gt;. The actual probability of
failure due to a flake will be denoted &lt;span
class="math inline"&gt;\(f_t\)&lt;/span&gt; (it is impossible in practice to know
&lt;span class="math inline"&gt;\(f_t\)&lt;/span&gt;). At Google, we estimate &lt;span
class="math inline"&gt;\(\hat{f}_t\)&lt;/span&gt; based on the historical failure
rate of the test. Apple and Facebook recently published on their work in
on estimating flake rates &lt;span class="citation"
data-cites="Kowalczyk2020 Machalica2020"&gt;(&lt;a href="#ref-Kowalczyk2020"
role="doc-biblioref"&gt;Kowalczyk et al. 2020&lt;/a&gt;; &lt;a
href="#ref-Machalica2020" role="doc-biblioref"&gt;Machalica et al.
2020&lt;/a&gt;)&lt;/span&gt;. One challenge with flake rate estimation is that a
single change to the code can completely change the flakiness
characteristics of a test in unpredictable ways. Making the flake rate
estimation sensitive to recent changes is an ongoing challenge and one
we partially solve in this work by doing live re-estimation of the flake
rate during the culprit finding process itself.&lt;/p&gt;
&lt;h2 id="sec:background:cf"&gt;Culprit Finding&lt;/h2&gt;
&lt;p&gt;Informally, Culprit Finding is the problem of identifying a version
&lt;span class="math inline"&gt;\(c\)&lt;/span&gt; between two versions &lt;span
class="math inline"&gt;\(a\)&lt;/span&gt; and &lt;span
class="math inline"&gt;\(b\)&lt;/span&gt; such that &lt;span class="math inline"&gt;\(a
&amp;lt; c \le b\)&lt;/span&gt; where a given test &lt;span
class="math inline"&gt;\(t\)&lt;/span&gt; was passing at &lt;span
class="math inline"&gt;\(a\)&lt;/span&gt;, failing at &lt;span
class="math inline"&gt;\(b\)&lt;/span&gt;, and &lt;span
class="math inline"&gt;\(c\)&lt;/span&gt; is the version which introduced the
fault. At Google we consider the passing status of a test to be 100%
reliable and therefore version &lt;span class="math inline"&gt;\(a\)&lt;/span&gt;
cannot be a culprit but version &lt;span class="math inline"&gt;\(b\)&lt;/span&gt;
could be the culprit. For simplicity, this paper only considers
searching for the culprit for a single test &lt;span
class="math inline"&gt;\(t\)&lt;/span&gt; (which failed at &lt;span
class="math inline"&gt;\(b\)&lt;/span&gt;) but in principle it can be extended to
a set of tests &lt;span class="math inline"&gt;\(T\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Google’s version control system, Piper &lt;span class="citation"
data-cites="Potvin2016"&gt;(&lt;a href="#ref-Potvin2016"
role="doc-biblioref"&gt;Potvin and Levenberg 2016&lt;/a&gt;)&lt;/span&gt;, stores the
mainline history as a linear list of versions. Each version gets a
monotonically, &lt;em&gt;but not sequentially&lt;/em&gt;, increasing number as its
version number called the &lt;em&gt;Changelist Number&lt;/em&gt; or CL number for
short. Thus, our implementation and experiments do not consider branches
and merges as would be necessary for a Distributed Version Control
System (DVCS) such as git. However, only trivial changes to the
mathematics are needed to apply our approach to such an environment
&lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Thus, the versions larger than &lt;span class="math inline"&gt;\(a\)&lt;/span&gt;
and smaller or equal to &lt;span class="math inline"&gt;\(b\)&lt;/span&gt; are an
ordered list of items we will call the &lt;em&gt;search range&lt;/em&gt; and denote
as &lt;span class="math inline"&gt;\(S =
\left\{s_1, ..., s_{n-1}, s_n\right\}\)&lt;/span&gt; where &lt;span
class="math inline"&gt;\(s_n = b\)&lt;/span&gt;. During the search, test
executions will be run (and may be run in parallel) at various versions.
The unordered set of executions at version &lt;span
class="math inline"&gt;\(s_i\)&lt;/span&gt; will be denoted &lt;span
class="math inline"&gt;\(X_i\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;For the purposes of culprit finding, based on the status of failure
detected, the build/test execution statuses are mapped to one of 2
possible states: &lt;code&gt;PASS&lt;/code&gt; or &lt;code&gt;FAIL&lt;/code&gt;. We denote (for
version &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt;): the number of
statuses that map to &lt;code&gt;PASS&lt;/code&gt; as &lt;span
class="math inline"&gt;\(\texttt{\small PASSES}(X_i)\)&lt;/span&gt; and the
number of statuses that map to &lt;code&gt;FAIL&lt;/code&gt; as &lt;span
class="math inline"&gt;\(\texttt{\small FAILS}(X_i)\)&lt;/span&gt;.&lt;/p&gt;

&lt;h2 id="bisection"&gt;Bisection&lt;/h2&gt;

&lt;p&gt;&lt;span id="alg:bisect" label="alg:bisect"&gt;
&lt;a href="images/icst-2023/alg1.png"&gt;&lt;img alt="Algorithm Bisect" src="images/icst-2023/alg1.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The Bisect algorithm is a specialized form of binary search. It runs
tests (or more generally any operation on the code that can return PASS
or FAIL) to attempt to identify which commit introduced a bug. Algorithm
&lt;a href="#alg:bisect" data-reference-type="ref"
data-reference="alg:bisect"&gt;[alg:bisect]&lt;/a&gt; gives the psuedo-code for
this procedure. Bisect is now commonly implemented in most version
control systems (see &lt;code&gt;git bisect&lt;/code&gt; and &lt;code&gt;hg bisect&lt;/code&gt;
as common examples). In the case of Distributed Version Control Systems
(DVCS) systems such as ‘git‘ and ‘hg‘ the implementation of bisect is
somewhat more complex as they model version history as a directed
acyclic graph &lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The algorithm presented in Alg &lt;a href="#alg:bisect"
data-reference-type="ref" data-reference="alg:bisect"&gt;[alg:bisect]&lt;/a&gt;
has two important changes from the standard binary search. First, it
takes into account that a test can fail and pass at the same version and
the &lt;code&gt;firstFail&lt;/code&gt; function specifically looks for a failure
after the &lt;code&gt;lastPass&lt;/code&gt;. Second, it takes a parameter &lt;span
class="math inline"&gt;\(k\)&lt;/span&gt; which allows the user to specify that
each test execution be run &lt;span class="math inline"&gt;\(k\)&lt;/span&gt; times.
This allows the user to “deflake” the test executions by rerunning
failures. Our empirical evaluation (Section &lt;a href="#sec:evaluation"
data-reference-type="ref" data-reference="sec:evaluation"&gt;5&lt;/a&gt;)
examines both the cost and effectiveness of this simple modification.
While this simple modification to bisect may be reasonably effective for
moderately flaky tests, it does not explicitly model the effect of
non-deterministic failures on the likelihood of a suspect to be the
culprit.&lt;/p&gt;
&lt;h2 id="guessing-games-and-noisy-searches"&gt;Guessing Games and Noisy
Searches&lt;/h2&gt;
&lt;div class="algorithm"&gt;

&lt;/div&gt;
&lt;p&gt;One can view the culprit finding scenario as a kind of guessing game.
The questioner guesses the test always fails at a given suspect version.
A test execution at that suspect acts as a kind of “responder” or
“oracle” which answers. The test execution is an unreliable oracle which
may answer FAIL when it should have answered PASS. But, the oracle never
answers PASS when it should have answered FAIL – note the asymmetry.&lt;/p&gt;
&lt;p&gt;This kind of guessing game is a Rényi-Ulam game, which has been well
characterized by the community &lt;span class="citation"
data-cites="Pelc2002"&gt;(&lt;a href="#ref-Pelc2002" role="doc-biblioref"&gt;Pelc
2002&lt;/a&gt;)&lt;/span&gt;. The main differences from the “classical” games
presented by Rényi and separately by Ulam is (a) the format of the
questions and (b) the limitations placed on the oracle responding
incorrectly. In a common formulation of the Rényi-Ulam game, the
questioner is trying to “guess the number” between (for instance) 1 and
1,000,000. Each question is allowed to be any subset of numbers in the
search range. The responder or oracle is allowed to lie at most a fixed
number of times (for instance once or twice). This formulation has
allowed the community to find analytic solutions to determine the number
of questions in the optimal strategy. We refer the reader to the survey
from Pelc for an overview of the field and its connection with error
correcting codes &lt;span class="citation" data-cites="Pelc2002"&gt;(&lt;a
href="#ref-Pelc2002" role="doc-biblioref"&gt;Pelc 2002&lt;/a&gt;)&lt;/span&gt;. The
culprit finding scenario is “noisy binary search” scenario where the
oracle only lies for one type of response. Rivest &lt;em&gt;et al.&lt;/em&gt; &lt;span
class="citation" data-cites="Rivest1978"&gt;(&lt;a href="#ref-Rivest1978"
role="doc-biblioref"&gt;Rivest, Meyer, and Kleitman 1978&lt;/a&gt;)&lt;/span&gt;
provide a theoretical treatment of this “half-lie” variant (as well as
the usual variation).&lt;/p&gt;
&lt;h2 id="bayesian-binary-search"&gt;Bayesian Binary Search&lt;/h2&gt;
&lt;p&gt;Ben Or and Hassidim &lt;span class="citation"
data-cites="Ben-Or2008"&gt;(&lt;a href="#ref-Ben-Or2008"
role="doc-biblioref"&gt;Ben-Or and Hassidim 2008&lt;/a&gt;)&lt;/span&gt; noted the
connection between these “Noisy Binary Search” problems and Bayesian
inference. Our work builds off of their formulation and applies it to
the culprit finding setting. In the Bayesian setting, consider the
probability each suspect is the culprit and the probability there is no
culprit (i.e. the original failure was caused by a flake). These
probabilities together form a distribution: &lt;span
class="math display"&gt;\[(\textrm{Pr}\left[{\text{there is no
culprit}}\right]) +
  \sum_{i=1}^{n} \textrm{Pr}\left[{s_i \text{ is the culprit}}\right] =
1\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;We represent this distribution with &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{C_i}\right]\)&lt;/span&gt; with &lt;span
class="math inline"&gt;\(i=1..(n+1)\)&lt;/span&gt; where &lt;span
class="math display"&gt;\[\begin{aligned}
\begin{split}
  \textrm{Pr}\left[{C_i}\right] &amp;amp;= \textrm{Pr}\left[{s_i \text{ is
the culprit}}\right], \; \forall \; i \in [1, n]
   \\
  \textrm{Pr}\left[{C_{n+1}}\right] &amp;amp;= \textrm{Pr}\left[{\text{there
is no culprit}}\right] \\
\end{split}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Initially when the original failure is first detected at &lt;span
class="math inline"&gt;\(s_n\)&lt;/span&gt; and the search range is created, the
probability distribution is uniform: &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{C_i}\right] =
\frac{1}{(n+1)}\)&lt;/span&gt; for all &lt;span class="math inline"&gt;\(i \in [1,
n+1]\)&lt;/span&gt;. Now consider new evidence &lt;span
class="math inline"&gt;\(E\)&lt;/span&gt; arriving. In the Bayesian model, this
would &lt;em&gt;update&lt;/em&gt; our probability given this new evidence: &lt;span
class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{C_i | E}\right] = \frac{\textrm{Pr}\left[{E |
C_i}\right] \cdot
\textrm{Pr}\left[{C_i}\right]}{\textrm{Pr}\left[{E}\right]}
  \label{eq:bayes}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In the above equation, the &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{C_i}\right]\)&lt;/span&gt; is the
&lt;em&gt;prior&lt;/em&gt; probability and the probability &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{C_i | E}\right]\)&lt;/span&gt; is the
&lt;em&gt;posterior&lt;/em&gt; probability. In the culprit finding context, the new
evidence is typically newly observed test executions. However, there is
no reason we cannot take into account other information as well.&lt;/p&gt;
&lt;p&gt;In the Bayesian framework, new evidence is applied iteratively. In
each iteration, the prior probability is the posterior probability of
the previous iteration. Since multiplication is commutative, multiple
pieces of evidence can be applied in any order to arrive at the same
posterior probability: &lt;span class="math display"&gt;\[\begin{aligned}
\begin{split}
  \textrm{Pr}\left[{C_i | E_1, E_2}\right] &amp;amp;=
\frac{\textrm{Pr}\left[{E_2 |
C_i}\right]}{\textrm{Pr}\left[{E_2}\right]}
                         \frac{\textrm{Pr}\left[{E_1 |
C_i}\right]}{\textrm{Pr}\left[{E_1}\right]} \textrm{Pr}\left[{Ci}\right]
\\
                      &amp;amp;= \frac{\textrm{Pr}\left[{E_1 |
C_i}\right]}{\textrm{Pr}\left[{E_1}\right]}
                         \frac{\textrm{Pr}\left[{E_2 |
C_i}\right]}{\textrm{Pr}\left[{E_2}\right]} \textrm{Pr}\left[{Ci}\right]
\end{split}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;After the current posterior probability has been calculated, it is
used to select the next suspect to execute a test at. In the traditional
Bayes approach, the suspect to examine is the one with the maximum
posterior probability. However, in the context of a noisy binary search,
the suspects are ordered so a PASS at suspect &lt;span
class="math inline"&gt;\(s_i\)&lt;/span&gt; indicates a PASS at all suspects
prior to &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt;. Following Ben Or and
Hassidim &lt;span class="citation" data-cites="Ben-Or2008"&gt;(&lt;a
href="#ref-Ben-Or2008" role="doc-biblioref"&gt;Ben-Or and Hassidim
2008&lt;/a&gt;)&lt;/span&gt;, we convert the posterior distribution to a cumulative
probability distribution and select the first suspect with a cumulative
probability &lt;span class="math inline"&gt;\(\geq 0.5\)&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id="flake-aware-culprit-finding"&gt;Flake Aware Culprit Finding&lt;/h1&gt;
&lt;p&gt;Now we introduce our algorithm, Flake Aware Culprit Finding (FACF),
in the Bayesian framework of Ben Or and Hassidim &lt;span class="citation"
data-cites="Ben-Or2008"&gt;(&lt;a href="#ref-Ben-Or2008"
role="doc-biblioref"&gt;Ben-Or and Hassidim 2008&lt;/a&gt;)&lt;/span&gt;. As above, let
&lt;span class="math inline"&gt;\(\textrm{Pr}\left[{C_i}\right]\)&lt;/span&gt; be
the probability that suspect &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; is
the culprit and &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{C_{n+1}}\right]\)&lt;/span&gt; be the
probability there is no culprit. These probabilities are initialized to
some suitable initial distribution such as the uniform distribution.&lt;/p&gt;
&lt;p&gt;To update the distribution with new evidence &lt;span
class="math inline"&gt;\(E\)&lt;/span&gt; in the form of a pass or fail for some
suspect &lt;span class="math inline"&gt;\(k\)&lt;/span&gt;, apply Bayes rule
(Equation &lt;a href="#eq:bayes" data-reference-type="ref"
data-reference="eq:bayes"&gt;[eq:bayes]&lt;/a&gt;). Note that &lt;span
class="math inline"&gt;\(\textrm{Pr}\left[{E}\right]\)&lt;/span&gt; can be
rewritten by Bayes rule in terms of a sum by marginalizing over the
likelihood that each suspect &lt;span class="math inline"&gt;\(j\)&lt;/span&gt;
could be the culprit: &lt;span class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{E}\right] = \sum_{j=1}^{n} \textrm{Pr}\left[{E |
C_j}\right] \textrm{Pr}\left[{C_j}\right]\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;There are two types of evidence: test executions with state
&lt;code&gt;PASS&lt;/code&gt; or &lt;code&gt;FAIL&lt;/code&gt; at suspect &lt;span
class="math inline"&gt;\(i\)&lt;/span&gt;. We indicate these as the events &lt;span
class="math inline"&gt;\(P_i\)&lt;/span&gt; and &lt;span
class="math inline"&gt;\(F_i\)&lt;/span&gt; respectively. The marginalized
probability of a &lt;code&gt;PASS&lt;/code&gt; at &lt;span
class="math inline"&gt;\(i\)&lt;/span&gt; given there is a culprit at &lt;span
class="math inline"&gt;\(j\)&lt;/span&gt; is: &lt;span
class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{P_i | C_j}\right] =
    \begin{cases}
      1 - \hat{f}_t  &amp;amp; \text{if } i &amp;lt; j \\
      0              &amp;amp; \text{otherwise}
    \end{cases}
  \label{eq:pass}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The marginalized probability of a &lt;code&gt;FAIL&lt;/code&gt; at &lt;span
class="math inline"&gt;\(i\)&lt;/span&gt; given there is a culprit at &lt;span
class="math inline"&gt;\(j\)&lt;/span&gt; is: &lt;span
class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{F_i | C_j}\right] =
    \begin{cases}
      \hat{f}_t      &amp;amp; \text{if } i &amp;lt; j \\
      1              &amp;amp; \text{otherwise}
    \end{cases}
  \label{eq:fail}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;With Equation &lt;a href="#eq:pass" data-reference-type="ref"
data-reference="eq:pass"&gt;[eq:pass]&lt;/a&gt;, we write a Bayesian update for
&lt;code&gt;PASS&lt;/code&gt; at suspect &lt;span class="math inline"&gt;\(k\)&lt;/span&gt; as
the following. Given &lt;span class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{C_i | P_k}\right] = \frac{\textrm{Pr}\left[{P_k |
C_i}\right] \textrm{Pr}\left[{C_i}\right]}{
\textrm{Pr}\left[{P_k}\right]
  }\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;let &lt;span class="math display"&gt;\[\begin{aligned}
\begin{split}
  \textrm{Pr}\left[{P_k}\right] &amp;amp;= \sum_{j=1}^{n}
\textrm{Pr}\left[{P_k | C_j}\right] \textrm{Pr}\left[{C_j}\right] \\
           &amp;amp;= \sum_{j=k+1}^{n} (1 - \hat{f}_t)
\textrm{Pr}\left[{C_j}\right]
\end{split}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;div class="algorithm"&gt;

&lt;/div&gt;
&lt;div class="algorithm"&gt;
&lt;p&gt;cdf = cumulativeDistribution(dist) thresholds = &lt;span
class="math inline"&gt;\(\left\{ \frac{i}{(k+1)} \; | \; i=1..k
\right\}\)&lt;/span&gt; tidx = 0 runs = list() runs&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;then &lt;span class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{C_i | P_k}\right] =
  \begin{cases}
    \frac{(1 - \hat{f}_t)
\textrm{Pr}\left[{C_i}\right]}{\textrm{Pr}\left[{P_k}\right]} &amp;amp;
\text{if } k &amp;lt; i \\
    0                                         &amp;amp; \text{otherwise} \\
  \end{cases}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The update using Equation &lt;a href="#eq:fail"
data-reference-type="ref" data-reference="eq:fail"&gt;[eq:fail]&lt;/a&gt; for
&lt;code&gt;FAIL&lt;/code&gt; at suspect &lt;span class="math inline"&gt;\(k\)&lt;/span&gt; is
similar. Given &lt;span class="math display"&gt;\[\begin{aligned}
  \textrm{Pr}\left[{C_i | F_k}\right] = \frac{\textrm{Pr}\left[{F_k |
C_i}\right] \textrm{Pr}\left[{C_i}\right]}{
    \sum_{j=1}^{n} \textrm{Pr}\left[{F_k | C_j}\right]
\textrm{Pr}\left[{C_j}\right]
  }\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;let &lt;span class="math display"&gt;\[\begin{aligned}
\begin{split}
  \textrm{Pr}\left[{F_k}\right] &amp;amp;= \sum_{j=1}^{n}
\textrm{Pr}\left[{F_k | C_j}\right] \textrm{Pr}\left[{C_j}\right] \\
           &amp;amp;= \sum_{j=1}^{k} \textrm{Pr}\left[{C_j}\right] +
\sum_{j=k+1}^{n} \hat{f}_t \textrm{Pr}\left[{C_j}\right]
\end{split}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;then &lt;span class="math display"&gt;\[\begin{aligned}
\textrm{Pr}\left[{C_i | F_k}\right] =
  \begin{cases}
    \frac{\hat{f}_t
\textrm{Pr}\left[{C_i}\right]}{\textrm{Pr}\left[{F_k}\right]} &amp;amp;
\text{if } k &amp;lt; i \\
    \frac{\textrm{Pr}\left[{C_i}\right]}{\textrm{Pr}\left[{F_k}\right]}           &amp;amp;
\text{otherwise} \\
  \end{cases}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;

&lt;h2 id="the-facf-algorithm"&gt;The FACF Algorithm&lt;/h2&gt;

&lt;p&gt;&lt;span id="alg:facf" label="alg:facf"&gt;
&lt;a href="images/icst-2023/alg2.png"&gt;&lt;img alt="Algorithm FACF" src="images/icst-2023/alg2.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span id="alg:nextRuns" label="alg:nextRuns"&gt;
&lt;a href="images/icst-2023/alg3.png"&gt;&lt;img alt="Algorithm nextRuns" src="images/icst-2023/alg3.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Algorithm &lt;a href="#alg:facf" data-reference-type="ref"
data-reference="alg:facf"&gt;[alg:facf]&lt;/a&gt; presents the pseudo code for a
culprit finding algorithm based on the above Bayesian formulation. It
takes a prior distribution (the uniform distribution can be used), an
estimated flake rate &lt;span class="math inline"&gt;\(\hat{f}_t\)&lt;/span&gt;, and
the suspects. It returns the most likely culprit or &lt;code&gt;NONE&lt;/code&gt;
(in the case that it is most likely there is no culprit). The FACF
algorithm builds a set of evidence &lt;span
class="math inline"&gt;\(X\)&lt;/span&gt; containing the observed passes and
failures so far. At each step, that evidence is converted to a
distribution using the math presented above. Then, FACF calls Algorithm
&lt;a href="#alg:nextRuns" data-reference-type="ref"
data-reference="alg:nextRuns"&gt;[alg:nextRuns]&lt;/a&gt; &lt;code&gt;NextRuns&lt;/code&gt;
to compute the next suspect to run.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;NextRuns&lt;/code&gt; converts the probability distribution into a
cumulative distribution. It then selects the suspects with cumulative
probability over a set of thresholds and returns them. The version of
&lt;code&gt;NextRuns&lt;/code&gt; we present here has been generalized to allow for
&lt;span class="math inline"&gt;\(k\)&lt;/span&gt; parallel runs and also contains a
minor optimization on lines 10-11. If the suspect &lt;span
class="math inline"&gt;\(s_{i-1}\)&lt;/span&gt; prior to the selected suspect
&lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; hasn’t been selected to run and
its cumulative probability is above &lt;span
class="math inline"&gt;\(0\)&lt;/span&gt; then the prior suspect &lt;span
class="math inline"&gt;\(s_{i-1}\)&lt;/span&gt; is selected in favor of &lt;span
class="math inline"&gt;\(s_i\)&lt;/span&gt;. This optimization ensures that we
look for the passing run preceding the most likely culprit before
looking for a failing run at the culprit.&lt;/p&gt;
&lt;h2 id="sec:thresholds"&gt;Choosing the Thresholds in NextRuns&lt;/h2&gt;
&lt;p&gt;Another optimization can be made to NextRuns by changing the
thresholds used to select suspects. Instead of simply dividing the
probability space up evenly it uses the observation that the information
gain from a PASS is more than the gain from a FAIL. Modeling that as
&lt;span class="math inline"&gt;\(I(P_i) = 1\)&lt;/span&gt; and &lt;span
class="math inline"&gt;\(I(F_i) = 1 - \hat{f}_t\)&lt;/span&gt;, we can compute
the expected information gain for new evidence at suspect &lt;span
class="math inline"&gt;\(s_i\)&lt;/span&gt; as &lt;span
class="math inline"&gt;\(\textrm{E}\left[{I(s_i)}\right] = I(P_i)P_i +
I(F_i)F_i\)&lt;/span&gt;. Expanding from the marginalized equations &lt;a
href="#eq:pass" data-reference-type="ref"
data-reference="eq:pass"&gt;[eq:pass]&lt;/a&gt; and &lt;a href="#eq:fail"
data-reference-type="ref" data-reference="eq:fail"&gt;[eq:fail]&lt;/a&gt; gives
&lt;span class="math display"&gt;\[\begin{aligned}
  \textrm{E}\left[{I(s_i)}\right] = (1 - \hat{f}_t)(n + i \hat{f}_t -
1)\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Computing the cumulative expectation over &lt;span
class="math inline"&gt;\(\{ \textrm{E}\left[{I(s_1)}\right], ...,
\textrm{E}\left[{I(s_{n+1})}\right] \}\)&lt;/span&gt; and normalizing allows
us to select the suspect that maximizes the information gain. The
empirical evaluation (Section &lt;a href="#sec:evaluation"
data-reference-type="ref" data-reference="sec:evaluation"&gt;5&lt;/a&gt;)
examines the effect of this optimization. The importance of the supplied
flake rate estimate (&lt;span class="math inline"&gt;\(\hat{f}_t\)&lt;/span&gt;) is
also examined in Section &lt;a href="#sec:evaluation"
data-reference-type="ref" data-reference="sec:evaluation"&gt;5&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="sec:priors"&gt;Prior Probabilities for FACF&lt;/h2&gt;
&lt;p&gt;The prior distribution supplied to Algorithm &lt;a href="#alg:facf"
data-reference-type="ref" data-reference="alg:facf"&gt;[alg:facf]&lt;/a&gt; does
not have to be a uniform distribution. Instead, it can be informed by
any other data the culprit finding system might find useful. At Google,
we are exploring many such sources of data, but so far are only using
two primary sources in production.&lt;/p&gt;
&lt;p&gt;First, we have always used the static build dependence graph to
filter out non-affecting suspects before culprit finding &lt;span
class="citation" data-cites="Gupta2011"&gt;(&lt;a href="#ref-Gupta2011"
role="doc-biblioref"&gt;Gupta, Ivey, and Penix 2011&lt;/a&gt;)&lt;/span&gt;. In FACF,
we take that a step further and, using a stale snapshot for scalability,
we compute the minimum distance in the build graph between the files
changed in each suspect and the test being culprit-found &lt;span
class="citation" data-cites="Memon2017"&gt;(&lt;a href="#ref-Memon2017"
role="doc-biblioref"&gt;Memon et al. 2017&lt;/a&gt;)&lt;/span&gt;. Using these
distances, we form a probability distribution where the suspects with
files closer to the test have a higher probability of being the culprit
&lt;span class="citation" data-cites="Ziftci2013a Ziftci2017"&gt;(&lt;a
href="#ref-Ziftci2013a" role="doc-biblioref"&gt;Ziftci and Ramavajjala
2013&lt;/a&gt;; &lt;a href="#ref-Ziftci2017" role="doc-biblioref"&gt;Ziftci and
Reardon 2017&lt;/a&gt;)&lt;/span&gt;. Second, we look at the historical likelihood
of a true breakage (versus a flaky one) to determine the probability
that there is no culprit. Combining that distribution with the one from
the minimum build distance forms a prior distribution we use for culprit
finding.&lt;/p&gt;
&lt;p&gt;Using this scheme, flaky tests tend to get reruns at the &lt;span
class="math inline"&gt;\(s_n\)&lt;/span&gt; (the suspect where the failure was
detected) as their first test executions during culprit finding. This is
intentional as a large fraction of the search ranges we culprit find
tend to be flaky and this reduces the cost of proving that. In the
empirical evaluation (Section &lt;a href="#sec:evaluation"
data-reference-type="ref" data-reference="sec:evaluation"&gt;5&lt;/a&gt;), we
examine the effect of the prior distribution on both cost and
accuracy.&lt;/p&gt;
&lt;h1 id="sec:verification"&gt;Culprit Verification for Accuracy
Evaluation&lt;/h1&gt;
&lt;p&gt;The previous sections detailed our culprit finding algorithm (FACF)
and the baseline algorithm we compare against (deflaked bisection). In
order to evaluate the accuracy of a culprit finding system for a
particular dataset, we need to know which commits are the actual culprit
commits. If the actual culprit commits are known, then we can compute
the usual measures (True Positive Rate, False Positive Rate, Accuracy,
Precision, Recall, etc...) &lt;span class="citation"
data-cites="Tharwat2021"&gt;(&lt;a href="#ref-Tharwat2021"
role="doc-biblioref"&gt;Tharwat 2021&lt;/a&gt;)&lt;/span&gt;. Previous work in culprit
finding, test case selection, fault localization and related research
areas have often used curated datasets (e.g. Defects4J &lt;span
class="citation" data-cites="Just2014"&gt;(&lt;a href="#ref-Just2014"
role="doc-biblioref"&gt;Just, Jalali, and Ernst 2014&lt;/a&gt;)&lt;/span&gt;), bug
databases &lt;span class="citation"
data-cites="Bhattacharya2010 Herzig2015 Najafi2019a"&gt;(&lt;a
href="#ref-Bhattacharya2010" role="doc-biblioref"&gt;Bhattacharya and
Neamtiu 2010&lt;/a&gt;; &lt;a href="#ref-Herzig2015" role="doc-biblioref"&gt;Herzig
et al. 2015&lt;/a&gt;; &lt;a href="#ref-Najafi2019a" role="doc-biblioref"&gt;Najafi,
Rigby, and Shang 2019&lt;/a&gt;)&lt;/span&gt;, and synthetic benchmarks with
injected bugs &lt;span class="citation"
data-cites="Henderson2018 Henderson2019"&gt;(&lt;a href="#ref-Henderson2018"
role="doc-biblioref"&gt;Henderson and Podgurski 2018&lt;/a&gt;; &lt;a
href="#ref-Henderson2019" role="doc-biblioref"&gt;Henderson, Podgurski, and
Kucuk 2019&lt;/a&gt;)&lt;/span&gt;. But our primary interest is in the accuracy of
the algorithms in the Google environment, not the accuracy on open
source bug databases, curated datasets, or synthetic bugs.&lt;/p&gt;
&lt;p&gt;At Google, we do not have a comprehensive database of developer
investigations of every continuous integration test failure – indeed
there are far too many failures per day for developers to examine and
evaluate every single one. We also didn’t want to completely rely on
human feedback to tell us when our culprit finding systems have
identified the wrong culprit – as had been previously done &lt;span
class="citation" data-cites="Ziftci2017"&gt;(&lt;a href="#ref-Ziftci2017"
role="doc-biblioref"&gt;Ziftci and Reardon 2017&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Instead, we wanted to be able to verify whether or not an identified
culprit for a particular test and search range is correct or not. The
verification needs to be automated such that the we can operationally
monitor the accuracy of the deployed system and catch any performance
regressions in the culprit finder. Continuous monitoring ensures a high
quality user experience by alerting our team to accuracy
degradations.&lt;/p&gt;
&lt;h2 id="culprit-finding-conclusions"&gt;Culprit Finding Conclusions&lt;/h2&gt;
&lt;p&gt;A culprit finder may draw one of two conclusions:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;FI&lt;/strong&gt;: &lt;code&gt;FLAKE_IDENTIFIED&lt;/code&gt; &lt;em&gt;the
culprit finder determined the status transition was caused by
non-deterministic behavior.&lt;/em&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;CVI&lt;/strong&gt;:
&lt;code&gt;CULPRIT_VERSION_IDENTIFIED(version)&lt;/code&gt; &lt;em&gt;the culprit finder
determined a specific &lt;code&gt;version&lt;/code&gt; was identified as the
culprit&lt;/em&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The verification system will label each conclusion examined with
either &lt;code&gt;CORRECT&lt;/code&gt; or &lt;code&gt;INCORRECT&lt;/code&gt; from which we can
define the standard counts for True and False Positives and Negatives.
Accuracy, Precision, and Recall can then be directly computed.&lt;/p&gt;
&lt;h2 id="when-is-a-culprit-incorrect"&gt;When is a Culprit Incorrect?&lt;/h2&gt;
&lt;p&gt;For ease of discussion, we will use the notation introduced in
Section &lt;a href="#sec:background:cf" data-reference-type="ref"
data-reference="sec:background:cf"&gt;2.2&lt;/a&gt; for the search range &lt;span
class="math inline"&gt;\(S\)&lt;/span&gt; with &lt;span
class="math inline"&gt;\(s_0\)&lt;/span&gt; indicating the previous passing
version, &lt;span class="math inline"&gt;\(s_n\)&lt;/span&gt; indicating the version
where the failure was first detected, and &lt;span
class="math inline"&gt;\(s_k\)&lt;/span&gt; indicating the identified culprit.
Now, consider the two cases&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;FLAKE_IDENTIFIED&lt;/code&gt; these are incorrect if no
subsequent runs pass at the version where the original failure was
detected (no flaky behavior can be reproduced).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;code&gt;CULPRIT_VERSION_IDENTIFIED(version)&lt;/code&gt; these are
incorrect if we can prove any of the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A pass at &lt;span class="math inline"&gt;\(s_n\)&lt;/span&gt; indicates the
failure was a flake.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;A pass at the culprit &lt;span class="math inline"&gt;\(s_k\)&lt;/span&gt;
indicates that the culprit was incorrectly identified.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No passes detected at the version prior to the culprit, &lt;span
class="math inline"&gt;\(s_{k-1}\)&lt;/span&gt;, indicates that the culprit was
incorrectly identified.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Additionally the following conditions indicate the culprit may have
been misidentified due to a test dependency on either time or some
unknown external factor:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;No passes are identified at &lt;span
class="math inline"&gt;\(s_0\)&lt;/span&gt;, indicating the test failure may be
time or environment dependent (and the conclusion cannot be
trusted).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No pass at &lt;span class="math inline"&gt;\(s_0\)&lt;/span&gt; is detected
prior (in the time dimension) to a failure at &lt;span
class="math inline"&gt;\(s_n\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No failure at &lt;span class="math inline"&gt;\(s_n\)&lt;/span&gt; is
detected prior (in the time dimension) to a pass at &lt;span
class="math inline"&gt;\(s_0\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No pass at &lt;span class="math inline"&gt;\(s_{k-1}\)&lt;/span&gt; is
detected prior (in the time dimension) to a failure at &lt;span
class="math inline"&gt;\(s_k\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;No failure at &lt;span class="math inline"&gt;\(s_k\)&lt;/span&gt; is
detected prior (in the time dimension) to a pass at &lt;span
class="math inline"&gt;\(s_{k-1}\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Verification is not reproducible 17 hours later.&lt;a href="#fn4"
class="footnote-ref" id="fnref4"
role="doc-noteref"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Thus, our approach for determining whether or not a culprit is
correct is to do extensive reruns for a particular conclusion.&lt;/p&gt;
&lt;h2 id="how-many-reruns-to-conduct-to-verify-a-conclusion"&gt;How Many
Reruns to Conduct to Verify a Conclusion&lt;/h2&gt;
&lt;p&gt;A test run &lt;span class="math inline"&gt;\(x\)&lt;/span&gt; times fails every
time with the rate &lt;span class="math inline"&gt;\(\hat{f}_t^x\)&lt;/span&gt;. If
we want to achieve confidence level &lt;span
class="math inline"&gt;\(C\)&lt;/span&gt; (ex. &lt;span class="math inline"&gt;\(C =
.99999999\)&lt;/span&gt;) of verifier correctness, we can compute the number
of reruns to conduct for each check with &lt;span class="math inline"&gt;\(x =
\left\lceil{\frac{\,\textrm{log}\!\!\left({1 -
C}\right)}{\,\textrm{log}\!\!\left({\hat{f}_t}\right)}}\right\rceil\)&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="sampling-strategy"&gt;Sampling Strategy&lt;/h2&gt;
&lt;p&gt;While it would be ideal to verify every single culprit for every
single test, the expense, in practice, of such an operation is too high.
We conduct verification with a very high confidence level (&lt;span
class="math inline"&gt;\(C = 0.99999999\)&lt;/span&gt;) and a minimum on the
estimated flakiness rate of &lt;span class="math inline"&gt;\(0.1\)&lt;/span&gt; to
ensure a minimum of 8 reruns for each check even for targets that have
not been historically flaky. With such an expensive configuration, we
can only afford the following sampling strategy.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Randomly sample at &lt;span class="math inline"&gt;\(1\%\)&lt;/span&gt; of
culprit finding conclusions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Sample the first conclusion for each unique culprit
version.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We tag which sampling strategy was used to sample a particular
conclusion allowing us to compute statistics for each sampling frame
independently.&lt;/p&gt;
&lt;h2 id="the-verified-culprits-dataset"&gt;The Verified Culprits
Dataset&lt;/h2&gt;
&lt;p&gt;Using our production culprit finders based on the FACF algorithm and
a verifier implementing the above verification strategy, we have
produced an internal dataset with 144,130 verified conclusions in the
last 60 days, which we use in Section &lt;a href="#sec:evaluation"
data-reference-type="ref" data-reference="sec:evaluation"&gt;5&lt;/a&gt; to
evaluate the performance of the algorithms presented in this paper.
Note, because the evaluation of an algorithm is also expensive, we only
conduct the evaluation on a subset of the whole dataset.&lt;/p&gt;
&lt;p&gt;While we are unable to make the dataset public, we encourage others
to use our verification approach on their own culprit finding systems
and when possible share these datasets with the external community for
use in future studies. Such datasets are not only useful for culprit
finding research but also for fault localization, test prioritization,
test selection, automatic program repair, and other topics.&lt;/p&gt;

&lt;h1 id="sec:evaluation"&gt;Empirical Evaluation&lt;/h1&gt;

&lt;p&gt;We empirically evaluated the behavior of the probabilistic Flake
Aware Culprit Finding (FACF) algorithm, compared it to the traditional
Bisect algorithm &lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;,
evaluated the effectiveness of adding deflaking runs to Bisect, and
evaluated the effectiveness of two optimizations for FACF.&lt;/p&gt;
&lt;h2 id="research-questions"&gt;Research Questions&lt;/h2&gt;
&lt;p&gt;The following research questions were considered. All questions were
considered with respect to the Google environment (see Section &lt;a
href="#sec:dataset" data-reference-type="ref"
data-reference="sec:dataset"&gt;5.5&lt;/a&gt; for more details about the dataset
used).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Which algorithm (FACF or Bisect) was more accurate in identifying
culprit commits?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What difference do algorithmic tweaks (such as adding deflaking
runs to Bisect) make to accuracy.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;How efficient is each algorithm as measured in number of test
executions?&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;What difference do algorithmic tweaks (such as adding deflaking
runs to Bisect) make to efficiency.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Does flakiness affect culprit finding accuracy and cost?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="measuring-culprit-finding-accuracy"&gt;Measuring Culprit Finding
Accuracy&lt;/h2&gt;
&lt;p&gt;To measure the accuracy of the culprit finders we produce a binary
variable (“correct”) which is true if the culprit finder identified
version matched the culprit in the dataset. Accuracy is then defined as
the sample proportion: &lt;span class="math inline"&gt;\(\textbf{ACC} =
\frac{\text{\# correct}}{\text{Total}}\)&lt;/span&gt;. Culprit finder “A” is
judged more accurate than culprit finder “B” if A’s &lt;strong&gt;ACC&lt;/strong&gt;
value is higher than B’s and a statistical test (described in Section &lt;a
href="#sec:stat-tests" data-reference-type="ref"
data-reference="sec:stat-tests"&gt;5.4&lt;/a&gt;) determines the difference is
significant.&lt;/p&gt;
&lt;h2 id="measuring-culprit-finding-cost"&gt;Measuring Culprit Finding
Cost&lt;/h2&gt;
&lt;p&gt;We measure cost as the number of test executions performed by the
algorithm. Culprit finder “A” is judged lower cost than culprit finder
“B” if the mean number of test executions is less than “B” and a
statistical test (described in Section &lt;a href="#sec:stat-tests"
data-reference-type="ref" data-reference="sec:stat-tests"&gt;5.4&lt;/a&gt;)
determines the difference is significant.&lt;/p&gt;
&lt;h2 id="sec:stat-tests"&gt;On Our Usage of Statistical Tests&lt;/h2&gt;
&lt;p&gt;For answering RQ1 and RQ2, we observe the distribution per
culprit-finding algorithm of whether or not the algorithm identified the
culprit (0 or 1). For answering RQ3 and RQ4, we observe the distribution
per culprit-finding algorithm of the number of test executions required
to complete culprit finding.&lt;/p&gt;
&lt;p&gt;We follow the recommendations of McCrum-Gardner &lt;span
class="citation" data-cites="McCrum-Gardner2008"&gt;(&lt;a
href="#ref-McCrum-Gardner2008" role="doc-biblioref"&gt;McCrum-Gardner
2008&lt;/a&gt;)&lt;/span&gt; as well as Walpole &lt;em&gt;et al.&lt;/em&gt; &lt;span
class="citation" data-cites="Walpole2007"&gt;(&lt;a href="#ref-Walpole2007"
role="doc-biblioref"&gt;Walpole 2007&lt;/a&gt;)&lt;/span&gt; as to the proper test
statistics for our analysis. Since data points for a specific culprit
range have a correspondence across algorithms, we perform paired
statistical tests when feasible. The analysis is complicated by the
observation that neither the dichotomous distribution of correctness nor
the numerical distribution of number of test executions are normally
distributed. Following McCrum-Gardner we opt to use non-parametric
tests. Additionally different tests are used for accuracy (dichotomous
nominal variable) and number of executions (numerical variable)
respectively.&lt;/p&gt;
&lt;p&gt;As we have more than 2 groups to consider (10 algorithms), we
initially perform omnibus tests over all algorithms to justify the
existence of statistical significance over all algorithms. In response
to the multiple comparisons problem &lt;span class="citation"
data-cites="Walpole2007"&gt;(&lt;a href="#ref-Walpole2007"
role="doc-biblioref"&gt;Walpole 2007&lt;/a&gt;)&lt;/span&gt;, we compute the corrected
significance bound using the formula for the family-wise error rate. Our
experimental design has us first conduct the ANOVA significance test to
determine if any of the algorithms differed in performance. Then we
conduct post-hoc testing to determine which algorithm’s performance
differed. For each considered question we conduct &lt;span
class="math inline"&gt;\(\binom{10}{2} + 1\)&lt;/span&gt; significance tests. We
have &lt;span class="math inline"&gt;\(6\)&lt;/span&gt; considered questions which
we use significance testing to answer, giving us a total &lt;span
class="math inline"&gt;\(r =
6\left(\binom{10}{2} + 1\right) = 276\)&lt;/span&gt; tests.&lt;/p&gt;
&lt;p&gt;Solving for the &lt;span class="math inline"&gt;\(\alpha\)&lt;/span&gt; in the
experiment-wise error rate formula from Walpole (pg. 529 &lt;span
class="citation" data-cites="Walpole2007"&gt;(&lt;a href="#ref-Walpole2007"
role="doc-biblioref"&gt;Walpole 2007&lt;/a&gt;)&lt;/span&gt;) with &lt;span
class="math inline"&gt;\(p\)&lt;/span&gt; standing for the probability of a false
rejection of at least one hypothesis in the experiment gives: &lt;span
class="math inline"&gt;\(\alpha = 1 - (1 - p)^{\frac{1}{r}}\)&lt;/span&gt;. Given
&lt;span class="math inline"&gt;\(r = 276\)&lt;/span&gt; tests and an intended
experiment-wise error rate of &lt;span class="math inline"&gt;\(p =
0.001\)&lt;/span&gt;, we conservatively arrive at &lt;span
class="math inline"&gt;\(\alpha =
10^{-6}\)&lt;/span&gt; after rounding down to control for family-wise error
rate. We use &lt;span class="math inline"&gt;\(\alpha\)&lt;/span&gt; as our
significance level in all tests.&lt;/p&gt;
&lt;p&gt;Cochran’s Q Test is used for significance testing of the accuracy
distributions and Friedman’s &lt;span
class="math inline"&gt;\(\chi^{2}\)&lt;/span&gt; Test for number of executions.
Post-hoc testing was conducted with McNemar’s test and Wilcoxon Signed
Rank Test respectively.&lt;/p&gt;
&lt;h2 id="sec:dataset"&gt;Evaluation Dataset&lt;/h2&gt;
&lt;p&gt;For the study we used a subset of the dataset produced by the
production Culprit Verifier (described in Section &lt;a
href="#sec:verification" data-reference-type="ref"
data-reference="sec:verification"&gt;4&lt;/a&gt;). The evaluation dataset
consists of 13600 test breakages with their required build flags, search
range of versions, and the verified culprit. The verified culprit may be
an indicator that there was no culprit and detected transition was
caused by a flake. Approximately 60% of the items had a culprit version
and 40% did not (as these were caused by a flaky failure).&lt;/p&gt;

&lt;p&gt;Multiple tests may be broken by the same version. When looking at
unique search ranges, we actually see approximately twice as many flaky
ranges as non-flaky ones. This hints towards having tighter bounds on
which ranges are worth culprit finding as all of the runs for two-thirds
of ranges would have been better utilized on more deflaking runs if
these two categories are accurately discernable.&lt;/p&gt;
&lt;p&gt;We therefore examine the overall dataset for discrepancies between
the two categories. For example, flaky ranges have, on average, 8 tests
failing while non-flaky ranges have 224. For the objective of finding
unique real culprits, we are interested in the minimum flake rate over
targets in a range for flaky and non-flaky ranges, respectively. Fig &lt;a
href="#fig:min-flake-rate" data-reference-type="ref"
data-reference="fig:min-flake-rate"&gt;[fig:min-flake-rate]&lt;/a&gt; shows us
that, in fact, 99% of real culprit ranges have targets below a flake
rate of 75%.&lt;/p&gt;

&lt;h2 id="results"&gt;Results&lt;/h2&gt;

&lt;p&gt;&lt;span id="fig:intervals" label="fig:intervals"&gt;
&lt;a href="images/icst-2023/fig2-4.png"&gt;&lt;img alt="Figure 2-4" src="images/icst-2023/fig2-4.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span id="fig:min-flake-rate" label="fig:min-flake-rate"&gt;
&lt;a href="images/icst-2023/fig5.png"&gt;&lt;img alt="Figure 5" src="images/icst-2023/fig5.png"&gt;&lt;/a&gt;
&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;h3
id="rq1-which-algorithm-facf-or-bisect-was-more-accurate-in-identifying-culprit-commits"&gt;RQ1:
Which algorithm (FACF or Bisect) was more accurate in identifying
culprit commits?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;All versions of FACF were more accurate overall than all versions of
Bisect (Figure &lt;a href="#fig:intervals" data-reference-type="ref"
data-reference="fig:intervals:acc"&gt;2&lt;/a&gt;). The difference was
significant with a p-value &lt;span class="math inline"&gt;\(&amp;lt;
10^{-12}\)&lt;/span&gt;, below the adjusted &lt;span
class="math inline"&gt;\(10^{-6}\)&lt;/span&gt; significance level required.&lt;/p&gt;
&lt;p&gt;&lt;h3
id="rq2-what-difference-do-algorithmic-tweaks-such-as-adding-deflaking-runs-to-bisect-make-to-accuracy"&gt;RQ2:
What difference do algorithmic tweaks (such as adding deflaking runs to
Bisect) make to accuracy?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;The production version of FACF, FACF(all), was most accurate and
significantly different than all other algorithms (Figure &lt;a
href="#fig:intervals" data-reference-type="ref"
data-reference="fig:intervals:acc"&gt;2&lt;/a&gt;). This was followed by
FACF(fr=.1) which set the floor of 10% on the estimated flake rate for
tests. The other FACF variants were equally accurate.&lt;/p&gt;
&lt;p&gt;&lt;h3
id="rq3-how-efficient-is-each-algorithm-as-measured-in-number-of-test-executions"&gt;RQ3:
How efficient is each algorithm as measured in number of test
executions?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;Figure &lt;a href="#fig:intervals" data-reference-type="ref"
data-reference="fig:intervals:builds"&gt;2&lt;/a&gt; shows the most efficient
algorithm was unsurprisingly Bisect(1) which does not attempt to do any
extra executions to deflake test failures. The next most efficient
algorithm was FACF(all) which was also the most accurate. As can be seen
in the boxplot in Figure &lt;a href="#fig:intervals"
data-reference-type="ref" data-reference="fig:intervals:builds"&gt;2&lt;/a&gt;,
the FACF variants tend to have many more extreme outliers in their cost
distribution than the Bisect variants. This is because they account for
the prior flake rate. An organization may control their cost by not
culprit finding tests which are more than (for instance) 50% flaky. No
such upper bound was established for this experiment.&lt;/p&gt;
&lt;p&gt;&lt;h3
id="rq4-what-difference-do-algorithmic-tweaks-such-as-adding-deflaking-runs-to-bisect-make-to-efficiency"&gt;RQ4:
What difference do algorithmic tweaks (such as adding deflaking runs to
Bisect) make to efficiency?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;First, both FACF(all) and FACF(priors) had less cost than the
standard FACF. This indicates that while FACF(priors) does not improve
accuracy it does improve efficiency of the algorithm. In particular many
more culprits were found with just two builds.&lt;/p&gt;
&lt;p&gt;Second, FACF(heur-thresholds) had no significant effect on cost nor
did it show any improvement accuracy. We conclude that although the
mathematical motivation may be sound, in the Google environment, we
cannot validate a benefit to this optimization at this time.&lt;/p&gt;
&lt;p&gt;&lt;h3
id="rq5-does-flakiness-affect-culprit-finding-accuracy-and-cost"&gt;RQ5:
Does flakiness affect culprit finding accuracy and cost?&lt;/h3&gt;&lt;/p&gt;
&lt;p&gt;Figures &lt;a href="#fig:intervals" data-reference-type="ref"
data-reference="fig:intervals"&gt;3&lt;/a&gt; and &lt;a
href="#fig:intervals" data-reference-type="ref"
data-reference="fig:intervals"&gt;4&lt;/a&gt; show the
accuracy and cost of culprit finding flaky and non-flaky culprits. For
search ranges without a culprit, FACF(all) clearly dominates Bisect in
accuracy and even has a small advantage in cost over Bisect(1).&lt;/p&gt;
&lt;p&gt;When there is a culprit, the FACF variants are all more accurate than
the Bisect variants according to the statistical tests. However, the
difference is much less pronounced with Bisect(1) accuracy &lt;span
class="math inline"&gt;\(\sim\)&lt;/span&gt;96.1% and FACF(all) accuracy &lt;span
class="math inline"&gt;\(\sim\)&lt;/span&gt;97.5%. In terms of cost, Bisect(1)
and Bisect(2) are the most efficient followed by the FACF variants.&lt;/p&gt;
&lt;p&gt;We will note, a production culprit finder cannot know a priori if a
breakage was caused by a flake. It would need to do deflaking runs to
establish that, costing approximately &lt;span
class="math inline"&gt;\(\left\lceil{\frac{\,\textrm{log}\!\!\left({p}\right)}{\,\textrm{log}\!\!\left({\hat{f}_t}\right)}}\right\rceil\)&lt;/span&gt;
where &lt;span class="math inline"&gt;\(p\)&lt;/span&gt; is your desired confidence
level. For &lt;span class="math inline"&gt;\(p=10^{-4}\)&lt;/span&gt; and &lt;span
class="math inline"&gt;\(\hat{f} = .2\)&lt;/span&gt;, this amounts to 6 extra
runs, which would significantly increase the cost of bisection. However,
as noted in Section &lt;a href="#sec:dataset" data-reference-type="ref"
data-reference="sec:dataset"&gt;5.5&lt;/a&gt;, prior flakiness rates could be
used to prune out a significant portion of flaky ranges (lowering cost)
with a minimal hit to accuracy.&lt;/p&gt;

&lt;h1 id="related-work"&gt;Related Work&lt;/h1&gt;
&lt;h2 id="culprit-finding"&gt;Culprit Finding&lt;/h2&gt;
&lt;p&gt;Despite its industrial importance, culprit finding has been
relatively less studied in the literature in comparison to topics such
as Fault Localization &lt;span class="citation"
data-cites="Agarwal2014 Wong2016"&gt;(&lt;a href="#ref-Agarwal2014"
role="doc-biblioref"&gt;Agarwal and Agrawal 2014&lt;/a&gt;; &lt;a
href="#ref-Wong2016" role="doc-biblioref"&gt;Wong et al. 2016&lt;/a&gt;)&lt;/span&gt;
(coverage based &lt;span class="citation"
data-cites="Jones2002 Jones2005 Lucia2014 Henderson2018 Henderson2019 Kucuk2021"&gt;(&lt;a
href="#ref-Jones2002" role="doc-biblioref"&gt;J. a. Jones, Harrold, and
Stasko 2002&lt;/a&gt;; &lt;a href="#ref-Jones2005" role="doc-biblioref"&gt;J. A.
Jones and Harrold 2005&lt;/a&gt;; &lt;a href="#ref-Lucia2014"
role="doc-biblioref"&gt;Lucia et al. 2014&lt;/a&gt;; &lt;a href="#ref-Henderson2018"
role="doc-biblioref"&gt;Henderson and Podgurski 2018&lt;/a&gt;; &lt;a
href="#ref-Henderson2019" role="doc-biblioref"&gt;Henderson, Podgurski, and
Kucuk 2019&lt;/a&gt;; &lt;a href="#ref-Kucuk2021" role="doc-biblioref"&gt;Kucuk,
Henderson, and Podgurski 2021&lt;/a&gt;)&lt;/span&gt;, information retrieval based
&lt;span class="citation" data-cites="Zhou2012 Youm2015 Ciborowska2022"&gt;(&lt;a
href="#ref-Zhou2012" role="doc-biblioref"&gt;J. Zhou, Zhang, and Lo
2012&lt;/a&gt;; &lt;a href="#ref-Youm2015" role="doc-biblioref"&gt;Youm et al.
2015&lt;/a&gt;; &lt;a href="#ref-Ciborowska2022" role="doc-biblioref"&gt;Ciborowska
and Damevski 2022&lt;/a&gt;)&lt;/span&gt;, or slicing based &lt;span class="citation"
data-cites="Podgurski1990 Horwitz1992 Ren2004"&gt;(&lt;a
href="#ref-Podgurski1990" role="doc-biblioref"&gt;Podgurski and Clarke
1990&lt;/a&gt;; &lt;a href="#ref-Horwitz1992" role="doc-biblioref"&gt;Horwitz and
Reps 1992&lt;/a&gt;; &lt;a href="#ref-Ren2004" role="doc-biblioref"&gt;Ren et al.
2004&lt;/a&gt;)&lt;/span&gt;), Bug Prediction &lt;span class="citation"
data-cites="Lewis2013 Punitha2013 Osman2017"&gt;(&lt;a href="#ref-Lewis2013"
role="doc-biblioref"&gt;Lewis et al. 2013&lt;/a&gt;; &lt;a href="#ref-Punitha2013"
role="doc-biblioref"&gt;Punitha and Chitra 2013&lt;/a&gt;; &lt;a
href="#ref-Osman2017" role="doc-biblioref"&gt;Osman et al.
2017&lt;/a&gt;)&lt;/span&gt;, Test Selection &lt;span class="citation"
data-cites="Engstrom2010 pan2022"&gt;(&lt;a href="#ref-Engstrom2010"
role="doc-biblioref"&gt;Engström, Runeson, and Skoglund 2010&lt;/a&gt;; &lt;a
href="#ref-pan2022" role="doc-biblioref"&gt;Pan et al. 2022&lt;/a&gt;)&lt;/span&gt;,
Test Prioritization &lt;span class="citation"
data-cites="DeS.CamposJunior2017 pan2022"&gt;(&lt;a
href="#ref-DeS.CamposJunior2017" role="doc-biblioref"&gt;de S. Campos
Junior et al. 2017&lt;/a&gt;; &lt;a href="#ref-pan2022" role="doc-biblioref"&gt;Pan
et al. 2022&lt;/a&gt;)&lt;/span&gt; and the SZZ algorithm for identifying bug
inducing commits in the context of research studies &lt;span
class="citation"
data-cites="Sliwerski2005 Rodriguez-Perez2018 Borg2019 Wen2019"&gt;(&lt;a
href="#ref-Sliwerski2005" role="doc-biblioref"&gt;Śliwerski, Zimmermann,
and Zeller 2005&lt;/a&gt;; &lt;a href="#ref-Rodriguez-Perez2018"
role="doc-biblioref"&gt;Rodríguez-Pérez, Robles, and González-Barahona
2018&lt;/a&gt;; &lt;a href="#ref-Borg2019" role="doc-biblioref"&gt;Borg et al.
2019&lt;/a&gt;; &lt;a href="#ref-Wen2019" role="doc-biblioref"&gt;Wen et al.
2019&lt;/a&gt;)&lt;/span&gt;. This is perhaps understandable as the problem only
emerges in environments were it becomes to costly to run every test at
every code submission.&lt;/p&gt;
&lt;p&gt;The idea of using a binary search to locate the culprit is common,
but it is not completely clear who invented it first. The Christian
Couder of &lt;code&gt;git bisect&lt;/code&gt; wrote a comprehensive paper on its
implementation &lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt; but
indicates there are other similar tools: “So what are the tools used to
fight regressions? [...] The only specific tools are test suites and
tools similar to &lt;code&gt;git bisect&lt;/code&gt;.” The first version of the
&lt;code&gt;git bisect&lt;/code&gt; command appears to have been written by Linus
Torvalds in 2005.&lt;a href="#fn5" class="footnote-ref" id="fnref5"
role="doc-noteref"&gt;&lt;sup&gt;5&lt;/sup&gt;&lt;/a&gt; Torvald’s commit message simply
states “This is useful for doing binary searching for problems.” The
source code for the mercurial bisect command &lt;code&gt;hg bisect&lt;/code&gt;
states that it was inspired by the git command.&lt;a href="#fn6"
class="footnote-ref" id="fnref6" role="doc-noteref"&gt;&lt;sup&gt;6&lt;/sup&gt;&lt;/a&gt; The
Subversion (SVN) command, &lt;code&gt;svn bisect&lt;/code&gt;, also cites the git
command as inspiration.&lt;a href="#fn7" class="footnote-ref" id="fnref7"
role="doc-noteref"&gt;&lt;sup&gt;7&lt;/sup&gt;&lt;/a&gt; Therefore, as far as the authors can
tell bisection for finding culprits appears to have been invented by
Torvalds.&lt;/p&gt;
&lt;p&gt;The Couder paper &lt;span class="citation" data-cites="Couder2008"&gt;(&lt;a
href="#ref-Couder2008" role="doc-biblioref"&gt;Couder 2008&lt;/a&gt;)&lt;/span&gt;
cites a GitHub repository for a program called “BBChop,” which is
lightly documented and appears not entirely completed by a user
enigmatically named Ealdwulf Wuffinga (likely a pseudonym, as that was a
name of the King of East Anglia from 664-713).&lt;a href="#fn8"
class="footnote-ref" id="fnref8" role="doc-noteref"&gt;&lt;sup&gt;8&lt;/sup&gt;&lt;/a&gt;
This program claims to have also implemented a Bayesian search for
culprits. We gladly cede the throne for first invention of applying
Bayes rule to culprit finding to Ealdwulf and note that our invention
was independent of the work in BBChop.&lt;/p&gt;
&lt;p&gt;More recently, work has been emerging on the industrial practice of
Culprit Finding. In 2013, Ziftci and Ramavajjala gave a public talk at
the Google Test Automation Conference in on Culprit Finding at Google
&lt;span class="citation" data-cites="Ziftci2013a"&gt;(&lt;a
href="#ref-Ziftci2013a" role="doc-biblioref"&gt;Ziftci and Ramavajjala
2013&lt;/a&gt;)&lt;/span&gt;. They note, that by 2013 Google has already been using
&lt;span class="math inline"&gt;\(m\)&lt;/span&gt;-ary bisection based culprit
finding for “small” and “medium” tests. They then give a preview of an
approach elaborated on in Ziftci and Reardon’s 2017 paper &lt;span
class="citation" data-cites="Ziftci2017"&gt;(&lt;a href="#ref-Ziftci2017"
role="doc-biblioref"&gt;Ziftci and Reardon 2017&lt;/a&gt;)&lt;/span&gt; for culprit
finding integration tests where test executions take a long time to run.
The authors propose a suspiciousness metric based on the minimum build
dependence distance and conduct a case study on the efficacy of using
such a metric to surface potential culprits to developers. We utilize a
similar build dependence distance as input to construct a prior
probability (see Section &lt;a href="#sec:priors" data-reference-type="ref"
data-reference="sec:priors"&gt;3.3&lt;/a&gt;) in this work but do not directly
surface the metric to our end users. Finally, for ground truth they rely
on the developers to report what the culprit version is. In contrast,
the empirical evaluation we present in this new work is fully automated
and does not rely on developers.&lt;/p&gt;
&lt;p&gt;In 2017, Saha and Gligoric &lt;span class="citation"
data-cites="Saha2017"&gt;(&lt;a href="#ref-Saha2017" role="doc-biblioref"&gt;Saha
and Gligoric 2017&lt;/a&gt;)&lt;/span&gt; proposed accelerating the traditional
bisect algorithm via Test Selection techniques. They use Coverage Based
Test Selection &lt;span class="citation" data-cites="Zhou2010 Musa2015"&gt;(&lt;a
href="#ref-Zhou2010" role="doc-biblioref"&gt;Z. Q. Zhou 2010&lt;/a&gt;; &lt;a
href="#ref-Musa2015" role="doc-biblioref"&gt;Musa et al. 2015&lt;/a&gt;)&lt;/span&gt;
to choose which commits are most likely to affect the test results at
the failing commit. This technique can be viewed as fine grained,
dynamic version of the static build dependence selection strategy we
employ at Google.&lt;/p&gt;
&lt;p&gt;In 2019, Najafi &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"
data-cites="Najafi2019a"&gt;(&lt;a href="#ref-Najafi2019a"
role="doc-biblioref"&gt;Najafi, Rigby, and Shang 2019&lt;/a&gt;)&lt;/span&gt; looked at
a similar problem to the traditional culprit finding problem we examine
here. In their scenario, there is a submission queue that queues up
commits to integrate into the main development branch. It batches these
waiting commits and tests them together. If a test fails, they need to
culprit find to determine the culprit commit. The authors evaluate using
a ML-driven risk based batching approach. In 2022, the same research
group re-evaluated the 2019 paper on an open source dataset in
Beheshtian &lt;em&gt;et al.&lt;/em&gt;’s 2022 paper &lt;span class="citation"
data-cites="Beheshtian2022"&gt;(&lt;a href="#ref-Beheshtian2022"
role="doc-biblioref"&gt;Beheshtian, Bavand, and Rigby 2022&lt;/a&gt;)&lt;/span&gt;.
They found that in the new environment the risk based batching didn’t do
as well as a new and improved combinatorics based batching scheme for
identifying the culprit commits.&lt;/p&gt;
&lt;p&gt;James Keenan gave a presentation in 2019 at the Perl Conference in
which he presented a concept, &lt;em&gt;multisection&lt;/em&gt;, for dealing with
multiple bugs in the same search range &lt;span class="citation"
data-cites="keenan2019"&gt;(&lt;a href="#ref-keenan2019"
role="doc-biblioref"&gt;Keenan 2019&lt;/a&gt;)&lt;/span&gt;. Ideally, industrial
culprit finders would automatically detect that there are multiple
distinct bug inducing commits.&lt;/p&gt;
&lt;p&gt;In 2021, two papers looked at using coverage based data for
accelerating bug localization. An and Yoo &lt;span class="citation"
data-cites="An2021"&gt;(&lt;a href="#ref-An2021" role="doc-biblioref"&gt;An and
Yoo 2021&lt;/a&gt;)&lt;/span&gt; used coverage data to accelerate both bisection and
SZZ &lt;span class="citation" data-cites="Sliwerski2005"&gt;(&lt;a
href="#ref-Sliwerski2005" role="doc-biblioref"&gt;Śliwerski, Zimmermann,
and Zeller 2005&lt;/a&gt;)&lt;/span&gt; and found significant speedups. Wen &lt;em&gt;et
al.&lt;/em&gt; &lt;span class="citation" data-cites="Wen2021"&gt;(&lt;a
href="#ref-Wen2021" role="doc-biblioref"&gt;Wen et al. 2021&lt;/a&gt;)&lt;/span&gt;
combined traditional Coverage Based Statistical Fault Localization &lt;span
class="citation" data-cites="Jones2002"&gt;(&lt;a href="#ref-Jones2002"
role="doc-biblioref"&gt;J. a. Jones, Harrold, and Stasko 2002&lt;/a&gt;)&lt;/span&gt;
with historical information to create a new suspiciousness score &lt;span
class="citation" data-cites="Sun2016"&gt;(&lt;a href="#ref-Sun2016"
role="doc-biblioref"&gt;Sun and Podgurski 2016&lt;/a&gt;)&lt;/span&gt;. This fault
localization method could be used in a culprit finding context by using
the line rankings to rank the commits.&lt;/p&gt;
&lt;p&gt;Finally, in 2022 Frolin Ocariza &lt;span class="citation"
data-cites="Ocariza2022"&gt;(&lt;a href="#ref-Ocariza2022"
role="doc-biblioref"&gt;Ocariza 2022&lt;/a&gt;)&lt;/span&gt; published a paper on
bisecting performance regressions. There are strong connections between
a flaky test and a performance regression as a performance regression
may not happen 100% of the time. Furthermore, the “baseline” version may
randomly have poor performance due to environmental or other factors.
Ocariza also arrives at a probabilistic approach, using a Bayesian model
to determine whether a run at a particular version is exhibiting the
performance regression or not. While mathematically related to our work
here and complementary, the approach is distinct. The authors note that
their technique can be combined with a Noisy Binary Search citing Karp
&lt;span class="citation" data-cites="Karp2007"&gt;(&lt;a href="#ref-Karp2007"
role="doc-biblioref"&gt;Karp and Kleinberg 2007&lt;/a&gt;)&lt;/span&gt; or with a
multisection search citing Keenan &lt;span class="citation"
data-cites="keenan2019"&gt;(&lt;a href="#ref-keenan2019"
role="doc-biblioref"&gt;Keenan 2019&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="noisy-binary-search"&gt;Noisy Binary Search&lt;/h2&gt;
&lt;p&gt;There is a vast literature on Rényi-Ulam games and Noisy Searching
problems (doubly so when considering their connection to error
correcting codes)! We direct readers to the Pelc survey &lt;span
class="citation" data-cites="Pelc2002"&gt;(&lt;a href="#ref-Pelc2002"
role="doc-biblioref"&gt;Pelc 2002&lt;/a&gt;)&lt;/span&gt; as a starting point. We will
highlight a few articles here. First and foremost, the Ben Or and
Hassidim paper &lt;span class="citation" data-cites="Ben-Or2008"&gt;(&lt;a
href="#ref-Ben-Or2008" role="doc-biblioref"&gt;Ben-Or and Hassidim
2008&lt;/a&gt;)&lt;/span&gt; from 2008 most clearly explains the problem in terms of
a Bayesian inference, which is the formulation we use here. Second,
Waeber &lt;em&gt;et al.&lt;/em&gt; in 2013 &lt;span class="citation"
data-cites="Waeber2013"&gt;(&lt;a href="#ref-Waeber2013"
role="doc-biblioref"&gt;Waeber, Frazier, and Henderson 2013&lt;/a&gt;)&lt;/span&gt;
discuss the theoretical foundations of these &lt;em&gt;probabilistic bisection
algorithms&lt;/em&gt;. Finally, according to Waeber, Horstein first described
this algorithm in the context of error correcting codes in 1963 &lt;span
class="citation" data-cites="Horstein1963"&gt;(&lt;a href="#ref-Horstein1963"
role="doc-biblioref"&gt;Horstein 1963&lt;/a&gt;)&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id="sec:conclusion"&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Flake Aware Culprit Finding (FACF) is both accurate, efficient, and
able to flexibly incorporate prior information on the location of a
culprit. A large scale empirical study on real test and build breakages
found FACF to be significantly more effective than a traditional
bisection search while not increasing cost over a deflaked
bisection.&lt;/p&gt;

&lt;h1 id="sec:refereces"&gt;References&lt;/h1&gt;
&lt;div id="refs" class="references csl-bib-body hanging-indent"
role="doc-bibliography"&gt;
&lt;ol&gt;
&lt;li&gt;&lt;div id="ref-Agarwal2014" class="csl-entry" role="doc-biblioentry"&gt;
Agarwal, Pragya, and Arun Prakash Agrawal. 2014.
&lt;span&gt;“Fault-Localization &lt;span&gt;Techniques&lt;/span&gt; for &lt;span&gt;Software
Systems&lt;/span&gt;: &lt;span&gt;A Literature Review&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;SIGSOFT
Softw. Eng. Notes&lt;/em&gt; 39 (5): 1–8. &lt;a
href="https://doi.org/10.1145/2659118.2659125"&gt;https://doi.org/10.1145/2659118.2659125&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-An2021" class="csl-entry" role="doc-biblioentry"&gt;
An, Gabin, and Shin Yoo. 2021. &lt;span&gt;“Reducing the Search Space of Bug
Inducing Commits Using Failure Coverage.”&lt;/span&gt; In &lt;em&gt;Proceedings of
the 29th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on &lt;span&gt;European Software
Engineering Conference&lt;/span&gt; and &lt;span&gt;Symposium&lt;/span&gt; on the
&lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;,
1459–62. &lt;span&gt;Athens Greece&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3468264.3473129"&gt;https://doi.org/10.1145/3468264.3473129&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ananthanarayanan2019" class="csl-entry"
role="doc-biblioentry"&gt;
Ananthanarayanan, Sundaram, Masoud Saeida Ardekani, Denis Haenikel,
Balaji Varadarajan, Simon Soriano, Dhaval Patel, and Ali Reza
Adl-Tabatabai. 2019. &lt;span&gt;“Keeping Master Green at Scale.”&lt;/span&gt;
&lt;em&gt;Proceedings of the 14th EuroSys Conference 2019&lt;/em&gt;. &lt;a
href="https://doi.org/10.1145/3302424.3303970"&gt;https://doi.org/10.1145/3302424.3303970&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Beheshtian2022" class="csl-entry" role="doc-biblioentry"&gt;
Beheshtian, Mohammad Javad, Amir Hossein Bavand, and Peter C. Rigby.
2022. &lt;span&gt;“Software &lt;span&gt;Batch Testing&lt;/span&gt; to &lt;span&gt;Save Build
Test Resources&lt;/span&gt; and to &lt;span&gt;Reduce Feedback Time&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt; 48 (8): 2784–2801. &lt;a
href="https://doi.org/10.1109/TSE.2021.3070269"&gt;https://doi.org/10.1109/TSE.2021.3070269&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ben-Or2008" class="csl-entry" role="doc-biblioentry"&gt;
Ben-Or, Michael, and Avinatan Hassidim. 2008. &lt;span&gt;“The &lt;span&gt;Bayesian
Learner&lt;/span&gt; Is &lt;span&gt;Optimal&lt;/span&gt; for &lt;span&gt;Noisy Binary
Search&lt;/span&gt; (and &lt;span&gt;Pretty Good&lt;/span&gt; for &lt;span&gt;Quantum&lt;/span&gt; as
&lt;span&gt;Well&lt;/span&gt;).”&lt;/span&gt; In &lt;em&gt;2008 49th &lt;span&gt;Annual IEEE
Symposium&lt;/span&gt; on &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Computer
Science&lt;/span&gt;&lt;/em&gt;, 221–30. &lt;span&gt;Philadelphia, PA, USA&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/FOCS.2008.58"&gt;https://doi.org/10.1109/FOCS.2008.58&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Bhattacharya2010" class="csl-entry" role="doc-biblioentry"&gt;
Bhattacharya, Pamela, and Iulian Neamtiu. 2010. &lt;span&gt;“Fine-Grained
Incremental Learning and Multi-Feature Tossing Graphs to Improve Bug
Triaging.”&lt;/span&gt; In &lt;em&gt;2010 &lt;span&gt;IEEE International Conference&lt;/span&gt;
on &lt;span&gt;Software Maintenance&lt;/span&gt;&lt;/em&gt;, 1–10. &lt;span&gt;Timi oara,
Romania&lt;/span&gt;: &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSM.2010.5609736"&gt;https://doi.org/10.1109/ICSM.2010.5609736&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Binkley1992" class="csl-entry" role="doc-biblioentry"&gt;
Binkley, D. 1992. &lt;span&gt;“Using Semantic Differencing to Reduce the Cost
of Regression Testing.”&lt;/span&gt; In &lt;em&gt;Proceedings
&lt;span&gt;Conference&lt;/span&gt; on &lt;span&gt;Software Maintenance&lt;/span&gt; 1992&lt;/em&gt;,
41–50. &lt;span&gt;Orlando, FL, USA&lt;/span&gt;: &lt;span&gt;IEEE Comput. Soc.
Press&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSM.1992.242560"&gt;https://doi.org/10.1109/ICSM.1992.242560&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Borg2019" class="csl-entry" role="doc-biblioentry"&gt;
Borg, Markus, Oscar Svensson, Kristian Berg, and Daniel Hansson. 2019.
&lt;span&gt;“&lt;span&gt;SZZ&lt;/span&gt; Unleashed: An Open Implementation of the
&lt;span&gt;SZZ&lt;/span&gt; Algorithm - Featuring Example Usage in a Study of
Just-in-Time Bug Prediction for the &lt;span&gt;Jenkins&lt;/span&gt;
Project.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 3rd &lt;span&gt;ACM SIGSOFT
International Workshop&lt;/span&gt; on &lt;span&gt;Machine Learning
Techniques&lt;/span&gt; for &lt;span&gt;Software Quality Evaluation&lt;/span&gt; -
&lt;span&gt;MaLTeSQuE&lt;/span&gt; 2019&lt;/em&gt;, 7–12. &lt;span&gt;Tallinn, Estonia&lt;/span&gt;:
&lt;span&gt;ACM Press&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3340482.3342742"&gt;https://doi.org/10.1145/3340482.3342742&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ciborowska2022" class="csl-entry" role="doc-biblioentry"&gt;
Ciborowska, Agnieszka, and Kostadin Damevski. 2022. &lt;span&gt;“Fast
Changeset-Based Bug Localization with &lt;span&gt;BERT&lt;/span&gt;.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 44th &lt;span&gt;International Conference&lt;/span&gt; on
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 946–57. &lt;span&gt;Pittsburgh
Pennsylvania&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3510003.3510042"&gt;https://doi.org/10.1145/3510003.3510042&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Couder2008" class="csl-entry" role="doc-biblioentry"&gt;
Couder, Christian. 2008. &lt;span&gt;“Fighting Regressions with Git
Bisect.”&lt;/span&gt; &lt;em&gt;The Linux Kernel Archives&lt;/em&gt; 4 (5). &lt;a
href="https://www. kernel. org/pub/software/scm/git/doc s/git-
                  bisect-lk2009.html"&gt;https://www. kernel.
org/pub/software/scm/git/doc s/git- bisect-lk2009.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-DeS.CamposJunior2017" class="csl-entry"
role="doc-biblioentry"&gt;
de S. Campos Junior, Heleno, Marco Antônio P Araújo, José Maria N David,
Regina Braga, Fernanda Campos, and Victor Ströele. 2017. &lt;span&gt;“Test
&lt;span&gt;Case Prioritization&lt;/span&gt;: &lt;span&gt;A Systematic Review&lt;/span&gt; and
&lt;span&gt;Mapping&lt;/span&gt; of the &lt;span&gt;Literature&lt;/span&gt;.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 31st &lt;span&gt;Brazilian Symposium&lt;/span&gt; on
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 34–43. &lt;span&gt;New York, NY,
USA&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3131151.3131170"&gt;https://doi.org/10.1145/3131151.3131170&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Engstrom2010" class="csl-entry" role="doc-biblioentry"&gt;
Engström, Emelie, Per Runeson, and Mats Skoglund. 2010. &lt;span&gt;“A
Systematic Review on Regression Test Selection Techniques.”&lt;/span&gt;
&lt;em&gt;Information and Software Technology&lt;/em&gt; 52 (1): 14–30. &lt;a
href="https://doi.org/10.1016/j.infsof.2009.07.001"&gt;https://doi.org/10.1016/j.infsof.2009.07.001&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Fowler2006" class="csl-entry" role="doc-biblioentry"&gt;
Fowler, Martin. 2006. &lt;span&gt;“Continuous
&lt;span&gt;Integration&lt;/span&gt;.”&lt;/span&gt; &lt;a
href="https://martinfowler.com/articles/
                  continuousIntegration.html"&gt;https://martinfowler.com/articles/
continuousIntegration.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Gupta2011" class="csl-entry" role="doc-biblioentry"&gt;
Gupta, Pooja, Mark Ivey, and John Penix. 2011. &lt;span&gt;“Testing at the
Speed and Scale of &lt;span&gt;Google&lt;/span&gt;.”&lt;/span&gt; &lt;a
href="http://google-engtools.blogspot.com/2011/06/testing-at-
                  speed-and-scale-of-google.html"&gt;http://google-engtools.blogspot.com/2011/06/testing-at-
speed-and-scale-of-google.html&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Henderson2018" class="csl-entry" role="doc-biblioentry"&gt;
Henderson, Tim A. D., and Andy Podgurski. 2018. &lt;span&gt;“Behavioral
&lt;span&gt;Fault Localization&lt;/span&gt; by &lt;span&gt;Sampling Suspicious Dynamic
Control Flow Subgraphs&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2018 &lt;span&gt;IEEE&lt;/span&gt;
11th &lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Software
Testing&lt;/span&gt;, &lt;span&gt;Verification&lt;/span&gt; and &lt;span&gt;Validation&lt;/span&gt;
(&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;, 93–104. &lt;span&gt;Vasteras&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICST.2018.00019"&gt;https://doi.org/10.1109/ICST.2018.00019&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Henderson2019" class="csl-entry" role="doc-biblioentry"&gt;
Henderson, Tim A. D., Andy Podgurski, and Yigit Kucuk. 2019.
&lt;span&gt;“Evaluating &lt;span&gt;Automatic Fault Localization Using Markov
Processes&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019 19th &lt;span&gt;International Working
Conference&lt;/span&gt; on &lt;span&gt;Source Code Analysis&lt;/span&gt; and
&lt;span&gt;Manipulation&lt;/span&gt; (&lt;span&gt;SCAM&lt;/span&gt;)&lt;/em&gt;, 115–26.
&lt;span&gt;Cleveland, OH, USA&lt;/span&gt;: &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/SCAM.2019.00021"&gt;https://doi.org/10.1109/SCAM.2019.00021&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Herzig2015" class="csl-entry" role="doc-biblioentry"&gt;
Herzig, Kim, Michaela Greiler, Jacek Czerwonka, and Brendan Murphy.
2015. &lt;span&gt;“The &lt;span&gt;Art&lt;/span&gt; of &lt;span&gt;Testing Less&lt;/span&gt; Without
&lt;span&gt;Sacrificing Quality&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2015
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 37th &lt;span&gt;IEEE International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, 1:483–93.
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE.2015.66"&gt;https://doi.org/10.1109/ICSE.2015.66&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Herzig2015a" class="csl-entry" role="doc-biblioentry"&gt;
Herzig, Kim, and Nachiappan Nagappan. 2015. &lt;span&gt;“Empirically
&lt;span&gt;Detecting False Test Alarms Using Association
Rules&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2015 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt;
37th &lt;span&gt;IEEE International Conference&lt;/span&gt; on &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 39–48. &lt;span&gt;Florence, Italy&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE.2015.133"&gt;https://doi.org/10.1109/ICSE.2015.133&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Horstein1963" class="csl-entry" role="doc-biblioentry"&gt;
Horstein, M. 1963. &lt;span&gt;“Sequential Transmission Using Noiseless
Feedback.”&lt;/span&gt; &lt;em&gt;IEEE Transactions on Information Theory&lt;/em&gt; 9
(3): 136–43. &lt;a
href="https://doi.org/10.1109/TIT.1963.1057832"&gt;https://doi.org/10.1109/TIT.1963.1057832&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Horwitz1992" class="csl-entry" role="doc-biblioentry"&gt;
Horwitz, S, and T Reps. 1992. &lt;span&gt;“The Use of Program Dependence
Graphs in Software Engineering.”&lt;/span&gt; In &lt;em&gt;International
&lt;span&gt;Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;,
9:349. &lt;span&gt;Springer&lt;/span&gt;. &lt;a
href="http://portal.acm.org/citation.cfm?id=24041&amp;amp;amp;dl="&gt;http://portal.acm.org/citation.cfm?id=24041&amp;amp;amp;dl=&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Jones2002" class="csl-entry" role="doc-biblioentry"&gt;
Jones, J.a., M. J. Harrold, and J. Stasko. 2002. &lt;span&gt;“Visualization of
Test Information to Assist Fault Localization.”&lt;/span&gt; &lt;em&gt;Proceedings
of the 24th International Conference on Software Engineering. ICSE
2002&lt;/em&gt;. &lt;a
href="https://doi.org/10.1145/581339.581397"&gt;https://doi.org/10.1145/581339.581397&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Jones2005" class="csl-entry" role="doc-biblioentry"&gt;
Jones, James A., and Mary Jean Harrold. 2005. &lt;span&gt;“Empirical
&lt;span&gt;Evaluation&lt;/span&gt; of the &lt;span class="nocase"&gt;Tarantula Automatic
Fault-localization Technique&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the
20th &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM International Conference&lt;/span&gt; on
&lt;span&gt;Automated Software Engineering&lt;/span&gt;&lt;/em&gt;, 273–82. &lt;span&gt;New
York, NY, USA&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/1101908.1101949"&gt;https://doi.org/10.1145/1101908.1101949&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Just2014" class="csl-entry" role="doc-biblioentry"&gt;
Just, René, Darioush Jalali, and Michael D Ernst. 2014.
&lt;span&gt;“&lt;span&gt;Defects4J&lt;/span&gt;: &lt;span&gt;A Database&lt;/span&gt; of &lt;span&gt;Existing
Faults&lt;/span&gt; to &lt;span&gt;Enable Controlled Testing Studies&lt;/span&gt; for
&lt;span&gt;Java Programs&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 2014
&lt;span&gt;International Symposium&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;
and &lt;span&gt;Analysis&lt;/span&gt;&lt;/em&gt;, 437–40. &lt;span&gt;New York, NY, USA&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/2610384.2628055"&gt;https://doi.org/10.1145/2610384.2628055&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Karp2007" class="csl-entry" role="doc-biblioentry"&gt;
Karp, Richard M., and Robert Kleinberg. 2007. &lt;span&gt;“Noisy Binary Search
and Its Applications.”&lt;/span&gt; In &lt;em&gt;Proceedings of the Eighteenth
Annual &lt;span&gt;ACM-SIAM&lt;/span&gt; Symposium on Discrete Algorithms&lt;/em&gt;,
881–90. &lt;span&gt;SODA&lt;/span&gt; ’07. &lt;span&gt;USA&lt;/span&gt;: &lt;span&gt;Society for
Industrial and Applied Mathematics&lt;/span&gt;. &lt;a
href="https://dl.acm.org/doi/abs/10.5555/1283383.1283478"&gt;https://dl.acm.org/doi/abs/10.5555/1283383.1283478&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-keenan2019" class="csl-entry" role="doc-biblioentry"&gt;
Keenan, James. 2019. &lt;span&gt;“James &lt;span&gt;E&lt;/span&gt;. &lt;span&gt;Keenan&lt;/span&gt; -
"&lt;span&gt;Multisection&lt;/span&gt;: &lt;span&gt;When Bisection Isn&lt;/span&gt;’t
&lt;span&gt;Enough&lt;/span&gt; to &lt;span&gt;Debug&lt;/span&gt; a
&lt;span&gt;Problem&lt;/span&gt;".”&lt;/span&gt; &lt;a
href="https://www.youtube.com/watch?v=05CwdTRt6AM"&gt;https://www.youtube.com/watch?v=05CwdTRt6AM&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Kowalczyk2020" class="csl-entry" role="doc-biblioentry"&gt;
Kowalczyk, Emily, Karan Nair, Zebao Gao, Leo Silberstein, Teng Long, and
Atif Memon. 2020. &lt;span&gt;“Modeling and Ranking Flaky Tests at
&lt;span&gt;Apple&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the
&lt;span&gt;ACM&lt;/span&gt;/&lt;span&gt;IEEE&lt;/span&gt; 42nd &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;&lt;/em&gt;, 110–19. &lt;span&gt;Seoul
South Korea&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3377813.3381370"&gt;https://doi.org/10.1145/3377813.3381370&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Kucuk2021" class="csl-entry" role="doc-biblioentry"&gt;
Kucuk, Yigit, Tim A. D. Henderson, and Andy Podgurski. 2021.
&lt;span&gt;“Improving &lt;span&gt;Fault Localization&lt;/span&gt; by &lt;span&gt;Integrating
Value&lt;/span&gt; and &lt;span&gt;Predicate Based Causal Inference
Techniques&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2021
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 43rd &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;
(&lt;span&gt;ICSE&lt;/span&gt;)&lt;/em&gt;, 649–60. &lt;span&gt;Madrid, ES&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE43902.2021.00066"&gt;https://doi.org/10.1109/ICSE43902.2021.00066&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Leong2019" class="csl-entry" role="doc-biblioentry"&gt;
Leong, Claire, Abhayendra Singh, Mike Papadakis, Yves Le Traon, and John
Micco. 2019. &lt;span&gt;“Assessing &lt;span&gt;Transition-Based Test Selection
Algorithms&lt;/span&gt; at &lt;span&gt;Google&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 101–10. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2019.00019"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00019&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Lewis2013" class="csl-entry" role="doc-biblioentry"&gt;
Lewis, Chris, Zhongpeng Lin, Caitlin Sadowski, and Xiaoyan Zhu. 2013.
&lt;span&gt;“Does Bug Prediction Support Human Developers? Findings from a
Google Case Study.”&lt;/span&gt; In &lt;em&gt;Proceedings of the …&lt;/em&gt;, 372–81. &lt;a
href="http://dl.acm.org/citation.cfm?id=2486838"&gt;http://dl.acm.org/citation.cfm?id=2486838&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Lucia2014" class="csl-entry" role="doc-biblioentry"&gt;
Lucia, David Lo, Lingxiao Jiang, Ferdian Thung, and Aditya Budi. 2014.
&lt;span&gt;“Extended Comprehensive Study of Association Measures for Fault
Localization.”&lt;/span&gt; &lt;em&gt;Journal of Software: Evolution and
Process&lt;/em&gt; 26 (2): 172–219. &lt;a
href="https://doi.org/10.1002/smr.1616"&gt;https://doi.org/10.1002/smr.1616&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Machalica2020" class="csl-entry" role="doc-biblioentry"&gt;
Machalica, Mateusz, Wojtek Chmiel, Stanislaw Swierc, and Ruslan
Sakevych. 2020. &lt;span&gt;“Probabilistic &lt;span&gt;Flakiness&lt;/span&gt;:
&lt;span&gt;How&lt;/span&gt; Do You Test Your Tests?”&lt;/span&gt; &lt;em&gt;DEVINFRA&lt;/em&gt;. &lt;a
href="https://engineering.fb.com/2020/12/10/developer-tools/
                  probabilistic-flakiness/"&gt;https://engineering.fb.com/2020/12/10/developer-tools/
probabilistic-flakiness/&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Machalica2019" class="csl-entry" role="doc-biblioentry"&gt;
Machalica, Mateusz, Alex Samylkin, Meredith Porth, and Satish Chandra.
2019. &lt;span&gt;“Predictive &lt;span&gt;Test Selection&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2019
&lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 41st &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 91–100. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2019.00018"&gt;https://doi.org/10.1109/ICSE-SEIP.2019.00018&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-McCrum-Gardner2008" class="csl-entry"
role="doc-biblioentry"&gt;
McCrum-Gardner, Evie. 2008. &lt;span&gt;“Which Is the Correct Statistical Test
to Use?”&lt;/span&gt; &lt;em&gt;British Journal of Oral and Maxillofacial
Surgery&lt;/em&gt; 46 (1): 38–41. &lt;a
href="https://doi.org/10.1016/j.bjoms.2007.09.002"&gt;https://doi.org/10.1016/j.bjoms.2007.09.002&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Memon2017" class="csl-entry" role="doc-biblioentry"&gt;
Memon, Atif, Zebao Gao, Bao Nguyen, Sanjeev Dhanda, Eric Nickell, Rob
Siemborski, and John Micco. 2017. &lt;span&gt;“Taming &lt;span
class="nocase"&gt;Google-scale&lt;/span&gt; Continuous Testing.”&lt;/span&gt; In
&lt;em&gt;2017 &lt;span&gt;IEEE&lt;/span&gt;/&lt;span&gt;ACM&lt;/span&gt; 39th &lt;span&gt;International
Conference&lt;/span&gt; on &lt;span&gt;Software Engineering&lt;/span&gt;: &lt;span&gt;Software
Engineering&lt;/span&gt; in &lt;span&gt;Practice Track&lt;/span&gt;
(&lt;span&gt;ICSE-SEIP&lt;/span&gt;)&lt;/em&gt;, 233–42. &lt;span&gt;Piscataway, NJ, USA&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2017.16"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.16&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Micco2012" class="csl-entry" role="doc-biblioentry"&gt;
Micco, John. 2012. &lt;span&gt;“Tools for &lt;span&gt;Continuous Integration&lt;/span&gt;
at &lt;span&gt;Google Scale&lt;/span&gt;.”&lt;/span&gt; Tech {{Talk}}. &lt;span&gt;Google
NYC&lt;/span&gt;. &lt;a
href="https://youtu.be/KH2_sB1A6lA"&gt;https://youtu.be/KH2_sB1A6lA&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Micco2013" class="csl-entry" role="doc-biblioentry"&gt;
———. 2013. &lt;span&gt;“Continuous &lt;span&gt;Integration&lt;/span&gt; at &lt;span&gt;Google
Scale&lt;/span&gt;.”&lt;/span&gt; Lecture. &lt;span&gt;EclipseCon 2013&lt;/span&gt;. &lt;a
href="https://web.archive.org/web/20140705215747/https://
                  www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-
                  03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf"&gt;https://web.archive.org/web/20140705215747/https://
www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/2013-
03-24%20Continuous%20Integration%20at%20Google%20Scale.pdf&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Musa2015" class="csl-entry" role="doc-biblioentry"&gt;
Musa, Samaila, Abu Bakar Md Sultan, Abdul Azim Bin Abd-Ghani, and Salmi
Baharom. 2015. &lt;span&gt;“Regression &lt;span&gt;Test Cases&lt;/span&gt; Selection for
&lt;span&gt;Object-Oriented Programs&lt;/span&gt; Based on &lt;span&gt;Affected
Statements&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;International Journal of Software
Engineering and Its Applications&lt;/em&gt; 9 (10): 91–108. &lt;a
href="https://doi.org/10.14257/ijseia.2015.9.10.10"&gt;https://doi.org/10.14257/ijseia.2015.9.10.10&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Najafi2019a" class="csl-entry" role="doc-biblioentry"&gt;
Najafi, Armin, Peter C. Rigby, and Weiyi Shang. 2019. &lt;span&gt;“Bisecting
Commits and Modeling Commit Risk During Testing.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on
&lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
&lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 279–89. &lt;span&gt;New York, NY, USA&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3338906.3338944"&gt;https://doi.org/10.1145/3338906.3338944&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ocariza2022" class="csl-entry" role="doc-biblioentry"&gt;
Ocariza, Frolin S. 2022. &lt;span&gt;“On the &lt;span&gt;Effectiveness&lt;/span&gt; of
&lt;span&gt;Bisection&lt;/span&gt; in &lt;span&gt;Performance Regression
Localization&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;Empirical Software Engineering&lt;/em&gt; 27
(4): 95. &lt;a
href="https://doi.org/10.1007/s10664-022-10152-3"&gt;https://doi.org/10.1007/s10664-022-10152-3&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Osman2017" class="csl-entry" role="doc-biblioentry"&gt;
Osman, Haidar, Mohammad Ghafari, Oscar Nierstrasz, and Mircea Lungu.
2017. &lt;span&gt;“An &lt;span&gt;Extensive Analysis&lt;/span&gt; of &lt;span&gt;Efficient Bug
Prediction Configurations&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 13th
&lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Predictive Models&lt;/span&gt;
and &lt;span&gt;Data Analytics&lt;/span&gt; in &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 107–16. &lt;span&gt;Toronto Canada&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3127005.3127017"&gt;https://doi.org/10.1145/3127005.3127017&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-pan2022" class="csl-entry" role="doc-biblioentry"&gt;
Pan, Rongqi, Mojtaba Bagherzadeh, Taher A. Ghaleb, and Lionel Briand.
2022. &lt;span&gt;“Test Case Selection and Prioritization Using Machine
Learning: A Systematic Literature Review.”&lt;/span&gt; &lt;em&gt;Empirical Software
Engineering&lt;/em&gt; 27 (2): 29. &lt;a
href="https://doi.org/10.1007/s10664-021-10066-6"&gt;https://doi.org/10.1007/s10664-021-10066-6&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Pelc2002" class="csl-entry" role="doc-biblioentry"&gt;
Pelc, Andrzej. 2002. &lt;span&gt;“Searching Games with Errorsfifty Years of
Coping with Liars.”&lt;/span&gt; &lt;em&gt;Theoretical Computer Science&lt;/em&gt; 270
(1-2): 71–109. &lt;a
href="https://doi.org/10.1016/S0304-3975(01)00303-6"&gt;https://doi.org/10.1016/S0304-3975(01)00303-6&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Podgurski1990" class="csl-entry" role="doc-biblioentry"&gt;
Podgurski, A, and L A Clarke. 1990. &lt;span&gt;“A &lt;span&gt;Formal Model&lt;/span&gt;
of &lt;span&gt;Program Dependences&lt;/span&gt; and &lt;span&gt;Its Implications&lt;/span&gt;
for &lt;span&gt;Software Testing&lt;/span&gt;, &lt;span&gt;Debugging&lt;/span&gt;, and
&lt;span&gt;Maintenance&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;IEEE Transactions of Software
Engineering&lt;/em&gt; 16 (9): 965–79. &lt;a
href="https://doi.org/10.1109/32.58784"&gt;https://doi.org/10.1109/32.58784&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Potvin2016" class="csl-entry" role="doc-biblioentry"&gt;
Potvin, Rachel, and Josh Levenberg. 2016. &lt;span&gt;“Why Google Stores
Billions of Lines of Code in a Single Repository.”&lt;/span&gt;
&lt;em&gt;Communications of the ACM&lt;/em&gt; 59 (7): 78–87. &lt;a
href="https://doi.org/10.1145/2854146"&gt;https://doi.org/10.1145/2854146&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Punitha2013" class="csl-entry" role="doc-biblioentry"&gt;
Punitha, K., and S. Chitra. 2013. &lt;span&gt;“Software Defect Prediction
Using Software Metrics - &lt;span&gt;A&lt;/span&gt; Survey.”&lt;/span&gt; In &lt;em&gt;2013
&lt;span&gt;International Conference&lt;/span&gt; on &lt;span&gt;Information
Communication&lt;/span&gt; and &lt;span&gt;Embedded Systems&lt;/span&gt;
(&lt;span&gt;ICICES&lt;/span&gt;)&lt;/em&gt;, 555–58. &lt;span&gt;Chennai&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICICES.2013.6508369"&gt;https://doi.org/10.1109/ICICES.2013.6508369&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ren2004" class="csl-entry" role="doc-biblioentry"&gt;
Ren, Xiaoxia, Fenil Shah, Frank Tip, Barbara G. Ryder, and Ophelia
Chesley. 2004. &lt;span&gt;“Chianti: A Tool for Change Impact Analysis of Java
Programs.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 19th Annual &lt;span&gt;ACM
SIGPLAN&lt;/span&gt; Conference on &lt;span class="nocase"&gt;Object-oriented&lt;/span&gt;
Programming, Systems, Languages, and Applications&lt;/em&gt;, 432–48.
&lt;span&gt;Vancouver BC Canada&lt;/span&gt;: &lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/1028976.1029012"&gt;https://doi.org/10.1145/1028976.1029012&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Rivest1978" class="csl-entry" role="doc-biblioentry"&gt;
Rivest, R. L., A. R. Meyer, and D. J. Kleitman. 1978. &lt;span&gt;“Coping with
Errors in Binary Search Procedures (&lt;span&gt;Preliminary
Report&lt;/span&gt;).”&lt;/span&gt; In &lt;em&gt;Proceedings of the Tenth Annual
&lt;span&gt;ACM&lt;/span&gt; Symposium on &lt;span&gt;Theory&lt;/span&gt; of Computing -
&lt;span&gt;STOC&lt;/span&gt; ’78&lt;/em&gt;, 227–32. &lt;span&gt;San Diego, California, United
States&lt;/span&gt;: &lt;span&gt;ACM Press&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/800133.804351"&gt;https://doi.org/10.1145/800133.804351&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Rodriguez-Perez2018" class="csl-entry"
role="doc-biblioentry"&gt;
Rodríguez-Pérez, Gema, Gregorio Robles, and Jesús M. González-Barahona.
2018. &lt;span&gt;“Reproducibility and Credibility in Empirical Software
Engineering: &lt;span&gt;A&lt;/span&gt; Case Study Based on a Systematic Literature
Review of the Use of the &lt;span&gt;SZZ&lt;/span&gt; Algorithm.”&lt;/span&gt;
&lt;em&gt;Information and Software Technology&lt;/em&gt; 99 (July): 164–76. &lt;a
href="https://doi.org/10.1016/j.infsof.2018.03.009"&gt;https://doi.org/10.1016/j.infsof.2018.03.009&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Saha2017" class="csl-entry" role="doc-biblioentry"&gt;
Saha, Ripon, and Milos Gligoric. 2017. &lt;span&gt;“Selective &lt;span&gt;Bisection
Debugging&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;Fundamental &lt;span&gt;Approaches&lt;/span&gt; to
&lt;span&gt;Software Engineering&lt;/span&gt;&lt;/em&gt;, edited by Marieke Huisman and
Julia Rubin, 10202:60–77. &lt;span&gt;Berlin, Heidelberg&lt;/span&gt;:
&lt;span&gt;Springer Berlin Heidelberg&lt;/span&gt;. &lt;a
href="https://doi.org/10.1007/978-3-662-54494-5_4"&gt;https://doi.org/10.1007/978-3-662-54494-5_4&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Sliwerski2005" class="csl-entry" role="doc-biblioentry"&gt;
Śliwerski, Jacek, Thomas Zimmermann, and Andreas Zeller. 2005.
&lt;span&gt;“When Do Changes Induce Fixes?”&lt;/span&gt; &lt;em&gt;ACM SIGSOFT Software
Engineering Notes&lt;/em&gt; 30 (4): 1. &lt;a
href="https://doi.org/10.1145/1082983.1083147"&gt;https://doi.org/10.1145/1082983.1083147&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Sun2016" class="csl-entry" role="doc-biblioentry"&gt;
Sun, Shih-Feng, and Andy Podgurski. 2016. &lt;span&gt;“Properties of
&lt;span&gt;Effective Metrics&lt;/span&gt; for &lt;span&gt;Coverage-Based Statistical
Fault Localization&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2016 &lt;span&gt;IEEE International
Conference&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;,
&lt;span&gt;Verification&lt;/span&gt; and &lt;span&gt;Validation&lt;/span&gt;
(&lt;span&gt;ICST&lt;/span&gt;)&lt;/em&gt;, 124–34. &lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/ICST.2016.31"&gt;https://doi.org/10.1109/ICST.2016.31&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Tharwat2021" class="csl-entry" role="doc-biblioentry"&gt;
Tharwat, Alaa. 2021. &lt;span&gt;“Classification Assessment Methods.”&lt;/span&gt;
&lt;em&gt;Applied Computing and Informatics&lt;/em&gt; 17 (1): 168–92. &lt;a
href="https://doi.org/10.1016/j.aci.2018.08.003"&gt;https://doi.org/10.1016/j.aci.2018.08.003&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Tip1995" class="csl-entry" role="doc-biblioentry"&gt;
Tip, Frank. 1995. &lt;span&gt;“A Survey of Program Slicing Techniques.”&lt;/span&gt;
&lt;em&gt;Journal of Programming Languages&lt;/em&gt; 3 (3): 121–89.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Waeber2013" class="csl-entry" role="doc-biblioentry"&gt;
Waeber, Rolf, Peter I. Frazier, and Shane G. Henderson. 2013.
&lt;span&gt;“Bisection &lt;span&gt;Search&lt;/span&gt; with &lt;span&gt;Noisy
Responses&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;SIAM Journal on Control and
Optimization&lt;/em&gt; 51 (3): 2261–79. &lt;a
href="https://doi.org/10.1137/120861898"&gt;https://doi.org/10.1137/120861898&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Walpole2007" class="csl-entry" role="doc-biblioentry"&gt;
Walpole, Ronald E., ed. 2007. &lt;em&gt;Probability &amp;amp; Statistics for
Engineers &amp;amp; Scientists&lt;/em&gt;. 8th ed. &lt;span&gt;Upper Saddle River,
NJ&lt;/span&gt;: &lt;span&gt;Pearson Prentice Hall&lt;/span&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wang2020" class="csl-entry" role="doc-biblioentry"&gt;
Wang, Kaiyuan, Greg Tener, Vijay Gullapalli, Xin Huang, Ahmed Gad, and
Daniel Rall. 2020. &lt;span&gt;“Scalable Build Service System with Smart
Scheduling Service.”&lt;/span&gt; In &lt;em&gt;Proceedings of the 29th &lt;span&gt;ACM
SIGSOFT International Symposium&lt;/span&gt; on &lt;span&gt;Software Testing&lt;/span&gt;
and &lt;span&gt;Analysis&lt;/span&gt;&lt;/em&gt;, 452–62. &lt;span&gt;Virtual Event USA&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3395363.3397371"&gt;https://doi.org/10.1145/3395363.3397371&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wen2021" class="csl-entry" role="doc-biblioentry"&gt;
Wen, Ming, Junjie Chen, Yongqiang Tian, Rongxin Wu, Dan Hao, Shi Han,
and Shing-Chi Cheung. 2021. &lt;span&gt;“Historical &lt;span&gt;Spectrum Based Fault
Localization&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software
Engineering&lt;/em&gt; 47 (11): 2348–68. &lt;a
href="https://doi.org/10.1109/TSE.2019.2948158"&gt;https://doi.org/10.1109/TSE.2019.2948158&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wen2019" class="csl-entry" role="doc-biblioentry"&gt;
Wen, Ming, Rongxin Wu, Yepang Liu, Yongqiang Tian, Xuan Xie, Shing-Chi
Cheung, and Zhendong Su. 2019. &lt;span&gt;“Exploring and Exploiting the
Correlations Between Bug-Inducing and Bug-Fixing Commits.”&lt;/span&gt; In
&lt;em&gt;Proceedings of the 2019 27th &lt;span&gt;ACM Joint Meeting&lt;/span&gt; on
&lt;span&gt;European Software Engineering Conference&lt;/span&gt; and
&lt;span&gt;Symposium&lt;/span&gt; on the &lt;span&gt;Foundations&lt;/span&gt; of &lt;span&gt;Software
Engineering&lt;/span&gt;&lt;/em&gt;, 326–37. &lt;span&gt;Tallinn Estonia&lt;/span&gt;:
&lt;span&gt;ACM&lt;/span&gt;. &lt;a
href="https://doi.org/10.1145/3338906.3338962"&gt;https://doi.org/10.1145/3338906.3338962&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Wong2016" class="csl-entry" role="doc-biblioentry"&gt;
Wong, W. Eric, Ruizhi Gao, Yihao Li, Rui Abreu, and Franz Wotawa. 2016.
&lt;span&gt;“A &lt;span&gt;Survey&lt;/span&gt; on &lt;span&gt;Software Fault
Localization&lt;/span&gt;.”&lt;/span&gt; &lt;em&gt;IEEE Transactions on Software
Engineering&lt;/em&gt; 42 (8): 707–40. &lt;a
href="https://doi.org/10.1109/TSE.2016.2521368"&gt;https://doi.org/10.1109/TSE.2016.2521368&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Youm2015" class="csl-entry" role="doc-biblioentry"&gt;
Youm, Klaus Changsun, June Ahn, Jeongho Kim, and Eunseok Lee. 2015.
&lt;span&gt;“Bug &lt;span&gt;Localization Based&lt;/span&gt; on &lt;span&gt;Code Change
Histories&lt;/span&gt; and &lt;span&gt;Bug Reports&lt;/span&gt;.”&lt;/span&gt; In &lt;em&gt;2015
&lt;span&gt;Asia-Pacific Software Engineering Conference&lt;/span&gt;
(&lt;span&gt;APSEC&lt;/span&gt;)&lt;/em&gt;, 190–97. &lt;span&gt;New Delhi&lt;/span&gt;:
&lt;span&gt;IEEE&lt;/span&gt;. &lt;a
href="https://doi.org/10.1109/APSEC.2015.23"&gt;https://doi.org/10.1109/APSEC.2015.23&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Zhou2012" class="csl-entry" role="doc-biblioentry"&gt;
Zhou, Jian, Hongyu Zhang, and David Lo. 2012. &lt;span&gt;“Where Should the
Bugs Be Fixed? &lt;span&gt;More&lt;/span&gt; Accurate Information Retrieval-Based
Bug Localization Based on Bug Reports.”&lt;/span&gt; &lt;em&gt;Proceedings -
International Conference on Software Engineering&lt;/em&gt;, 14–24. &lt;a
href="https://doi.org/10.1109/ICSE.2012.6227210"&gt;https://doi.org/10.1109/ICSE.2012.6227210&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Zhou2010" class="csl-entry" role="doc-biblioentry"&gt;
Zhou, Zhi Quan. 2010. &lt;span&gt;“Using Coverage Information to Guide Test
Case Selection in &lt;span&gt;Adaptive Random Testing&lt;/span&gt;.”&lt;/span&gt;
&lt;em&gt;Proceedings - International Computer Software and Applications
Conference&lt;/em&gt;, 208–13. &lt;a
href="https://doi.org/10.1109/COMPSACW.2010.43"&gt;https://doi.org/10.1109/COMPSACW.2010.43&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ziftci2013a" class="csl-entry" role="doc-biblioentry"&gt;
Ziftci, Celal, and Vivek Ramavajjala. 2013. &lt;span&gt;“Finding
&lt;span&gt;Culprits Automatically&lt;/span&gt; in &lt;span&gt;Failing Builds&lt;/span&gt; -
i.e. &lt;span&gt;Who Broke&lt;/span&gt; the &lt;span&gt;Build&lt;/span&gt;?”&lt;/span&gt; &lt;a
href="https://www.youtube.com/watch?v=SZLuBYlq3OM"&gt;https://www.youtube.com/watch?v=SZLuBYlq3OM&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;li&gt;&lt;div id="ref-Ziftci2017" class="csl-entry" role="doc-biblioentry"&gt;
Ziftci, Celal, and Jim Reardon. 2017. &lt;span&gt;“Who Broke the Build?
&lt;span&gt;Automatically&lt;/span&gt; Identifying Changes That Induce Test Failures
in Continuous Integration at Google Scale.”&lt;/span&gt; &lt;em&gt;Proceedings -
2017 IEEE/ACM 39th International Conference on Software Engineering:
Software Engineering in Practice Track, ICSE-SEIP 2017&lt;/em&gt;, 113–22. &lt;a
href="https://doi.org/10.1109/ICSE-SEIP.2017.13"&gt;https://doi.org/10.1109/ICSE-SEIP.2017.13&lt;/a&gt;.
&lt;/div&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;section class="footnotes footnotes-end-of-document"
role="doc-endnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1" role="doc-endnote"&gt;&lt;p&gt;In practice the restriction on
network usage on TAP is somewhat loose. There are legacy tests that have
been tagged to allow them to utilize the network and there is an on
going effort to fully eliminate network usage on TAP.&lt;a href="#fnref1"
class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2" role="doc-endnote"&gt;&lt;p&gt;Other CI platforms exist for
integration tests that span multiple machines, use large amounts of RAM,
or take a very long time to run. The algorithm presented in this paper
has also been implemented for one of those CI systems but we will not
present an empirical evaluation of its performance in that environment
in this paper. In general, Culprit Finding is much more difficult in
such environments as tests may use a mixture of code from different
versions and network resources may be shared across tests.&lt;a
href="#fnref2" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3" role="doc-endnote"&gt;&lt;p&gt;An internal version of Bazel &lt;a
href="https://bazel.build/" class="uri"&gt;https://bazel.build/&lt;/a&gt;.&lt;a
href="#fnref3" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn4" role="doc-endnote"&gt;&lt;p&gt;The exact number of hours isn’t so
important. The main thing is to repeat the verification at a suitable
interval from the original attempt.&lt;a href="#fnref4"
class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn5" role="doc-endnote"&gt;&lt;p&gt;&lt;a
href="https://github.com/git/git/commit/8b3a1e056f2107deedfdada86046971c9ad7bb87"
class="uri"&gt;https://github.com/git/git/commit/8b3a1e056f2107deedfdada86046971c9ad7bb87&lt;/a&gt;&lt;a
href="#fnref5" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn6" role="doc-endnote"&gt;&lt;p&gt;&lt;a
href="https://www.mercurial-scm.org/repo/hg/file/52464a20add0/mercurial/hbisect.py"
class="uri"&gt;https://www.mercurial-scm.org/repo/hg/file/52464a20add0/mercurial/hbisect.py&lt;/a&gt;,
&lt;a href="https://www.mercurial-scm.org/repo/hg/rev/a7678cbd7c28"
class="uri"&gt;https://www.mercurial-scm.org/repo/hg/rev/a7678cbd7c28&lt;/a&gt;&lt;a
href="#fnref6" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn7" role="doc-endnote"&gt;&lt;p&gt;&lt;a
href="https://metacpan.org/release/INFINOID/App-SVN-Bisect-1.1/source/README"
class="uri"&gt;https://metacpan.org/release/INFINOID/App-SVN-Bisect-1.1/source/README&lt;/a&gt;&lt;a
href="#fnref7" class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn8" role="doc-endnote"&gt;&lt;p&gt;&lt;a
href="https://github.com/Ealdwulf/bbchop"
class="uri"&gt;https://github.com/Ealdwulf/bbchop&lt;/a&gt;&lt;a href="#fnref8"
class="footnote-back" role="doc-backlink"&gt;↩︎&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;</content><category term="Paper"/></entry><entry><title>Improving fault localization by integrating value and predicate based causal inference techniques</title><link href="https://hackthology.com/improving-fault-localization-by-integrating-value-and-predicate-based-causal-inference-techniques.html" rel="alternate"/><published>2021-05-26T00:00:00-04:00</published><updated>2021-05-26T00:00:00-04:00</updated><author><name>Yiğit Küçük, &lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2021-05-26:/improving-fault-localization-by-integrating-value-and-predicate-based-causal-inference-techniques.html</id><summary type="html">&lt;p&gt;Yiğit Küçük, &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, and Andy Podgurski
&lt;em&gt;Improving fault localization by integrating value and predicate based causal inference techniques&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icse-2021/icse-2021-papers/72/Improving-Fault-Localization-by-Integrating-Value-and-Predicate-Based-Causal-Inferenc"&gt;ICSE 2021&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICSE43902.2021.00066"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icse-2021.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icse-2021-supplement.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://doi.org/10.5281/zenodo.4441439"&gt;ARTIFACT&lt;/a&gt;.
&lt;a href="https://hackthology.com/improving-fault-localization-by-integrating-value-and-predicate-based-causal-inference-techniques.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Statistical fault localization (SFL) techniques use execution profiles and
success/failure information from software executions, in conjunction …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Yiğit Küçük, &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, and Andy Podgurski
&lt;em&gt;Improving fault localization by integrating value and predicate based causal inference techniques&lt;/em&gt;.  &lt;a href="https://conf.researchr.org/details/icse-2021/icse-2021-papers/72/Improving-Fault-Localization-by-Integrating-Value-and-Predicate-Based-Causal-Inferenc"&gt;ICSE 2021&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/ICSE43902.2021.00066"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icse-2021.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icse-2021-supplement.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://doi.org/10.5281/zenodo.4441439"&gt;ARTIFACT&lt;/a&gt;.
&lt;a href="https://hackthology.com/improving-fault-localization-by-integrating-value-and-predicate-based-causal-inference-techniques.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Statistical fault localization (SFL) techniques use execution profiles and
success/failure information from software executions, in conjunction with
statistical inference, to automatically score program elements based on how
likely they are to be faulty. SFL techniques typically employ one type of
profile data: either coverage data, predicate outcomes, or variable values. Most
SFL techniques actually measure correlation, not causation, between profile
values and success/failure, and so they are subject to confounding bias that
distorts the scores they produce. This paper presents a new SFL technique, named
UniVal, that uses causal inference techniques and machine learning to integrate
information about both predicate outcomes and variable values to more accurately
estimate the true failure-causing effect of program statements. UniVal was
empirically compared to several coverage-based, predicate-based, and value-based
SFL techniques on 800 program versions with real faults.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hackthology.com/pdfs/icse-2021.pdf"&gt;Read the paper&lt;/a&gt;&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>The Impact of Rare Failures on Statistical Fault Localization: the Case of the Defects4J Suite</title><link href="https://hackthology.com/the-impact-of-rare-failures-on-statistical-fault-localization-the-case-of-the-defects4j-suite.html" rel="alternate"/><published>2019-10-03T00:00:00-04:00</published><updated>2019-10-03T00:00:00-04:00</updated><author><name>Yiğit Küçük, &lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2019-10-03:/the-impact-of-rare-failures-on-statistical-fault-localization-the-case-of-the-defects4j-suite.html</id><summary type="html">&lt;p&gt;Yiğit Küçük, &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, and Andy Podgurski
&lt;em&gt;The Impact of Rare Failures on Statistical Fault Localization: the Case of the Defects4J Suite&lt;/em&gt;.  &lt;a href="https://icsme2019.github.io/"&gt;ICSME 2019&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="http://tba"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icsme-2019.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/the-impact-of-rare-failures-on-statistical-fault-localization-the-case-of-the-defects4j-suite.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Statistical Fault Localization (SFL) uses coverage profiles (or "spectra")
collected from passing and failing tests, together …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Yiğit Küçük, &lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, and Andy Podgurski
&lt;em&gt;The Impact of Rare Failures on Statistical Fault Localization: the Case of the Defects4J Suite&lt;/em&gt;.  &lt;a href="https://icsme2019.github.io/"&gt;ICSME 2019&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="http://tba"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icsme-2019.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/the-impact-of-rare-failures-on-statistical-fault-localization-the-case-of-the-defects4j-suite.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Statistical Fault Localization (SFL) uses coverage profiles (or "spectra")
collected from passing and failing tests, together with statistical metrics,
which are typically composed of simple estimators, to identify which elements of
a program are most likely to have caused observed failures. Previous SFL
research has not thoroughly examined how the effectiveness of SFL metrics is
related to the proportion of failures in test suites and related quantities. To
address this issue, we studied the Defects4J benchmark suite of programs and
test suites and found that if a test suite has very few failures, SFL performs
poorly. To better understand this phenomenon, we investigated the precision of
some statistical estimators of which SFL metrics are composed, as measured by
their coefficients of variation.  The precision of an embedded estimator, which
depends on the dataset, was found to correlate with the effectiveness of a
metric containing it: low precision is associated with poor effectiveness.
Boosting precision by adding test cases was found to improve overall SFL
effectiveness. We present our findings and discuss their implications for the
evaluation and use of SFL metrics.&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://hackthology.com/pdfs/icsme-2019.pdf"&gt;Read the rest of the paper as a pdf&lt;/a&gt;)&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>Evaluating Automatic Fault Localization Using Markov Processes</title><link href="https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html" rel="alternate"/><published>2019-09-30T00:00:00-04:00</published><updated>2019-09-30T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, Yiğit Küçük, and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2019-09-30:/evaluating-automatic-fault-localization-using-markov-processes.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Yiğit Küçük, and Andy Podgurski
&lt;em&gt;Evaluating Automatic Fault Localization Using Markov Processes&lt;/em&gt;.  &lt;a href="http://www.ieee-scam.org/2019/"&gt;SCAM 2019&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/SCAM.2019.00021"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/scam-2019.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/scam-2019-supplement.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/scam-2019.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Abstract …&lt;/h4&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Yiğit Küçük, and Andy Podgurski
&lt;em&gt;Evaluating Automatic Fault Localization Using Markov Processes&lt;/em&gt;.  &lt;a href="http://www.ieee-scam.org/2019/"&gt;SCAM 2019&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/SCAM.2019.00021"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/scam-2019.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/scam-2019-supplement.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/scam-2019.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;
Statistical fault localization (SFL) techniques are commonly compared and
evaluated using a measure known as "Rank Score" and its associated evaluation
process.  In the latter process each SFL technique under comparison is used to
produce a list of program locations, ranked by their suspiciousness scores.
Each technique then receives a Rank Score for each faulty program it is applied
to, which is equal to the rank of the first faulty location in the
corresponding list. The SFL technique whose average Rank Score is lowest is
judged the best overall, based on the assumption that a programmer will examine
each location in rank order until a fault is found.  However, this assumption
*oversimplifies* how an SFL technique would be used in practice.
Programmers are likely to regard suspiciousness ranks as just one source of
information among several that are relevant to locating faults. This paper
provides a new evaluation approach using first-order Markov models of debugging
processes, which can incorporate multiple additional kinds of information,
e.g., about code locality, dependences, or even intuition.  Our approach,
&lt;span&gt;&lt;span class="math inline"&gt;\( \textrm{HT}_{\textrm{Rank}} \)&lt;/span&gt;&lt;/span&gt;, scores SFL techniques based on the expected number of steps a
programmer would take through the Markov model before reaching a faulty
location. Unlike previous evaluation methods, &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; can compare techniques
even when they produce fault localization reports differing in structure or
information granularity.  To illustrate the approach, we present a case study
comparing two existing fault localization techniques that produce results
varying in form and granularity.
&lt;/p&gt;

&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Automatic fault localization is a software engineering technique to assist a programmer during the debugging process by suggesting "suspicious" locations that may contain or overlap with a fault (bug, defect) that is the root cause of observed failures. The big idea behind automatic fault localization (or just fault localization) is that pointing the programmer towards the right area of the program will enable them to find the relevant fault more quickly.&lt;/p&gt;
&lt;p&gt;A much-investigated approach to fault localization is &lt;em&gt;Coverage-Based Statistical Fault Localization&lt;/em&gt; (CBSFL), which is also known as &lt;em&gt;Spectrum-Based Fault Localization&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]-[&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;]&lt;/span&gt;. This approach uses code-coverage profiles and success/failure information from testing or field use of software to rank statements or other generic program locations (e.g., basic blocks, methods, or classes) from most "suspicious" (likely to be faulty) to least suspicious. To perform CBSFL, each test case is run using a version of the program being debugged that has been instrumented to record which potential fault locations were actually executed on that test. A human or automated &lt;em&gt;test oracle&lt;/em&gt; labels each test to indicate whether it passed or failed. The coverage profiles are also referred to as &lt;em&gt;coverage spectra&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In the usage scenario typically envisioned for CBSFL, a programmer uses the ranked list of program locations to guide debugging. Starting at the top of the list and moving down, they examine each location to determine if it is faulty. If the location of a fault is near the top of the list, the programmer saves time by avoiding consideration of most of the non-faulty locations in the program. However, if there is no fault near the top of the list, the programmer instead wastes time examining many more locations than necessary. CBSFL techniques are typically evaluated empirically in terms of their ability to rank faulty locations near the top of the list &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;], [&lt;a href="#ref-Pearson2017"&gt;5&lt;/a&gt;]&lt;/span&gt;, as measured by each technique's "Rank Score", which is the location of the first faulty location in the list. A CBSFL technique that consistently ranks faulty statements from a wide range of faulty programs near the top of the corresponding lists is considered a good technique.&lt;/p&gt;
&lt;p&gt;One pitfall of using the ranked-list evaluation regime outlined above is that it can be applied fairly only when the techniques being compared provide results as a prioritized list of program elements of the same granularity. This means that if technique A produces a prioritized list of basic blocks, technique B produces an unordered set of sub-expressions, and technique C produces a prioritized list of classes then it is not valid to use the Standard Rank Score to compare them. The Standard Rank Score can only be applied to ordered lists and thus cannot be used directly to evaluate technique B, and it requires the techniques being compared to have the same granularity. Our new evaluation metric (called &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;) accounts for these differences in granularity and report construction, allowing a direct comparison between different styles of fault localization. We present a case study in Section 27 comparing &lt;em&gt;behavioral&lt;/em&gt; fault localization (which produces fragments of the dynamic control flow graph) to standard CBSFL.&lt;/p&gt;
&lt;p&gt;Second, it is evident that the imagined usage scenario for CBSFL, in which a programmer examines each possible fault location in rank order until a fault is found, is an oversimplification of programmer behavior &lt;span class="citation"&gt;[&lt;a href="#ref-Parnin2011"&gt;6&lt;/a&gt;]&lt;/span&gt;. Programmers are likely to deviate from this scenario, e.g.: by choosing not to re-examine locations that have already been carefully examined and have not changed; by examining the locations around a highly ranked one, regardless of their ranks; by examining locations that a highly ranked location is dependent upon or that are dependent upon it &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;7&lt;/a&gt;]&lt;/span&gt;; by employing a conventional debugger (such as gdb, WinDB, or Visual Studio's debugger); or simply by using their knowledge and intuition about the program.&lt;/p&gt;
&lt;p&gt;To support more flexible and nuanced evaluation criteria for CBSFL and other fault localization techniques, we present a new approach to evaluating them that is based on constructing and analyzing first-order Markov models of debugging processes and that uses a new evaluation metric (&lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;) based on the "hitting time" of a Markov process. This approach allows researchers to directly compare different fault localization techniques by incorporating their results and other relevant information into an appropriate model. To illustrate the approach, we present models for two classes of fault localization techniques: CBSFL and Suspicious Behavior Based Fault Localization (SBBFL) &lt;span class="citation"&gt;[&lt;a href="#ref-Cheng2009a"&gt;8&lt;/a&gt;], [&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;. The models we present are also easy to update, allowing researchers to incorporate results of future studies of programmers' behavior during debugging.&lt;/p&gt;
&lt;p&gt;Our new debugging model (and its &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; metric) can be thought of as a first-order simulation of the debugging process as conducted by a programmer. As such, we intend for it to be a practical alternative to conducting an expensive user study. The model is capable of incorporating a variety of behaviors a programmer may exhibit while debugging, allowing researchers to evaluate the performance of their tool against multiple debugging "styles."&lt;/p&gt;
&lt;h1 id="background-and-related-work"&gt;Background and Related Work&lt;/h1&gt;
&lt;p&gt;Coverage Based Statistical Fault Localization (CBSFL) &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;], [&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt; techniques attempt to quantify the likelihood that individual program locations are faulty using sample statistics, called &lt;em&gt;suspiciousness metrics&lt;/em&gt; or &lt;em&gt;fault localization metrics&lt;/em&gt;, which are computed from PASS/FAIL labels assigned to test executions and from coverage profiles (coverage spectra) collected from those executions. A CBSFL suspiciousness metric (of which there are a great many &lt;span class="citation"&gt;[&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;], [&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;]&lt;/span&gt;) measures the statistical association between the occurrence of test failures and the coverage of individual program locations (program elements) of a certain kind.&lt;/p&gt;
&lt;p&gt;Some statistical fault localization techniques use additional information beyond basic coverage information to either improve accuracy or provide more explainable results. For instance, work on &lt;em&gt;Causal Statistical Fault Localization&lt;/em&gt; uses information about the execution of program dependence predecessors of a target statement to adjust for confounding bias that can distort suspiciousness scores &lt;span class="citation"&gt;[&lt;a href="#ref-Baah2010"&gt;10&lt;/a&gt;]&lt;/span&gt;. By contrast, &lt;em&gt;Suspicious-Behavior-Based Fault Localization&lt;/em&gt; (SBBFL) techniques use runtime control-flow information (the behavior) to identify groups of "collaborating" suspicious elements &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;. These techniques typically leverage data mining techniques &lt;span class="citation"&gt;[&lt;a href="#ref-Aggarwal2014"&gt;11&lt;/a&gt;]&lt;/span&gt; such as frequent pattern mining &lt;span class="citation"&gt;[&lt;a href="#ref-Agrawal1993"&gt;12&lt;/a&gt;]-[&lt;a href="#ref-Aggarwal2014a"&gt;14&lt;/a&gt;]&lt;/span&gt; or significant pattern mining &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;], [&lt;a href="#ref-Yan2008"&gt;15&lt;/a&gt;]&lt;/span&gt;. Unlike CBSFL techniques, SBBFL techniques output a ranked list of &lt;em&gt;patterns&lt;/em&gt; (subgraphs, itemsets, trees) which each contain multiple program locations. This makes it difficult to directly compare SBBFL and CBSFL techniques using traditional evaluation methods.&lt;/p&gt;
&lt;p&gt;Finally, a variety of non-statistical (or hybrid) approaches to fault localization have been explored &lt;span class="citation"&gt;[&lt;a href="#ref-Abreu2006"&gt;16&lt;/a&gt;]-[&lt;a href="#ref-Wong2016"&gt;19&lt;/a&gt;]&lt;/span&gt;. These approaches range from delta debugging &lt;span class="citation"&gt;[&lt;a href="#ref-Zeller1999"&gt;20&lt;/a&gt;]&lt;/span&gt; to nearest neighbor queries &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;7&lt;/a&gt;]&lt;/span&gt; to program slicing &lt;span class="citation"&gt;[&lt;a href="#ref-Tip1995"&gt;21&lt;/a&gt;], [&lt;a href="#ref-Mao2014"&gt;22&lt;/a&gt;]&lt;/span&gt; to information retrieval &lt;span class="citation"&gt;[&lt;a href="#ref-Marcus2004"&gt;23&lt;/a&gt;]-[&lt;a href="#ref-Le2015"&gt;25&lt;/a&gt;]&lt;/span&gt; to test case generation &lt;span class="citation"&gt;[&lt;a href="#ref-Artzi2010"&gt;26&lt;/a&gt;]-[&lt;a href="#ref-Perez2014"&gt;28&lt;/a&gt;]&lt;/span&gt;. Despite technical and theoretical differences in these approaches, they all suggest locations (or groups of locations) for programmers to consider when debugging.&lt;/p&gt;
&lt;h2 id="the-tarantula-evaluation"&gt;The Tarantula Evaluation&lt;/h2&gt;
&lt;p&gt;Some of the earliest papers on fault localization do not provide a quantitative method for evaluating performance (as is seen in later papers &lt;span class="citation"&gt;[&lt;a href="#ref-Pearson2017"&gt;5&lt;/a&gt;]&lt;/span&gt;). For instance, the earliest CBSFL paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;, by Jones &lt;em&gt;et al.&lt;/em&gt;, proposes a technique and evaluates it qualitatively using data visualization. At the time, this was entirely appropriate as Jones was proposing a technique for visualizing the relative suspiciousness of different statements, as estimated with what is now called a suspiciousness metric (Tarantula). The visualization used for evaluating this technique aggregated the visualizations for all of the subject programs included in the study.&lt;/p&gt;
&lt;p&gt;While the evaluation method used in the Jones &lt;em&gt;et al.&lt;/em&gt; paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt; effectively communicated the potential of CBSFL (and interested many researchers in the idea) it was not good way to compare multiple fault localization techniques. In 2005 Jones and Harrold &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt; published a study that compared their Tarantula technique to three other techniques: Set Union and Intersection &lt;span class="citation"&gt;[&lt;a href="#ref-Agrawal1995"&gt;29&lt;/a&gt;]&lt;/span&gt;, Nearest Neighbor &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;7&lt;/a&gt;]&lt;/span&gt;, and Cause-Transitions &lt;span class="citation"&gt;[&lt;a href="#ref-Cleve2005"&gt;30&lt;/a&gt;]&lt;/span&gt;. These techniques involved different approaches toward the fault localization problem and originally had been evaluated in different ways. Jones and Harrold re-evaluated all of the techniques under a new common evaluation framework.&lt;/p&gt;
&lt;p&gt;In their 2005 paper, Jones and Harrold evaluated the effectiveness of each fault localization technique by using it to rank the statements in each subject program version from most likely to be the root cause of observed program failures to least likely. For their technique Tarantula, the statements were ranked using the Tarantula suspiciousness score.&lt;a href="#fn1" class="footnoteRef" id="fnref1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; To compare the effectiveness of the techniques, another kind of score was assigned to each faulty version of each subject program. This score is based on the "rank score":&lt;/p&gt;
&lt;h4 id="definition.-tarantula-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Tarantula Rank Score &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l
  \in L\)&lt;/span&gt; the Rank Score &lt;span class="math inline"&gt;\(r(l)\)&lt;/span&gt; for a faulty location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; is: &lt;span class="math display"&gt;\[\begin{aligned}
    {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) \ge s(l) \right\} }\right|}}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Set Union and Intersection, Nearest Neighbor, and Cause-Transitions, Jones and Harrold used an idea of Renieres and Reiss &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;7&lt;/a&gt;]&lt;/span&gt; and ranked a program's statements based on consideration of its System Dependence Graph (SDG) &lt;span class="citation"&gt;[&lt;a href="#ref-Horwitz1990"&gt;31&lt;/a&gt;]&lt;/span&gt;. The surrogate suspiciousness score of a program location &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; is the inverse of the size of the smallest dependence sphere around &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; that contains a faulty location. The surrogate scores are then used to calculate the Tarantula Rank Score (Def. 14).&lt;/p&gt;
&lt;p&gt;In Jones's and Harrold's evaluation the authors did not use the Tarantula Rank Score directly but instead used a version of it that is normalized by program size:&lt;/p&gt;
&lt;h4 id="definition.-tarantula-effectiveness-score-expense"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Tarantula Effectiveness Score (Expense) &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This score is the proportion of program locations that do &lt;strong&gt;not&lt;/strong&gt; need to be examined to find a fault when the locations are examined in rank order. Formally, let &lt;span class="math inline"&gt;\(n\)&lt;/span&gt; be the total number of program locations, and let &lt;span class="math inline"&gt;\(r(f)\)&lt;/span&gt; be the Tarantula Rank Score (Def. 14) of the faulty location &lt;span class="math inline"&gt;\(f\)&lt;/span&gt;. Then the score is: &lt;span class="math display"&gt;\[\begin{aligned}
    \frac{n-r(f)}{n}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using the normalized effectiveness score, Jones and Harrold directly compared the fault localization effectiveness of the techniques they considered. They did this in two ways. First, they presented a table that bucketed all the buggy versions of all the programs by their Tarantula Effectiveness Scores (given as percentages). Second, they presented a figure that showed the same data as a cumulative curve.&lt;/p&gt;
&lt;p&gt;The core ideas of Jones' and Harrold's Effectivness/Expense score now underlie most evaluations of CBSFL techniques. Faulty statements are scored, ranked, rank-scored, normalized, and then aggregated over all programs and versions to provide an overall representation of a fault localization method's performance (e.g., &lt;span class="citation"&gt;[&lt;a href="#ref-Steimann2013"&gt;53&lt;/a&gt;]&lt;/span&gt;, [&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;], [&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;], [&lt;a href="#ref-Wong2008"&gt;32&lt;/a&gt;]-[&lt;a href="#ref-Zheng2018"&gt;34&lt;/a&gt;]&lt;/span&gt;). However, some refinements have been made to both the Rank Score and the Effectiveness Score.&lt;/p&gt;
&lt;h2 id="the-implied-debugging-models"&gt;The Implied Debugging Models&lt;/h2&gt;
&lt;p&gt;It is worth (re)stating here the debugging model implied in the Jones and Harrold evaluation &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt;. The programmer receives from the fault localization tool a ranked list of statements with the most suspicious statements at the top. The programmer then moves down the list examining each location in turn. If multiple statements have the same rank (the same suspiciousness score) all of those statements are examined before the programmer makes a determination on whether or not the bug has been located. This rule is captured in the mathematical definition of the Tarantula Rank Score (Definition 14).&lt;/p&gt;
&lt;p&gt;For the non-CBSFL methods which Jones compared CBSFL against, the ranks of the program locations were once again compared using the method of Renieres and Reiss &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;7&lt;/a&gt;], [&lt;a href="#ref-Cleve2005"&gt;30&lt;/a&gt;], [&lt;a href="#ref-ChaoLiu2006"&gt;35&lt;/a&gt;]&lt;/span&gt; which is sometimes called &lt;em&gt;T-Score&lt;/em&gt;. As a reminder, this method computes a surrogate suspiciousness score based on the size of smallest &lt;em&gt;dependence sphere&lt;/em&gt;&lt;a href="#fn2" class="footnoteRef" id="fnref2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; centered around the locations indicated in the fault localization report that contain the faulty code. This implies a debugging model in which the programmer examines each "shell" of the dependence sphere in turn before moving onto the next larger shell (see Figure 7 in &lt;span class="citation"&gt;[&lt;a href="#ref-Cleve2005"&gt;30&lt;/a&gt;]&lt;/span&gt; for a visualization).&lt;/p&gt;
&lt;p&gt;Neither of these debugging models are realistic. Programmers may be reasonably expected to deviate from the ordering implied by the ranking. During the debugging process a programmer may use a variety of information sources — including intuition — to decide on the next element to examine. They may examine the same element multiple times. They may take a highly circuitous route to the buggy code or via intuition jump immediately to the fault. The models described above allow for none of these subtleties.&lt;/p&gt;
&lt;h2 id="refinements-to-the-evaluation-framework"&gt;Refinements to the Evaluation Framework&lt;/h2&gt;
&lt;p&gt;Wong &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2008"&gt;32&lt;/a&gt;]&lt;/span&gt; introduced the most commonly used effectiveness score, which is called the &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; score. This score is essentially the same as the Expense score (Def. 15) except that it gives the percentage of locations that need to be examined rather than those avoided.&lt;/p&gt;
&lt;h4 id="definition.-mathcalexam-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; Score &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2008"&gt;32&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[\begin{aligned}
    \frac{r(f)}{n}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ali &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Ali2009"&gt;37&lt;/a&gt;]&lt;/span&gt; identified an important problem with Jones' and Harrold's evaluation method: some fault localization techniques always assign different locations distinct suspiciousness scores, but others do not. Ali &lt;em&gt;et al.&lt;/em&gt; pointed out that when comparing techniques, the Tarantula Effectiveness Score may favor a technique that generates more distinct suspiciousness scores than the other techniques. The fix they propose is to assign to a location in a group of locations with the same suspiciousness score a rank score that reflects developers having to examine half the locations in the group on average.&lt;/p&gt;
&lt;h4 id="definition.-standard-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Standard Rank Score&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This score is the expected number of locations a programmer would inspect before locating a fault. Formally, given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt;, the Rank Score for a location &lt;span class="math inline"&gt;\(l
  \in L\)&lt;/span&gt; is &lt;span class="citation"&gt;[&lt;a href="#ref-Ali2009"&gt;37&lt;/a&gt;]&lt;/span&gt;: &lt;span class="math display"&gt;\[\begin{aligned}
    {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) &amp;gt; s(l) \right\} }\right|}} +
    \frac{
      {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \right\} }\right|}}
    }{
      2
    }
  \end{aligned}\]&lt;/span&gt; Note: when we refer to the "Standard Rank Score" this is the definition we are referring to.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Parnin and Orso &lt;span class="citation"&gt;[&lt;a href="#ref-Parnin2011"&gt;6&lt;/a&gt;]&lt;/span&gt; conducted a study of programmers' actual use of a statistical fault localization tool (Tarantula &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;). One of their findings was that programmers did not look deeply through the ranked list of locations and would instead only consider the first few locations. Consequently, they encouraged researchers to no longer report effectiveness scores as percentages. Most CBSFL studies now report absolute (non-percentage) rank scores. This is desirable for another reason: larger programs can have much larger absolute ranks than small programs, for the same percentage rank. Consider, for instance a program with 100,000 lines. If a fault's Rank Score is 10,000 its percentage Exam Score would be 10%. A 10% Exam Score might look like a reasonably good localization (and would be if the program had 100 lines) but no programmer will be willing to look through 10,000 lines. By themselves, percentage evaluation metrics (like Exam Score) produce inherently misleading results for large programs.&lt;/p&gt;
&lt;p&gt;Steinmann &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Steimann2013"&gt;53&lt;/a&gt;]&lt;/span&gt; identified a number of threats to validity in CBSFL studies, including: heterogeneous subject programs, poor test suites, small sample sizes, unclear sample spaces, flaky tests, total number of faults, and masked faults. For evaluation they used the Standard Rank Score of Definition 17 modified to deal with &lt;span class="math inline"&gt;\(k\)&lt;/span&gt; faults tied at the same rank.&lt;/p&gt;
&lt;h4 id="definition.-steinmann-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Steinmann Rank Score&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This score is the expected number of locations a programmer would inspect before finding a fault when multiple faulty statements may have the same rank. Formally, given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt;, the Rank Score for a location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; is &lt;span class="citation"&gt;[&lt;a href="#ref-Steimann2013"&gt;53&lt;/a&gt;]&lt;/span&gt;: &lt;span class="math display"&gt;\[\begin{aligned}
    &amp;amp; {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) &amp;gt; s(l) \right\} }\right|}}\\
    &amp;amp; + \frac{
          {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \right\} }\right|}} + 1
        }{
          {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \wedge x \text{ is a
          faulty location} \right\}}\right|}} + 1
        }
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Moon &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Moon2014"&gt;38&lt;/a&gt;]&lt;/span&gt; proposed Locality Information Loss (LIL) as an alternative evaluation framework. LIL models the localization result as a probability distribution constructed from the suspiciousness scores:&lt;/p&gt;
&lt;h4 id="definition.-lil-probability-distribution"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. LIL Probability Distribution&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math inline"&gt;\(\tau\)&lt;/span&gt; be a suspicious metric normalized to the &lt;span class="math inline"&gt;\([0,1]\)&lt;/span&gt; range of reals. Let &lt;span class="math inline"&gt;\(n\)&lt;/span&gt; be the number of locations in the program and let &lt;span class="math inline"&gt;\(L = \{l_1,\ldots,
  l_n\}\)&lt;/span&gt; be the set of locations. The constructed probability distribution is given by: &lt;span class="math display"&gt;\[\begin{aligned}
    P_{\tau}(l_i) = \frac{\tau(l_i)}{\sum^{n}_{j=1} \tau(l_j)}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;LIL uses the Kullback-Leibler measure of divergence between distributions to compute a score indicating how different the distribution constructed for a suspiciousness metric of interest is from the distribution constructed from an "ideal" metric, which gives a score of 1 to the faulty location(s) and gives negligible scores to every other location. The advantage of the LIL framework is that it does not depend on a list of ranked statements and can be applied to non-statistical methods (using a synthetic &lt;span class="math inline"&gt;\(\tau\)&lt;/span&gt;). The disadvantage of LIL is that it does not reflect programmer effort (as the Rank Scores do). However, it may be a better metric to use when evaluating fault localization systems as components of automated fault repair systems.&lt;/p&gt;
&lt;p&gt;Pearson &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Pearson2017"&gt;5&lt;/a&gt;]&lt;/span&gt; re-evaluated a number of previous results using new real world subject programs with real defects and test suites. In contrast to previous work they made use of statistical hypothesis testing and confidence intervals to characterize the uncertainty of the results. To evaluate the performance of each technique under study they used the &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; score, reporting best, average, and worst case results for multi-statement faults.&lt;/p&gt;
&lt;h1 id="a-new-approach-to-evaluation"&gt;A New Approach to Evaluation&lt;/h1&gt;
&lt;p&gt;Programmers consider multiple sources of information when performing debugging tasks and use them to guide their exploration of the source code. In our new approach to evaluating fault localization techniques, a model is constructed for each technique &lt;span class="math inline"&gt;\(T\)&lt;/span&gt; and each program &lt;span class="math inline"&gt;\(P\)&lt;/span&gt; of how a programmer using &lt;span class="math inline"&gt;\(T\)&lt;/span&gt; might move from examining one location in &lt;span class="math inline"&gt;\(P\)&lt;/span&gt; to examining another. The model for &lt;span class="math inline"&gt;\(T\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(P\)&lt;/span&gt; is used to compute a statistical estimate of the expected number of moves a programmer using &lt;span class="math inline"&gt;\(T\)&lt;/span&gt; would make before encountering a fault in &lt;span class="math inline"&gt;\(P\)&lt;/span&gt;. This estimate is used to compute a "hitting-time rank score" for technique &lt;span class="math inline"&gt;\(T\)&lt;/span&gt;. The scores for all the techniques can then be compared to determine which performed best on program &lt;span class="math inline"&gt;\(P\)&lt;/span&gt;. This section presents the general approach and specific example models. The models make use of CBSFL reports and information about static program structure and dynamic control flow.&lt;/p&gt;
&lt;p&gt;In order to support very flexible modeling and tractable analysis of debugging processes, we use first-order Markov chains (described below) to model them. Our first example models the debugging process assumed in previous work, in which a programmer follows a ranked list of suspicious program locations until a fault is found. Then we describe how to incorporate structural information about the program (which could influence a programmer's debugging behavior). Finally, we show how to model and compare CBSFL to a recent &lt;em&gt;Suspicious Behavioral Based Fault Localization&lt;/em&gt; (SBBFL) algorithm &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt; that identifies suspicious subgraphs of dynamic control flow graphs. This third model demonstrates the flexibility of our approach and could be adapted to evaluate other SBBFL techniques &lt;span class="citation"&gt;[&lt;a href="#ref-Cheng2009a"&gt;8&lt;/a&gt;], [&lt;a href="#ref-Liu2005"&gt;39&lt;/a&gt;]-[&lt;a href="#ref-Yousefi2013"&gt;47&lt;/a&gt;]&lt;/span&gt;. It also demonstrates that our approach can be used to compare statistical and non-statistical fault localization techniques under the same assumptions about programmer debugging behavior.&lt;/p&gt;
&lt;p&gt;It is important to emphasize that the quality and value of the evaluation results obtained with our approach depend primarily on the appropriateness of the model of the debugging process that is created. This model represents the evaluators' knowledge about likely programmer behavior during debugging and the factors that influence it. To avoid biasing their evaluation, evaluators must commit to an evaluation model and refrain from "tweaking" it after applying it to the data. &lt;span class="citation"&gt;[&lt;a href="#ref-Ioannidis2005"&gt;48&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;h2 id="background-on-ergodic-markov-chains"&gt;Background on Ergodic Markov Chains&lt;/h2&gt;
&lt;p&gt;A finite state Markov chain consists of a set of &lt;em&gt;states&lt;/em&gt; &lt;span class="math inline"&gt;\(S = \{s_1, s_2,
..., s_n \}\)&lt;/span&gt; and an &lt;span class="math inline"&gt;\(n \times n\)&lt;/span&gt; matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt;, called the &lt;em&gt;transition matrix&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Grinstead2012"&gt;49&lt;/a&gt;]&lt;/span&gt;. Entry &lt;span class="math inline"&gt;\({\bf P}_{i,j}\)&lt;/span&gt; gives the probability for a &lt;em&gt;Markov process&lt;/em&gt; in state &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; to move to state &lt;span class="math inline"&gt;\(s_j\)&lt;/span&gt;. The probability of a Markov process moving from one state to another only depends on the state the process is currently in. This is known as the &lt;em&gt;Markov property&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;A Markov chain is said to be &lt;em&gt;ergodic&lt;/em&gt; if, given enough steps, it can move from any state &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; to any state &lt;span class="math inline"&gt;\(s_j\)&lt;/span&gt;, i.e. &lt;span class="math inline"&gt;\({\textrm{Pr}\left[{s_i \xrightarrow{*} s_j}\right]} &amp;gt; 0\)&lt;/span&gt;. Thus, there are no states in an ergodic chain that the process can never leave.&lt;/p&gt;
&lt;p&gt;Ergodic Markov chains have &lt;em&gt;stationary distributions&lt;/em&gt;. Let &lt;span class="math inline"&gt;\({\bf v}\)&lt;/span&gt; be an arbitrary probability vector. The stationary distribution is a probability vector &lt;span class="math inline"&gt;\({\bf w}\)&lt;/span&gt; such that &lt;span class="math display"&gt;\[\lim_{n \rightarrow \infty} {\bf v}{\bf P}^{n} = {\bf w}\]&lt;/span&gt; The vector &lt;span class="math inline"&gt;\({\bf w}\)&lt;/span&gt; is a fixed point on &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt; implying &lt;span class="math inline"&gt;\({\bf w}{\bf P} = {\bf
w}\)&lt;/span&gt;. Stationary distributions give the long term behavior of a Markov chain - meaning that after many steps the chance a Markov process ends in state &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; is given by &lt;span class="math inline"&gt;\({\bf w}_i\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;expected hitting time&lt;/em&gt; of a state in a Markov chain is the expected number of steps (transitions) a Markov process will make before it encounters the state for the first time. Our new evaluation metric (&lt;span class="math inline"&gt;\(\text{HT}_{\text{Rank}}\)&lt;/span&gt;) uses the expected hitting time of the state representing a faulty program location to score a fault localization technique's performance. Lower expected hitting times yield better localization scores.&lt;/p&gt;
&lt;h4 id="definition.-expected-hitting-time"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Expected Hitting Time&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Consider a Markov chain with transition matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt;. Let &lt;span class="math inline"&gt;\(T_{i,j}\)&lt;/span&gt; be a random variable denoting the time at which a Markov process that starts at state &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; reaches state &lt;span class="math inline"&gt;\(s_j\)&lt;/span&gt;. The expected hitting time (or just hitting time) of state &lt;span class="math inline"&gt;\(s_j\)&lt;/span&gt; for such a process is the expected value of &lt;span class="math inline"&gt;\(T_{i,j}\)&lt;/span&gt; &lt;span class="math display"&gt;\[\begin{aligned}
    {\textrm{E}\left[{T_{i,j}}\right]} = \sum_{k=1}^{\infty} k \cdot {\textrm{Pr}\left[{T_{i,j}=k}\right]}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In general, a hitting time for a single state may be computed in &lt;span class="math inline"&gt;\(\mathcal{O}(n^3)\)&lt;/span&gt; steps &lt;span class="citation"&gt;[&lt;a href="#ref-Kemeny1960"&gt;50&lt;/a&gt;]&lt;/span&gt;. Somewhat less time is required for sparse transition matrices &lt;span class="citation"&gt;[&lt;a href="#ref-Davis2004"&gt;51&lt;/a&gt;]&lt;/span&gt;. Chapter 11 of Grinstead and Snell &lt;span class="citation"&gt;[&lt;a href="#ref-Grinstead2012"&gt;49&lt;/a&gt;]&lt;/span&gt; provides an accessible introduction to hitting time computation.&lt;/p&gt;
&lt;p&gt;Some programs may have too many elements for exact hitting time computations (our case study contains one such program). To deal with large programs the expected hitting time can also be estimated by taking repeated random walks through the Markov chain to obtain a sample of hitting times. The sample can then be used to estimate the expected hitting time by computing the sample mean.&lt;a href="#fn3" class="footnoteRef" id="fnref3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2 id="expected-hitting-time-rank-score-textrmht_textrmrank"&gt;Expected Hitting Time Rank Score (&lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;)&lt;/h2&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div style="margin-right: 2em; margin-left: 2em;"&gt;
&lt;strong&gt;Listing 1.&lt;/strong&gt;
A bug in the implementation of the "Has" method in an AVL tree.
&lt;/div&gt;
&lt;table&gt;
&lt;caption&gt; &lt;span style="font-variant: small-caps;"&gt;Table I: Reduced CBSFL Results for Listing 1&lt;/span&gt; &lt;/caption&gt;
&lt;thead&gt;
&lt;tr class="header"&gt;
&lt;th align="left"&gt;rank&lt;/th&gt;
&lt;th align="center"&gt;R. F1&lt;/th&gt;
&lt;th align="left"&gt;Function (Basic Block)&lt;/th&gt;
&lt;th align="left"&gt;rank&lt;/th&gt;
&lt;th align="center"&gt;R. F1&lt;/th&gt;
&lt;th align="left"&gt;Function (BB)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;1.5&lt;/td&gt;
&lt;td align="center"&gt;0.98&lt;/td&gt;
&lt;td align="left"&gt;Node.Has (2)&lt;/td&gt;
&lt;td align="left"&gt;6&lt;/td&gt;
&lt;td align="center"&gt;0.95&lt;/td&gt;
&lt;td align="left"&gt;Node.Has (3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;1.5&lt;/td&gt;
&lt;td align="center"&gt;0.98&lt;/td&gt;
&lt;td align="left"&gt;Node.String (3)&lt;/td&gt;
&lt;td align="left"&gt;7.5&lt;/td&gt;
&lt;td align="center"&gt;0.94&lt;/td&gt;
&lt;td align="left"&gt;main (1)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;1.5&lt;/td&gt;
&lt;td align="center"&gt;0.98&lt;/td&gt;
&lt;td align="left"&gt;Node.Verify (4)&lt;/td&gt;
&lt;td align="left"&gt;7.5&lt;/td&gt;
&lt;td align="center"&gt;0.94&lt;/td&gt;
&lt;td align="left"&gt;Scanner.Scan (24)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;4&lt;/td&gt;
&lt;td align="center"&gt;0.97&lt;/td&gt;
&lt;td align="left"&gt;Node.Has (4)&lt;/td&gt;
&lt;td align="left"&gt;7.5&lt;/td&gt;
&lt;td align="center"&gt;0.94&lt;/td&gt;
&lt;td align="left"&gt;Node.Verify (0)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;4&lt;/td&gt;
&lt;td align="center"&gt;0.97&lt;/td&gt;
&lt;td align="left"&gt;Node.Has (6)&lt;/td&gt;
&lt;td align="left"&gt;&lt;/td&gt;
&lt;td align="center"&gt;&lt;/td&gt;
&lt;td align="left"&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;img src="images/scam/markov-rank-list.png" alt="image" /&gt;
&lt;div style="margin-top: -2em; margin-right: 2em; margin-left: 2em;"&gt;
&lt;strong&gt;Fig. 1:&lt;/strong&gt; A simplified version of the Markov model for evaluating the ranked list of suspicious locations for the bug in Listing 1.
&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;
&lt;img src="images/scam/markov-rank-list-with-jumps.png" alt="image" /&gt;
&lt;div style="margin-top: -2em; margin-right: 2em; margin-left: 2em;"&gt;
&lt;strong&gt;Fig. 2:&lt;/strong&gt; An example Markov model showing how “jump” edges can be added to represent how a programmer might examine locations which are near the location they are currently reviewing. Compare to Figure 1.
&lt;/div&gt;
&lt;/p&gt;
&lt;p&gt;This section introduces our new evaluation metric &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;. &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; produces a "rank score" similar to the score produced by the Standard Rank Score of Definition 17. In the standard score, program locations are ranked by their CBSFL suspiciousness scores. A location's position in the ordered list is that location's Rank Score (see the definition for details).&lt;/p&gt;
&lt;p&gt;The new &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; score is obtained as follows:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;A Markov debugging model is supplied (as a Markov chain).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The expected hitting times (Def. 22) for each location in the program are computed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The locations are ordered by their expected hitting times.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; for a location is its position in the ordered list.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 id="definition.-textrmht_textrmrank"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; and a Markov chain &lt;span class="math inline"&gt;\((S, {\bf P})\)&lt;/span&gt; that represents the debugging process and has start state &lt;span class="math inline"&gt;\(0\)&lt;/span&gt;, the Hitting-Time Rank Score &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; for a location &lt;span class="math inline"&gt;\(l \in L\cap S\)&lt;/span&gt; is: &lt;span class="math display"&gt;\[\begin{aligned}
    &amp;amp; {{\left|{ \left\{ x ~:~
        x \in L \cap S \wedge
        {\textrm{E}\left[{T_{0,x}}\right]} &amp;lt; {\textrm{E}\left[{T_{0,l}}\right]}
        \right\}
    }\right|}} +
    \\
    &amp;amp; \frac{
        {{\left|{ \left\{ x ~:~
        x \in L \cap S \wedge
        {\textrm{E}\left[{T_{0,x}}\right]} = {\textrm{E}\left[{T_{0,l}}\right]} \right\}
        }\right|}}
    }{
      2
    }
  \end{aligned}\]&lt;/span&gt; Note: this is almost identical to Definition 17, but it replaces the suspiciousness score with the expected hitting time. Definition 18 can also be modified in a similar way for multi-fault programs.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="markov-debugging-models"&gt;Markov Debugging Models&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; is parameterized by a "debugging model" expressed as a Markov chain. As noted above, a Markov chain is made up a of set of states &lt;span class="math inline"&gt;\(S\)&lt;/span&gt; and transition matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt;. In a debugging model, there are two types of states: 1) textual locations in the source code of a program and 2) synthetic states. Figures 6 and 7 show examples of debugging models constructed for an implementation of an AVL tree. In the figures, the square nodes are Markov states representing basic blocks in the source code. (Note that CBSFL techniques typically compute the same suspiciousness score for all statements in a basic block.) The smaller, circular nodes are Markov states which are synthetic. They are there for structural reasons but do not represent particular locations in the source code. The edges in the graphs represent possible transitions between states, and they are annotated with transition probabilities. All outgoing edges from a node should sum to 1.&lt;/p&gt;
&lt;p&gt;In a Markov debugging model a programmer is represented by the Markov process. When the Markov process is simulated the debugging actions of a programmer are being simulated. This is a "first order" simulation, which means the actions of the simulated programmer (Markov process) only depend on the current location being examined. Thus, the Markov model provides a simple and easy-to-construct mathematical model of a programmer looking through the source code of a program to find the faulty statement(s). The simulated programmer begins at some starting state and moves from state to state until the faulty location is found. We require that all Markov models are &lt;em&gt;ergodic&lt;/em&gt;, ensuring that every state (program location) is eventually reachable in the model.&lt;/p&gt;
&lt;h2 id="an-extensible-markov-model-for-cbsfl"&gt;An Extensible Markov Model for CBSFL&lt;/h2&gt;
&lt;p&gt;As described in Section 12 a CBSFL report is made up of a ranked list of locations in the subject program. Our extensible Markov model includes a representation of the CBSFL ranked list. By itself, using &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; with a Markov model of a ranked list is just a mathematically complex way of restating Definition 17. However, with a Markov model of a CBSFL report in hand we can add further connections &lt;em&gt;between&lt;/em&gt; program locations (represented as Markov states) to represent other actions a programmer might take besides traversing down the ranked list. For instance, in Section 25 we note that programmers use graphical debuggers to traverse the dynamic control flow in a program - allowing them to visit statements in the order they are executed. We embed the dynamic control flow graph into the transition matrix of the Markov model to reflect this observation.&lt;/p&gt;
&lt;h3 id="a-ranked-list-as-a-markov-chain"&gt;A Ranked List as a Markov Chain&lt;/h3&gt;
&lt;p&gt;Figure 6 provides a graphical example of a Markov chain for a ranked list. Since the nodes in a graphical representation of a Markov chain represent states and the edges represent the transition matrix, the probabilities associated with outgoing edges of each node should sum to 1. In Figure 6, each circular node represents a rank in the list and the square nodes represent associated program locations, which are identified by their function names and static basic-block id number. The square nodes that are grouped together all have the same suspiciousness scores. We will provide here a brief, informal description of the structure of the transition matrix. A formal description of the chain is provided in Definition 28 in the Appendix. The exact choice of transition matrix in the formal chain was driven by a proof of equivalence between &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; with this Markov model (as defined in Definition 28) and the Standard Rank Score (Definition 17).&lt;a href="#fn4" class="footnoteRef" id="fnref4"&gt;&lt;sup&gt;4&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The transition matrix boils down to a couple of simple connections. The nodes representing groups form a doubly linked list (see the circular nodes in Figure 6). The ordering of the "group nodes" matches the ordering of the ranks in the ranked list. The links between the node are weighted so that a Markov process will tend to end up in a highly ranked node. More formally, the model was constructed so that if you ordered the Markov states by the probabilities in the &lt;em&gt;stationary distribution&lt;/em&gt; (which characterizes the long term behavior of the Markov process) from highest to lowest that ordering would match the order of the ranked list.&lt;/p&gt;
&lt;p&gt;The second type of connection is from a group node to its program location nodes. Each location node connects to exactly one group node. The transition probabilities (as shown in Figure 6) are set up such that there is an equal chance of moving to any of the locations in the group.&lt;/p&gt;
&lt;p&gt;The final connection is from a location node back to its group node. This is always assigned probability &lt;span class="math inline"&gt;\(1\)&lt;/span&gt; (see Figure 6). Again, see Definition 28 in the Appendix for the formal description.&lt;/p&gt;
&lt;h3 id="adding-local-jumps-to-the-cbsfl-chain"&gt;Adding Local Jumps to the CBSFL Chain&lt;/h3&gt;
&lt;p&gt;Figure 7 shows a modified version of the model in Figure 6. The modified model allows the Markov process to jump or "teleport" between program locations which are not adjacent in the CBSFL Ranked List. These "jump" connections are setup to model other ways a programmer might move through the source code of a program when debugging (see below). In the figure, these jumps are shown with added red and blue edges. For the Markov model depicted in the figure, the Markov process will with probability &lt;span class="math inline"&gt;\(\frac{1}{2}\)&lt;/span&gt; move back to the rank list and with probability &lt;span class="math inline"&gt;\(\frac{1}{2}\)&lt;/span&gt; teleport or jump to an alternative program location that is structurally adjacent (in the program's source code) to the current one.&lt;/p&gt;
&lt;p&gt;Informally, the modified model is set up so that if the Markov process is in a state &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; which represents program location &lt;span class="math inline"&gt;\(l_x\)&lt;/span&gt; it will with probability &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; move to a state &lt;span class="math inline"&gt;\(s_j\)&lt;/span&gt; which represents program location &lt;span class="math inline"&gt;\(l_y\)&lt;/span&gt; instead of returning to the rank list. The locations that the process can move to from &lt;span class="math inline"&gt;\(s_i\)&lt;/span&gt; are defined in a jump matrix &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt; which is parameter to the Markov model. The matrix &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt; encodes assumptions or observations about how programmers behave when they are debugging. A formal definition of the CBSFL chain with jumps is presented in the Appendix (see Definition 29).&lt;/p&gt;
&lt;p&gt;Definition 26 defines one general-purpose jump matrix &lt;span class="math inline"&gt;\({\bf
J}\)&lt;/span&gt;. It encodes two assumptions about programmer behavior. First, when a programmer considers a location inside a function they will also potentially examine other locations in that function. Second, when a programmer is examining a location they may examine locations preceding or succeeding it the dynamic control flow (e.g., with the assistance of a graphical debugger). Definition 26 encodes both assumptions by setting the relevant &lt;span class="math inline"&gt;\({\bf
J}_{i,j}\)&lt;/span&gt; entries to &lt;span class="math inline"&gt;\(1\)&lt;/span&gt;.&lt;/p&gt;
&lt;h4 id="definition.-spacial-behavioral-jumps"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Spacial + Behavioral Jumps&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[\begin{aligned}
    {\bf J}_{i,j} &amp;amp;=
    \left\{
      \begin{array}{cll}
          1 &amp;amp;
          \text{if}
          &amp;amp;    \text{$s_i$ and $s_j$ represent locations} \\
          &amp;amp; &amp;amp;  \text{in the same function}
               \\
        \\
          1 &amp;amp;
          \text{if}
          &amp;amp;    \text{$s_i$ and $s_j$ are adjacent locations in the} \\
          &amp;amp; &amp;amp;  \text{program&amp;#39;s dynamic control flow graph} \\
        \\
          0
          &amp;amp; \text{otherwise}
      \end{array}
    \right.
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In addition to &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt;, the new chain is parameterized by the probability &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; of a jump occurring when the process visits a state representing a program location. As &lt;span class="math inline"&gt;\(p_{\text{jump}} \rightarrow 0\)&lt;/span&gt; the transition matrix of new chain approaches the transition matrix for the chain in Definition 28 (see the Appendix). We suggest setting &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; to &lt;span class="math inline"&gt;\(0.5\)&lt;/span&gt; in the absence of data from a user study.&lt;/p&gt;
&lt;h2 id="modeling-sbbfl"&gt;Modeling SBBFL&lt;/h2&gt;
&lt;p&gt;As noted earlier, Markov models can be constructed for alternative fault localization techniques. Suspicious Behavior Based Fault Localization (SBBFL) &lt;span class="citation"&gt;[&lt;a href="#ref-Cheng2009a"&gt;8&lt;/a&gt;], [&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt; techniques return a report containing a ranked list of subgraphs or subtrees. Each subgraph contains multiple program locations usually drawn from a dynamic control flow graph of the program. Comparing this output to CBSFL using the Standard Rank Score can be difficult as a location may appear multiple times in graphs returned by the SBBFL algorithm. However, &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; can produce an accurate and comparable score by utilizing the expected hitting times of the states representing the faulty location. Definition 30 in the Appendix provides an example Markov chain which models a ranked list of suspicious subgraphs. It can be extended (not shown due to space constraints) to add a Jump matrix in the manner of Definition 29 (see the Appendix).&lt;/p&gt;
&lt;h1 id="case-study"&gt;Case Study&lt;/h1&gt;
&lt;p&gt;To illustrate our new approach to evaluation, we performed a case study in which it was used to evaluate several fault localization techniques of two different types: CBSFL &lt;span class="citation"&gt;[&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;], [&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt; and Suspicious-Behavior-Based Fault Localization (SBBFL) &lt;span class="citation"&gt;[&lt;a href="#ref-Cheng2009a"&gt;8&lt;/a&gt;], [&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;. We investigated the following research questions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RQ1&lt;/strong&gt;: How Accurate is &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Estimation? (Table III)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RQ2&lt;/strong&gt;: Does it make a difference whether &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; or the Standard Rank Score is used? (Table IV, Figs. 5 and 4)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We also considered an important general question about fault localization that a typical research study might investigate.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;RQ3&lt;/strong&gt;: Which kind of fault localization technique performs better, SBBFL or CBSFL? (Table IV)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In order to use an SBBFL technique, more complex profiling data (dynamic control flow graphs or DCFGs) are needed than for CBSFL (which requires only coverage data). Therefore, a more specialized profiler was required for this study. We used Dynagrok (https://github.com/timtadh/dynagrok) &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt; - a profiling tool for the Go Programming Language. We also reused subject programs used in a previous study &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt; (see Table II). They are all real-world Go programs of various sizes that were injected with mutation faults. The test cases for the programs are all either real-world inputs or test cases from the system regression testing suites that are distributed with the programs. Six representative suspiciousness metrics were considered: Ochiai, F1, Jaccard, Relative Ochiai, Relative F1, and Relative Jaccard &lt;span class="citation"&gt;[&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;]&lt;/span&gt;. These measures were all previously adapted to the SBBFL context &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;

&lt;table&gt;
&lt;caption&gt; &lt;span style="font-variant: small-caps;"&gt;Table II: Datasets used in the evaluation&lt;/span&gt; &lt;/caption&gt;
&lt;thead&gt;
&lt;tr class="header"&gt;
&lt;th align="left"&gt;Program&lt;/th&gt;
&lt;th align="right"&gt;L.O.C.&lt;/th&gt;
&lt;th align="right"&gt;Mutants&lt;/th&gt;
&lt;th align="left"&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;AVL (github.com/timtadh/dynagrok)&lt;/td&gt;
&lt;td align="right"&gt;483&lt;/td&gt;
&lt;td align="right"&gt;19&lt;/td&gt;
&lt;td align="left"&gt;An AVL tree&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Blackfriday (github.com/russross/blackfriday)&lt;/td&gt;
&lt;td align="right"&gt;8,887&lt;/td&gt;
&lt;td align="right"&gt;19&lt;/td&gt;
&lt;td align="left"&gt;Markdown processor&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;HTML (golang.org/x/net/html)&lt;/td&gt;
&lt;td align="right"&gt;9,540&lt;/td&gt;
&lt;td align="right"&gt;20&lt;/td&gt;
&lt;td align="left"&gt;An HTML parser&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Otto (github.com/robertkrimen/otto)&lt;/td&gt;
&lt;td align="right"&gt;39,426&lt;/td&gt;
&lt;td align="right"&gt;20&lt;/td&gt;
&lt;td align="left"&gt;Javascript interpreter&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;&lt;span&gt;&lt;code&gt;gc&lt;/code&gt;&lt;/span&gt; (go.googlesource.com/go)&lt;/td&gt;
&lt;td align="right"&gt;51,873&lt;/td&gt;
&lt;td align="right"&gt;16&lt;/td&gt;
&lt;td align="left"&gt;The Go compiler&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div style="margin-right: 2em; margin-left: 2em;"&gt;
&lt;p&gt;Note: The AVL tree is in the examples directory.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;All applications of techniques were replicated to address random variation in the results as the SBBFL algorithm that we used employs sampling &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;. The results from the replications were averaged and, unless otherwise noted, the average Rank Scores are presented. Finally, the exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; score was computed for 4 of the 5 programs. For the fifth program, the Go compiler, although &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; can be computed exactly, this requires so much time for each run to complete (&lt;span class="math inline"&gt;\(\approx\)&lt;/span&gt; 4 hours) that it precluded computing exact results for each program version (including all models for both SBBFL and CBSFL). Therefore, expected hitting times for the Go compiler were estimated using the method outlined in Section 21. Specifically, we collected 500 samples of hitting times of all states in the Markov debugging model by taking random walks (with a maximum walk length of 1,000,000 steps). The expected hitting times were estimated by taking the sample mean.&lt;/p&gt;
&lt;h2 id="the-chosen-textrmht_textrmrank-model"&gt;The Chosen &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Model&lt;/h2&gt;
&lt;p&gt;To avoid bias, it was important to choose the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; model before the case study was conducted, which we did. We used &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; with jumps (Definition 29) together with the jump matrix specified in Definition 26. We chose this matrix because we believe the order in which programmers examine program elements during debugging is driven in part by the structure of the program, even when they are debugging with the assistance of a fault localization report. The &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; probability was set to &lt;span class="math inline"&gt;\(0.5\)&lt;/span&gt; to indicate an equal chance of the programmer using or not using the fault localization report. A future large scale user study could empirically characterize the behavior of programmers while performing debugging to inform the choice of the &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; parameter. However, without such a study it is reasonable to use &lt;span class="math inline"&gt;\(0.5\)&lt;/span&gt;, which indicates "no information."&lt;/p&gt;
&lt;h2 id="rq1-how-accurate-is-textrmht_textrmrank-estimation"&gt;RQ1: How Accurate is &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Estimation?&lt;/h2&gt;
&lt;table&gt;
&lt;caption&gt; &lt;span style="font-variant: small-caps;"&gt;&lt;span&gt;&lt;span class="math inline"&gt;Table III: \(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Estimation Error&lt;/span&gt; &lt;/caption&gt;
&lt;thead&gt;
&lt;tr class="header"&gt;
&lt;th align="left"&gt;Subject Program&lt;/th&gt;
&lt;th align="center"&gt;avl&lt;/th&gt;
&lt;th align="center"&gt;blackfriday&lt;/th&gt;
&lt;th align="center"&gt;html&lt;/th&gt;
&lt;th align="center"&gt;otto&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;mean   median   stdev   p-value&lt;/td&gt;
&lt;td align="center"&gt;0.781&lt;/td&gt;
&lt;td align="center"&gt;0.469&lt;/td&gt;
&lt;td align="center"&gt;0.473&lt;/td&gt;
&lt;td align="center"&gt;0.476&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div style="margin-right: 2em; margin-left: 2em;"&gt;
&lt;p&gt;Percentage error of the estimated &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; versus the exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; (see note under Def 22). Letting &lt;span class="math inline"&gt;\(y\)&lt;/span&gt; be the exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; and &lt;span class="math inline"&gt;\(\hat{y}\)&lt;/span&gt; be the estimated &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;, the percentage error is &lt;span class="math inline"&gt;\(\frac{|\hat{y} - y|}{y} * 100\)&lt;/span&gt;. &lt;span&gt;-2.0em&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;For large programs the cost of computing the expected hitting times for &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; may be too high. Therefore, we have suggested estimating the expected hitting times (see note under Definition 22). To assess the accuracy of estimating the expected hitting time instead of computing it exactly, we did both for four subject programs, using the Relative F1 measure. For each program version, SFL technique, and Markov chain type the estimation error was computed as a percentage of the true value. Table III presents descriptive statistics characterizing these errors for each subject program. The last row of the table gives p-values from a independent two-sample T-test comparing the estimated &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; values and the exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; values. The null hypothesis is that the expected estimate &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; is the same as the expected exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;. All p-values are well above the &lt;span class="math inline"&gt;\(0.05\)&lt;/span&gt; significance level that would suggest rejecting the null hypothesis. Therefore, we accept the null hypotheses that the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; estimates are not significantly different from the exact &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; values. As indicated in the table, the maximum estimation error was around 3.7%. Therefore, if estimation is used we recommend considering &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; scores that are within 5% of each other to be equivalent.&lt;/p&gt;
&lt;h2 id="rq2-does-it-make-a-difference-whether-textrmht_textrmrank-or-the-standard-rank-score-is-used"&gt;RQ2: Does it make a difference whether &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; or the Standard Rank Score is used? &lt;/h2&gt;
&lt;table&gt;
&lt;caption&gt; &lt;span style="font-variant: small-caps;"&gt;Table IV: Fault Localization Performance&lt;/span&gt; &lt;/caption&gt;
&lt;thead&gt;
&lt;tr class="header"&gt;
&lt;th align="left"&gt;&lt;/th&gt;
&lt;th align="left"&gt;&lt;/th&gt;
&lt;th align="center" colspan=3&gt;Standard Rank Score&lt;/th&gt;
&lt;th align="center" colspan=3&gt;HTRank Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;th align="left"&gt;score&lt;/td&gt;
&lt;th align="left"&gt;subject&lt;/td&gt;
&lt;th align="center"&gt;CBSFL&lt;/td&gt;
&lt;th align="center"&gt;SBBFL&lt;/td&gt;
&lt;th align="center"&gt; %&lt;span class="math inline"&gt;\(\Delta\)&lt;/span&gt; &lt;/td&gt;
&lt;th align="center"&gt;CBSFL&lt;/td&gt;
&lt;th align="center"&gt;SBBFL&lt;/td&gt;
&lt;th align="center"&gt; %&lt;span class="math inline"&gt;\(\Delta\)&lt;/span&gt; &lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeF1&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;9.1&lt;/td&gt;
&lt;td align="center"&gt;4.9&lt;/td&gt;
&lt;td align="center"&gt;-47 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeF1&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;8.8&lt;/td&gt;
&lt;td align="center"&gt;4.4&lt;/td&gt;
&lt;td align="center"&gt;-50 %&lt;/td&gt;
&lt;td align="center"&gt;42.6&lt;/td&gt;
&lt;td align="center"&gt;11.0&lt;/td&gt;
&lt;td align="center"&gt;-74 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeF1&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;40.7&lt;/td&gt;
&lt;td align="center"&gt;25.3&lt;/td&gt;
&lt;td align="center"&gt;-38 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeF1&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;8.2&lt;/td&gt;
&lt;td align="center"&gt;6.2&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;102.2&lt;/td&gt;
&lt;td align="center"&gt;21.5&lt;/td&gt;
&lt;td align="center"&gt;-79 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeF1&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;264.8&lt;/td&gt;
&lt;td align="center"&gt;98.9&lt;/td&gt;
&lt;td align="center"&gt;-63 %&lt;/td&gt;
&lt;td align="center"&gt;1148.9&lt;/td&gt;
&lt;td align="center"&gt;1475.1&lt;/td&gt;
&lt;td align="center"&gt;28 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeOchiai&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;7.6&lt;/td&gt;
&lt;td align="center"&gt;6.3&lt;/td&gt;
&lt;td align="center"&gt;-16 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeOchiai&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;8.8&lt;/td&gt;
&lt;td align="center"&gt;4.4&lt;/td&gt;
&lt;td align="center"&gt;-50 %&lt;/td&gt;
&lt;td align="center"&gt;43.6&lt;/td&gt;
&lt;td align="center"&gt;9.8&lt;/td&gt;
&lt;td align="center"&gt;-78 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeOchiai&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;38.2&lt;/td&gt;
&lt;td align="center"&gt;22.4&lt;/td&gt;
&lt;td align="center"&gt;-41 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeOchiai&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;8.7&lt;/td&gt;
&lt;td align="center"&gt;6.8&lt;/td&gt;
&lt;td align="center"&gt;-22 %&lt;/td&gt;
&lt;td align="center"&gt;99.2&lt;/td&gt;
&lt;td align="center"&gt;102.6&lt;/td&gt;
&lt;td align="center"&gt;3 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeOchiai&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;262.2&lt;/td&gt;
&lt;td align="center"&gt;101.6&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;2888.8&lt;/td&gt;
&lt;td align="center"&gt;2984.1&lt;/td&gt;
&lt;td align="center"&gt;3 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeJaccard&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;10.1&lt;/td&gt;
&lt;td align="center"&gt;5.1&lt;/td&gt;
&lt;td align="center"&gt;-50 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeJaccard&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;16.0&lt;/td&gt;
&lt;td align="center"&gt;12.1&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;80.0&lt;/td&gt;
&lt;td align="center"&gt;176.2&lt;/td&gt;
&lt;td align="center"&gt;120 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeJaccard&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;33.3&lt;/td&gt;
&lt;td align="center"&gt;24.4&lt;/td&gt;
&lt;td align="center"&gt;-27 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;RelativeJaccard&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;8.2&lt;/td&gt;
&lt;td align="center"&gt;6.3&lt;/td&gt;
&lt;td align="center"&gt;-23 %&lt;/td&gt;
&lt;td align="center"&gt;75.2&lt;/td&gt;
&lt;td align="center"&gt;19.9&lt;/td&gt;
&lt;td align="center"&gt;-74 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;RelativeJaccard&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;747.9&lt;/td&gt;
&lt;td align="center"&gt;482.0&lt;/td&gt;
&lt;td align="center"&gt;-36 %&lt;/td&gt;
&lt;td align="center"&gt;1074.1&lt;/td&gt;
&lt;td align="center"&gt;1540.5&lt;/td&gt;
&lt;td align="center"&gt;43 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;F1&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;10.4&lt;/td&gt;
&lt;td align="center"&gt;5.1&lt;/td&gt;
&lt;td align="center"&gt;-51 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;F1&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;16.0&lt;/td&gt;
&lt;td align="center"&gt;12.1&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;81.9&lt;/td&gt;
&lt;td align="center"&gt;218.8&lt;/td&gt;
&lt;td align="center"&gt;167 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;F1&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;33.9&lt;/td&gt;
&lt;td align="center"&gt;18.6&lt;/td&gt;
&lt;td align="center"&gt;-45 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;F1&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;8.2&lt;/td&gt;
&lt;td align="center"&gt;6.2&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;81.0&lt;/td&gt;
&lt;td align="center"&gt;28.5&lt;/td&gt;
&lt;td align="center"&gt;-65 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;F1&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;746.8&lt;/td&gt;
&lt;td align="center"&gt;470.4&lt;/td&gt;
&lt;td align="center"&gt;-37 %&lt;/td&gt;
&lt;td align="center"&gt;1047.0&lt;/td&gt;
&lt;td align="center"&gt;1537.9&lt;/td&gt;
&lt;td align="center"&gt;47 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Ochiai&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;5.9&lt;/td&gt;
&lt;td align="center"&gt;6.3&lt;/td&gt;
&lt;td align="center"&gt;7 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;Ochiai&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;14.8&lt;/td&gt;
&lt;td align="center"&gt;10.3&lt;/td&gt;
&lt;td align="center"&gt;-30 %&lt;/td&gt;
&lt;td align="center"&gt;51.2&lt;/td&gt;
&lt;td align="center"&gt;108.7&lt;/td&gt;
&lt;td align="center"&gt;112 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Ochiai&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;30.7&lt;/td&gt;
&lt;td align="center"&gt;25.3&lt;/td&gt;
&lt;td align="center"&gt;-18 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;Ochiai&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;10.3&lt;/td&gt;
&lt;td align="center"&gt;8.4&lt;/td&gt;
&lt;td align="center"&gt;-19 %&lt;/td&gt;
&lt;td align="center"&gt;312.8&lt;/td&gt;
&lt;td align="center"&gt;607.7&lt;/td&gt;
&lt;td align="center"&gt;94 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Ochiai&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;1091.6&lt;/td&gt;
&lt;td align="center"&gt;773.5&lt;/td&gt;
&lt;td align="center"&gt;-29 %&lt;/td&gt;
&lt;td align="center"&gt;3137.2&lt;/td&gt;
&lt;td align="center"&gt;2988.8&lt;/td&gt;
&lt;td align="center"&gt;-5 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;Jaccard&lt;/td&gt;
&lt;td align="left"&gt;avl&lt;/td&gt;
&lt;td align="center"&gt;4.6&lt;/td&gt;
&lt;td align="center"&gt;2.0&lt;/td&gt;
&lt;td align="center"&gt;-56 %&lt;/td&gt;
&lt;td align="center"&gt;10.1&lt;/td&gt;
&lt;td align="center"&gt;5.1&lt;/td&gt;
&lt;td align="center"&gt;-50 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Jaccard&lt;/td&gt;
&lt;td align="left"&gt;blackfriday&lt;/td&gt;
&lt;td align="center"&gt;16.0&lt;/td&gt;
&lt;td align="center"&gt;12.1&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;77.8&lt;/td&gt;
&lt;td align="center"&gt;187.7&lt;/td&gt;
&lt;td align="center"&gt;141 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;Jaccard&lt;/td&gt;
&lt;td align="left"&gt;html&lt;/td&gt;
&lt;td align="center"&gt;12.8&lt;/td&gt;
&lt;td align="center"&gt;5.0&lt;/td&gt;
&lt;td align="center"&gt;-61 %&lt;/td&gt;
&lt;td align="center"&gt;33.3&lt;/td&gt;
&lt;td align="center"&gt;24.6&lt;/td&gt;
&lt;td align="center"&gt;-26 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="even"&gt;
&lt;td align="left"&gt;Jaccard&lt;/td&gt;
&lt;td align="left"&gt;otto&lt;/td&gt;
&lt;td align="center"&gt;8.2&lt;/td&gt;
&lt;td align="center"&gt;6.2&lt;/td&gt;
&lt;td align="center"&gt;-24 %&lt;/td&gt;
&lt;td align="center"&gt;75.3&lt;/td&gt;
&lt;td align="center"&gt;24.7&lt;/td&gt;
&lt;td align="center"&gt;-67 %&lt;/td&gt;
&lt;/tr&gt;
&lt;tr class="odd"&gt;
&lt;td align="left"&gt;Jaccard&lt;/td&gt;
&lt;td align="left"&gt;compiler&lt;/td&gt;
&lt;td align="center"&gt;747.9&lt;/td&gt;
&lt;td align="center"&gt;485.4&lt;/td&gt;
&lt;td align="center"&gt;-35 %&lt;/td&gt;
&lt;td align="center"&gt;1078.8&lt;/td&gt;
&lt;td align="center"&gt;1435.6&lt;/td&gt;
&lt;td align="center"&gt;33 %&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div style="margin-right: 2em; margin-left: 2em;"&gt;
&lt;p&gt;Summarizes the fault localization performance for CBSFL and SBBFL. Each fault localization technique is evaluated using both the Standard Rank Score and the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Score (Defs. 28 and 25). The mean rank scores are shown as well as the percentage changes from CBSFL to SBBFL. Lower ranks scores indicate better fault localization performance. A negative percentage difference (%&lt;span class="math inline"&gt;\(\Delta\)&lt;/span&gt;) indicates SBBFL &lt;strong&gt;improved&lt;/strong&gt; on CBSFL. A positive %&lt;span class="math inline"&gt;\(\Delta\)&lt;/span&gt; indicates CBSFL &lt;strong&gt;outperformed&lt;/strong&gt; SBBFL.&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;img src="images/scam/model-cmp-otto.png" title="Fig: 3" alt="Empirical probability density plots for the subject program Otto - showing the distributions of both the Standard Rank Scores and the HT_Rank Scores across all runs of all versions of Otto. The CBSFL technique is shown in blue and the SBBFL technique is shown in orange. The only suspciousness score used in this plot is RelativeF1." /&gt;
&lt;div style="margin-top: -2em; margin-right: 2em; margin-left: 2em;"&gt;
&lt;strong&gt;Fig 3:&lt;/strong&gt;
Empirical probability density plots for the subject program Otto - showing the distributions of both the Standard Rank Scores and the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Scores across all runs of all versions of Otto. The CBSFL technique is shown in blue and the SBBFL technique is shown in orange. The only suspciousness score used in this plot is RelativeF1. 
&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;
&lt;img src="images/scam/cbsfl-vs-sbbfl-by-rank-score.png" alt=" Comparison of CBSFL vs SBBFL average ranks (on log scale), under the Standard Rank Score (top) and HT_Rank (bottom), for each version of the program Otto; suspiciousness metric is RelativeF1. " /&gt;
&lt;img style="margin-top: -2em;" src="images/scam/cbsfl-vs-sbbfl-by-htrank.png" alt=" Comparison of CBSFL vs SBBFL average ranks (on log scale), under the Standard Rank Score (top) and HT_Rank (bottom), for each version of the program Otto; suspiciousness metric is RelativeF1. " /&gt;
&lt;div style="margin-top: -2em; margin-right: 2em; margin-left: 2em;"&gt;
&lt;strong&gt;Fig 4:&lt;/strong&gt;
Comparison of CBSFL vs SBBFL average ranks (on log scale), under the Standard Rank Score (top) and &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; (bottom), for each version of the program Otto; suspiciousness metric is RelativeF1.
&lt;/div&gt;
&lt;/p&gt;

&lt;p&gt;Table IV details the fault localization performance we observed for CBSFL and SBBFL under the Standard Rank Score and &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; using six different suspiciousness metrics. The results obtained with &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; were substantially different from those obtained with the Standard Rank Score, in terms of absolute ranks and percentage differences (%&lt;span class="math inline"&gt;\(\Delta\)&lt;/span&gt;). The mean Standard Rank Score for SBBFL is lower than that for CBSFL for &lt;em&gt;every&lt;/em&gt; suspiciousness metric and subject program. By contrast, for some programs and metrics, the mean &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; scores for CBSFL are lower than those for SBBFL. The mean &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; scores are also higher than the mean Standard Rank Scores overall.&lt;/p&gt;
&lt;p&gt;Another way to look at the same phenomenon is shown in Figure 5, which displays empirical probability density plots for the program Otto. Each plot compares the performance of CBSFL to SBBFL using a different evaluation method. The top plot uses the Standard Rank Score while the other plot uses &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;. As shown in the top plot, the Standard Rank Scores for both CBSFL and SBBFL are concentrated mainly between 0 and 15, with no values over 60. In the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; plot, by contrast, the scores for both CBSFL and SBBFL are much more widely dispersed. Figure 4 compares CBSFL to SBBFL with respect to average ranks (on a log scale), under the Standard Rank Score (top) and &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; (bottom), for each version of the program Otto. The suspiciousness metric is RelativeF1. The results for &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; are quite distict from those for the Standard Rank Score, with CBSFL showing much more variability under &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;These results provide confirmation for the theoretical motivation for &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;. Recall that one of the problems with the Standard Rank Score is that it does not account for either the differing structures of fault localization reports or differences in report granularity. SBBFL and CBSFL differ in both structure (ranked CFG fragments vs. ranked basic blocks) and granularity (multiple basic blocks vs. lone basic blocks). We expected the Standard Rank Score to unfairly favor SBBFL because it does not account for these differences and that is exactly what we see in Table IV. Under the Standard Rank Score SBBFL outperforms CBSFL on every program using every suspiciousness score.&lt;/p&gt;
&lt;p&gt;To be explicit, SBBFL reports ranked CFG fragments, each of which contains multiple basic blocks. Under the Standard Rank Score those fragments are ranked and the score is the rank of the first fragment in which the bug appears. CBSFL will, by contrast, rank each basic block independently. Now, consider the case where SBBFL reports a CFG fragment at rank 1 that contains 10 basic blocks, one of which contains the bug. Suppose CBSFL also reports each of those basic blocks as maximally suspicious. The Standard Rank Score for CBSFL will be 5 while for SBBFL it will be 1. Thus, the Standard Rank Score is unfairly biased toward SBBFL and against CBSFL. This is once again reflected in Table IV. The new metric &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; does not suffer from this problem. As shown in the table and discussed below, SBBFL often but not always outperforms CBSFL under &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;, suggesting that the theoretical correction we expect is indeed occurring. We therefore conclude that &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; provides a better metric for comparison when reports differ in structure and granularity.&lt;/p&gt;
&lt;h2 id="rq3-which-kind-of-fault-localization-technique-performs-better-sbbfl-or-cbsfl"&gt;RQ3: Which kind of fault localization technique performs better, SBBFL or CBSFL?&lt;/h2&gt;
&lt;p&gt;Referring once again to Table IV, the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; results indicate that SBBFL often but not always outperformed CBSFL. In particular, when the measure used was Relative F1 (which was found to be the best-performing measure for SBBFL in &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;), SBBFL performed better for all programs but the compiler. However, when Ochiai was used CBSFL outperformed SBBFL, although CBSFL with Relative F1 outperforms CBSFL with Ochiai. This indicates that SBBFL and Relative F1 may be the best combination tested with one caveat. For the compiler, SBBFL never outperforms CBSFL. However, CBSFL also performs very badly on this large program. This indicates that while CBSFL beats SBBFL on this program neither technique is effective at localizing faults in it.&lt;/p&gt;
&lt;h2 id="study-limitations"&gt;Study Limitations&lt;/h2&gt;
&lt;p&gt;The purpose of our case study is to illustrate the application of &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt;. It was not designed to settle controversies about the suspiciousness metrics we employed. Second, this study used real programs and tests but used synthetic bugs. In the future, we intend to provide an automated analysis system that builds upon the Defects4J dataset &lt;span class="citation"&gt;[&lt;a href="#ref-Just2014"&gt;52&lt;/a&gt;]&lt;/span&gt;. Third, our study included a representative but not exhaustive set of suspiciousness metrics &lt;span class="citation"&gt;[&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;]&lt;/span&gt; and may not generalize to other metrics.&lt;/p&gt;
&lt;p&gt;Finally, no user-study was performed to validate the chosen debugging model against actions an actual programmer would take. Although we would have liked to perform such a study at this time, our resources do not permit us to do so. To be conclusive, such a study would need to be large-scale and to utilize professional programmers who are skilled in traditional debugging and are able to spend significant time learning to use SFL techniques with comparable skill.&lt;/p&gt;
&lt;h1 id="discussion"&gt;Discussion&lt;/h1&gt;
&lt;p&gt;A new, flexible approach to evaluating automatic fault localization techniques was presented. The new &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Score provides a principled and flexible way of comparing different fault localization techniques. It is robust to differences in granularity and allows complex fault localization reports (such as those produced by SBBFL) to be incorporated. Unlike previous attempts at cross-technique comparison (see Section 12) the final scores are based on the expected number of steps through a Markov model. The model can incorporate both information from the chosen fault localization technique as well as other information available to the programmer (such as the structure of the program). The &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Score is sensitive to the model used (see Fig 5) and hence the choice of model is important. The choice should be made based on 1) the fault localization technique(s) being evaluated and 2) observations of programmer behavior. Choosing a model after viewing the results (and picking the model that gives the "best" results) leads to a biased outcome.&lt;/p&gt;
&lt;h2 id="recommendations-for-researchers" class="unnumbered"&gt;Recommendations for Researchers&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Report both Standard Rank Score and &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Score.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If evaluating multi-line faults the Steinmann Rank Score (Def. 18) should be used as the basis for defining the &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; Score.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Report which model is being used and why it was chosen, and include a description of the model.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the absence of user study data, set &lt;span class="math inline"&gt;\(p_{\text{jump}} = .5\)&lt;/span&gt; and set the weights in &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt; uniformly.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By evaluating fault localization methods with &lt;span&gt;&lt;span class="math inline"&gt;\(\textrm{HT}_{\textrm{Rank}}\)&lt;/span&gt;&lt;/span&gt; in addition to the Standard Rank Score researchers will be able to make valid cross-technique comparisons. This will enable the community to better understand the relationships between techniques and report-granularity while taking into account potential programmer behavior during debugging.&lt;/p&gt;
&lt;h1 id="acknowledgement" class="unnumbered"&gt;Acknowledgement&lt;/h1&gt;
&lt;p&gt;This work was partially supported by NSF award CCF-1525178 to Case Western Reserve University.&lt;/p&gt;
&lt;h1 id="markov-chain-definitions"&gt;Markov Chain Definitions&lt;/h1&gt;
&lt;h4 id="definition.-cbsfl-ranked-list-markov-chain"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. CBSFL Ranked List Markov Chain&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;To construct a Markov chain representing a list of program locations ranked in descending order by their suspiciousness scores:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; be the set of locations in the program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For a location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; let &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; be its CBSFL suspiciousness score.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Partition the locations in &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; into a list of groups &lt;span class="math inline"&gt;\(G = \left\{ g_1 \subseteq L, g_2 \subseteq L, ..., g_n \subseteq L \right\}\)&lt;/span&gt; such that for each group &lt;span class="math inline"&gt;\(g_i\)&lt;/span&gt; all of the locations it contains have the same score: &lt;span class="math inline"&gt;\( \forall ~ {g_i \in G}, ~ \forall ~ {l, l&amp;#39; \in g_i} \left[
        s(l) = s(l&amp;#39;) \right]\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The score of a group &lt;span class="math inline"&gt;\(s(g_i)\)&lt;/span&gt; is defined to be the common score of its members: &lt;span class="math inline"&gt;\( \forall ~ {l \in g_i} \left[ s(g_i) = s(l) \right]\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Order &lt;span class="math inline"&gt;\(G\)&lt;/span&gt; by the scores of its groups, such that &lt;span class="math inline"&gt;\(g_0\)&lt;/span&gt; has the highest score and &lt;span class="math inline"&gt;\(g_n\)&lt;/span&gt; has the lowest: &lt;span class="math inline"&gt;\(s(g_0) &amp;gt; s(g_1) &amp;gt; ... &amp;gt; s(g_n)\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now construct the set of states. There is one state for each group &lt;span class="math inline"&gt;\(g
      \in G\)&lt;/span&gt; and for each location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt;. &lt;span class="math display"&gt;\[S =
          \left\{ g : g \in G \right\}
          \cup
          \left\{ l : l \in L \right\}\]&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally construct the transition matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt; for the states &lt;span class="math inline"&gt;\(S\)&lt;/span&gt;. &lt;span class="math display"&gt;\[{\bf P}_{i,j} =
      \left\{
        \begin{array}{lll}
           1 &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in L \wedge s_j \in G \wedge s_i \in s_j \\
          \\
             \frac{{{\left|{L}\right|}} - 1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_0 \wedge s_j = s_i \\
          \\
             \frac{1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_n \wedge s_j = s_i \\
          \\
            \frac{{{\left|{L}\right|}} - 1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i - 1 = s_j \\
          \\
            \frac{1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i + 1 = s_j \\
          \\
            \frac{1}{2{{\left|{s_i}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in L \wedge s_j \in s_i \\
          \\
            0
            &amp;amp; \text{otherwise}
        \end{array}
      \right.\]&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h4 id="definition.-cbsfl-with-jumps-markov-chain"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. CBSFL with Jumps Markov Chain&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This definition augments Definition 28.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt; be a "jump" matrix representing ways a programmer might move through the program during debugging.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If &lt;span class="math inline"&gt;\({\bf J}_{x,y} &amp;gt; 0\)&lt;/span&gt; then locations &lt;span class="math inline"&gt;\(x,y \in L\)&lt;/span&gt; are "connected" by &lt;span class="math inline"&gt;\({\bf J}\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\(p_{\text{jump}}\)&lt;/span&gt; be the probability that when visiting a location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; the Markov process "jumps" to another location. Let &lt;span class="math inline"&gt;\(1 -
      p_{\text{jump}}\)&lt;/span&gt; be the probability that the process returns to the state which represents its group instead of jumping. As &lt;span class="math inline"&gt;\(p_\text{{jump}}
      \rightarrow 0\)&lt;/span&gt; the behavior of the chain approaches the behavior of the chain in Definition 28.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The new transition matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt; for the states &lt;span class="math inline"&gt;\(S\)&lt;/span&gt; is&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span class="math display"&gt;\[\begin{aligned}
      {\bf P}_{i,j} &amp;amp;=
      \left\{
        \begin{array}{cll}
            1 - p_{\text{jump}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in L \wedge s_j \in G \wedge s_i \in s_j \\
            &amp;amp; &amp;amp;  \wedge \left( \sum_{k}{{\bf J}_{i,k}} \right) &amp;gt; 0 \\
          \\
              p_{\text{jump}}
              \left( \frac{{\bf J}_{i,j}}{\sum_{k}{{\bf J}_{i,k}}} \right)
            &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in L \wedge s_j \in L \wedge {\bf J}_{i,j} &amp;gt; 0 \\
          \\
            \frac{{{\left|{L}\right|}} - 1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_0 \wedge s_j = s_i \\
          \\
            \frac{1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_n \wedge s_j = s_i \\
          \\
            \frac{{{\left|{L}\right|}} - 1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i - 1 = s_j \\
          \\
            \frac{1}{2{{\left|{L}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i + 1 = s_j \\
          \\
            \frac{1}{2{{\left|{s_i}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in L \wedge s_j \in s_i \\
          \\
            0
            &amp;amp; \text{otherwise}
        \end{array}
      \right.
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4 id="definition.-suspicious-behavior-markov-chain"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Suspicious Behavior Markov Chain&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;A chain that models a ranked list of suspicious subgraphs:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\(H\)&lt;/span&gt; be a set of suspicious subgraphs (behaviors).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;For a subgraph &lt;span class="math inline"&gt;\(h \in H\)&lt;/span&gt; let &lt;span class="math inline"&gt;\(\varsigma(h)\)&lt;/span&gt; be its suspiciousness score &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;9&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; be the set of locations in the program.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Partition the subgraphs in &lt;span class="math inline"&gt;\(H\)&lt;/span&gt; into a list of groups &lt;span class="math inline"&gt;\(G = \left\{ g_1 \subseteq H, g_2 \subseteq H, ..., g_n \subseteq H \right\}\)&lt;/span&gt; such that for each group &lt;span class="math inline"&gt;\(g_i\)&lt;/span&gt; all of the locations in &lt;span class="math inline"&gt;\(g_i\)&lt;/span&gt; have the same score: &lt;span class="math inline"&gt;\(\forall ~ {g_i \in G} ~ \forall ~ {a, b \in g_i} \left[
        \varsigma(a) = \varsigma(b) \right]\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let the score of a group &lt;span class="math inline"&gt;\(\varsigma(g_i)\)&lt;/span&gt; be the same as the scores of its members: &lt;span class="math inline"&gt;\( \forall ~ {g_i \in G} ~ \forall ~ {h \in g_i} \left[
        \varsigma(g_i) = \varsigma(h) \right]\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Order &lt;span class="math inline"&gt;\(G\)&lt;/span&gt; by the scores of its groups, such that &lt;span class="math inline"&gt;\(g_0\)&lt;/span&gt; has the highest score and &lt;span class="math inline"&gt;\(g_n\)&lt;/span&gt; has the lowest: &lt;span class="math inline"&gt;\( \varsigma(g_0) &amp;gt; \varsigma(g_1) &amp;gt; ... &amp;gt;
      \varsigma(g_n)\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Now construct the set of states. One state for each group &lt;span class="math inline"&gt;\(g \in G\)&lt;/span&gt;, one state for each subgraph &lt;span class="math inline"&gt;\(h \in H\)&lt;/span&gt;, and one state for each location &lt;span class="math inline"&gt;\(l
      \in V_{h}\)&lt;/span&gt; for all &lt;span class="math inline"&gt;\(h \in H\)&lt;/span&gt;. &lt;span class="math display"&gt;\[S =
          \left\{ g : g \in G \right\}
          \cup
          \left\{ h : h \in H \right\}
          \cup
          \left\{ l : l \in V_h,~ \forall~ h \in H \right\}\]&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Let &lt;span class="math inline"&gt;\(c: L \rightarrow \mathbb{N}^{+}\)&lt;/span&gt; be a function that gives the number of subgraphs &lt;span class="math inline"&gt;\(h \in H\)&lt;/span&gt; which a location &lt;span class="math inline"&gt;\(l\)&lt;/span&gt; appears in.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Finally construct the transition matrix &lt;span class="math inline"&gt;\({\bf P}\)&lt;/span&gt; for the states &lt;span class="math inline"&gt;\(S\)&lt;/span&gt;. &lt;span class="math display"&gt;\[{\bf P}_{i,j} =
      \left\{
        \begin{array}{cll}
            \frac{1}{c(s_i)} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in L \wedge s_j \in H \wedge s_i \in V_{s_j} \\
         \\
            \frac{1}{2}\frac{1}{{{\left|{V_{s_i}}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in H \wedge s_j \in L \wedge s_j \in V_{s_i} \\
          \\
            \frac{1}{2} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in H \wedge s_j \in G \wedge s_i \in s_j \\
          \\
            \frac{{{\left|{H}\right|}} - 1}{2{{\left|{H}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_0 \wedge s_j = s_i \\
          \\
            \frac{1}{2{{\left|{H}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i = g_n \wedge s_j = s_i \\
          \\
            \frac{{{\left|{H}\right|}} - 1}{2{{\left|{H}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i - 1 = s_j \\
          \\
            \frac{1}{2{{\left|{H}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in G \wedge s_i + 1 = s_j \\
          \\
            \frac{1}{2{{\left|{s_i}\right|}}} &amp;amp;
            \text{if}
            &amp;amp;
                 s_i \in G \wedge s_j \in H \wedge s_j \in s_i \\
          \\
            0
            &amp;amp; \text{otherwise}
        \end{array}
      \right.\]&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;div id="refs" class="references"&gt;
&lt;h1&gt;References&lt;/h1&gt;
&lt;div id="ref-Jones2002"&gt;
&lt;p&gt;[1] J. Jones, M. Harrold, and J. Stasko, "Visualization of test information to assist fault localization," &lt;em&gt;Proceedings of the 24th International Conference on Software Engineering. ICSE 2002&lt;/em&gt;, 2002, doi:&lt;a href="https://doi.org/10.1145/581339.581397"&gt;10.1145/581339.581397&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Lucia2014"&gt;
&lt;p&gt;[2] Lucia, D. Lo, L. Jiang, F. Thung, and A. Budi, "Extended comprehensive study of association measures for fault localization," &lt;em&gt;Journal of Software: Evolution and Process&lt;/em&gt;, vol. 26, no. 2, pp. 172-219, Feb. 2014, doi:&lt;a href="https://doi.org/10.1002/smr.1616"&gt;10.1002/smr.1616&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Sun2016"&gt;
&lt;p&gt;[3] S.-F. Sun and A. Podgurski, "Properties of Effective Metrics for Coverage-Based Statistical Fault Localization," in &lt;em&gt;2016 ieee international conference on software testing, verification and validation (icst)&lt;/em&gt;, 2016, pp. 124-134, doi:&lt;a href="https://doi.org/10.1109/ICST.2016.31"&gt;10.1109/ICST.2016.31&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Jones2005"&gt;
&lt;p&gt;[4] J. A. Jones and M. J. Harrold, "Empirical Evaluation of the Tarantula Automatic Fault-localization Technique," in &lt;em&gt;Proceedings of the 20th ieee/acm international conference on automated software engineering&lt;/em&gt;, 2005, pp. 273-282, doi:&lt;a href="https://doi.org/10.1145/1101908.1101949"&gt;10.1145/1101908.1101949&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Pearson2017"&gt;
&lt;p&gt;[5] S. Pearson, J. Campos, R. Just, G. Fraser, R. Abreu, M. D. Ernst, D. Pang, and B. Keller, "Evaluating and Improving Fault Localization," in &lt;em&gt;Proceedings of the 39th international conference on software engineering&lt;/em&gt;, 2017, pp. 609-620, doi:&lt;a href="https://doi.org/10.1109/ICSE.2017.62"&gt;10.1109/ICSE.2017.62&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Parnin2011"&gt;
&lt;p&gt;[6] C. Parnin and A. Orso, "Are Automated Debugging Techniques Actually Helping Programmers?" in &lt;em&gt;ISSTA&lt;/em&gt;, 2011, pp. 199-209.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Renieres2003"&gt;
&lt;p&gt;[7] M. Renieres and S. Reiss, "Fault localization with nearest neighbor queries," in &lt;em&gt;18th ieee international conference on automated software engineering, 2003. proceedings.&lt;/em&gt;, 2003, pp. 30-39, doi:&lt;a href="https://doi.org/10.1109/ASE.2003.1240292"&gt;10.1109/ASE.2003.1240292&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Cheng2009a"&gt;
&lt;p&gt;[8] H. Cheng, D. Lo, Y. Zhou, X. Wang, and X. Yan, "Identifying Bug Signatures Using Discriminative Graph Mining," in &lt;em&gt;Proceedings of the eighteenth international symposium on software testing and analysis&lt;/em&gt;, 2009, pp. 141-152, doi:&lt;a href="https://doi.org/10.1145/1572272.1572290"&gt;10.1145/1572272.1572290&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Henderson2018"&gt;
&lt;p&gt;[9] T. A. D. Henderson and A. Podgurski, "Behavioral Fault Localization by Sampling Suspicious Dynamic Control Flow Subgraphs," in &lt;em&gt;IEEE conference on software testing, validation and verification&lt;/em&gt;, 2018.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Baah2010"&gt;
&lt;p&gt;[10] G. G. K. Baah, A. Podgurski, and M. J. M. Harrold, "Causal inference for statistical fault localization," in &lt;em&gt;Proceedings of the 19th international symposium on software testing and analysis&lt;/em&gt;, 2010, pp. 73-84, doi:&lt;a href="https://doi.org/10.1145/1831708.1831717"&gt;10.1145/1831708.1831717&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Aggarwal2014"&gt;
&lt;p&gt;[11] C. C. Aggarwal and J. Han, Eds., &lt;em&gt;Frequent Pattern Mining&lt;/em&gt;. Cham: Springer International Publishing, 2014.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agrawal1993"&gt;
&lt;p&gt;[12] R. Agrawal, T. Imieliński, and A. Swami, "Mining association rules between sets of items in large databases," &lt;em&gt;ACM SIGMOD Record&lt;/em&gt;, vol. 22, no. 2, pp. 207-216, Jun. 1993, doi:&lt;a href="https://doi.org/10.1145/170036.170072"&gt;10.1145/170036.170072&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yan2002"&gt;
&lt;p&gt;[13] X. Yan and J. Han, "gSpan: graph-based substructure pattern mining," in &lt;em&gt;2002 ieee international conference on data mining, 2002. proceedings.&lt;/em&gt;, 2002, pp. 721-724, doi:&lt;a href="https://doi.org/10.1109/ICDM.2002.1184038"&gt;10.1109/ICDM.2002.1184038&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Aggarwal2014a"&gt;
&lt;p&gt;[14] C. C. Aggarwal, M. A. Bhuiyan, and M. A. Hasan, "Frequent Pattern Mining Algorithms: A Survey," in &lt;em&gt;Frequent pattern mining&lt;/em&gt;, Cham: Springer International Publishing, 2014, pp. 19-64.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yan2008"&gt;
&lt;p&gt;[15] X. Yan, H. Cheng, J. Han, and P. S. Yu, "Mining Significant Graph Patterns by Leap Search," in &lt;em&gt;Proceedings of the 2008 acm sigmod international conference on management of data&lt;/em&gt;, 2008, pp. 433-444, doi:&lt;a href="https://doi.org/10.1145/1376616.1376662"&gt;10.1145/1376616.1376662&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Abreu2006"&gt;
&lt;p&gt;[16] R. Abreu, P. Zoeteweij, and A. Van Gemund, "An Evaluation of Similarity Coefficients for Software Fault Localization," in &lt;em&gt;2006 12th pacific rim international symposium on dependable computing (prdc'06)&lt;/em&gt;, 2006, pp. 39-46, doi:&lt;a href="https://doi.org/10.1109/PRDC.2006.18"&gt;10.1109/PRDC.2006.18&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Abreu2009"&gt;
&lt;p&gt;[17] R. Abreu, P. Zoeteweij, R. Golsteijn, and A. J. C. van Gemund, "A practical evaluation of spectrum-based fault localization," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 82, no. 11, pp. 1780-1792, 2009, doi:&lt;a href="https://doi.org/10.1016/j.jss.2009.06.035"&gt;10.1016/j.jss.2009.06.035&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agarwal2014"&gt;
&lt;p&gt;[18] P. Agarwal and A. P. Agrawal, "Fault-localization Techniques for Software Systems: A Literature Review," &lt;em&gt;SIGSOFT Softw. Eng. Notes&lt;/em&gt;, vol. 39, no. 5, pp. 1-8, Sep. 2014, doi:&lt;a href="https://doi.org/10.1145/2659118.2659125"&gt;10.1145/2659118.2659125&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Wong2016"&gt;
&lt;p&gt;[19] W. E. Wong, R. Gao, Y. Li, R. Abreu, and F. Wotawa, "A Survey on Software Fault Localization," &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt;, vol. 42, no. 8, pp. 707-740, Aug. 2016, doi:&lt;a href="https://doi.org/10.1109/TSE.2016.2521368"&gt;10.1109/TSE.2016.2521368&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zeller1999"&gt;
&lt;p&gt;[20] A. Zeller, "Yesterday, My Program Worked. Today, It Does Not. Why?" &lt;em&gt;SIGSOFT Softw. Eng. Notes&lt;/em&gt;, vol. 24, no. 6, pp. 253-267, Oct. 1999, doi:&lt;a href="https://doi.org/10.1145/318774.318946"&gt;10.1145/318774.318946&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Tip1995"&gt;
&lt;p&gt;[21] F. Tip, "A survey of program slicing techniques," &lt;em&gt;Journal of programming languages&lt;/em&gt;, vol. 3, no. 3, pp. 121-189, 1995.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Mao2014"&gt;
&lt;p&gt;[22] X. Mao, Y. Lei, Z. Dai, Y. Qi, and C. Wang, "Slice-based statistical fault localization," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 89, no. 1, pp. 51-62, 2014, doi:&lt;a href="https://doi.org/10.1016/j.jss.2013.08.031"&gt;10.1016/j.jss.2013.08.031&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Marcus2004"&gt;
&lt;p&gt;[23] A. Marcus, A. Sergeyev, V. Rajlieh, and J. I. Maletic, "An information retrieval approach to concept location in source code," &lt;em&gt;Proceedings - Working Conference on Reverse Engineering, WCRE&lt;/em&gt;, pp. 214-223, 2004, doi:&lt;a href="https://doi.org/10.1109/WCRE.2004.10"&gt;10.1109/WCRE.2004.10&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zhou2012"&gt;
&lt;p&gt;[24] J. Zhou, H. Zhang, and D. Lo, "Where should the bugs be fixed? More accurate information retrieval-based bug localization based on bug reports," &lt;em&gt;Proceedings - International Conference on Software Engineering&lt;/em&gt;, pp. 14-24, 2012, doi:&lt;a href="https://doi.org/10.1109/ICSE.2012.6227210"&gt;10.1109/ICSE.2012.6227210&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Le2015"&gt;
&lt;p&gt;[25] T.-D. B. Le, R. J. Oentaryo, and D. Lo, "Information retrieval and spectrum based bug localization: better together," in &lt;em&gt;Proceedings of the 2015 10th joint meeting on foundations of software engineering - esec/fse 2015&lt;/em&gt;, 2015, pp. 579-590, doi:&lt;a href="https://doi.org/10.1145/2786805.2786880"&gt;10.1145/2786805.2786880&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Artzi2010"&gt;
&lt;p&gt;[26] S. Artzi, J. Dolby, F. Tip, and M. Pistoia, "Directed Test Generation for Effective Fault Localization," in &lt;em&gt;Proceedings of the 19th international symposium on software testing and analysis&lt;/em&gt;, 2010, pp. 49-60, doi:&lt;a href="https://doi.org/10.1145/1831708.1831715"&gt;10.1145/1831708.1831715&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Sahoo2013"&gt;
&lt;p&gt;[27] S. K. Sahoo, J. Criswell, C. Geigle, and V. Adve, "Using likely invariants for automated software fault localization," in &lt;em&gt;Proceedings of the eighteenth international conference on architectural support for programming languages and operating systems&lt;/em&gt;, 2013, vol. 41, p. 139, doi:&lt;a href="https://doi.org/10.1145/2451116.2451131"&gt;10.1145/2451116.2451131&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Perez2014"&gt;
&lt;p&gt;[28] A. Perez, R. Abreu, and A. Riboira, "A Dynamic Code Coverage Approach to Maximize Fault Localization Efficiency," &lt;em&gt;J. Syst. Softw.&lt;/em&gt;, vol. 90, pp. 18-28, Apr. 2014, doi:&lt;a href="https://doi.org/10.1016/j.jss.2013.12.036"&gt;10.1016/j.jss.2013.12.036&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agrawal1995"&gt;
&lt;p&gt;[29] H. Agrawal, J. Horgan, S. London, and W. Wong, "Fault localization using execution slices and dataflow tests," in &lt;em&gt;Proceedings of sixth international symposium on software reliability engineering. issre'95&lt;/em&gt;, 1995, pp. 143-151, doi:&lt;a href="https://doi.org/10.1109/ISSRE.1995.497652"&gt;10.1109/ISSRE.1995.497652&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Cleve2005"&gt;
&lt;p&gt;[30] H. Cleve and A. Zeller, "Locating causes of program failures," &lt;em&gt;Proceedings of the 27th international conference on Software engineering - ICSE '05&lt;/em&gt;, p. 342, 2005, doi:&lt;a href="https://doi.org/10.1145/1062455.1062522"&gt;10.1145/1062455.1062522&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Horwitz1990"&gt;
&lt;p&gt;[31] S. Horwitz, "Identifying the Semantic and Textual Differences Between Two Versions of a Program," &lt;em&gt;SIGPLAN Not.&lt;/em&gt;, vol. 25, no. 6, pp. 234-245, Jun. 1990, doi:&lt;a href="https://doi.org/10.1145/93548.93574"&gt;10.1145/93548.93574&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Wong2008"&gt;
&lt;p&gt;[32] E. Wong, T. Wei, Y. Qi, and L. Zhao, "A Crosstab-based Statistical Method for Effective Fault Localization," in &lt;em&gt;2008 international conference on software testing, verification, and validation&lt;/em&gt;, 2008, pp. 42-51, doi:&lt;a href="https://doi.org/10.1109/ICST.2008.65"&gt;10.1109/ICST.2008.65&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Landsberg2015"&gt;
&lt;p&gt;[33] D. Landsberg, H. Chockler, D. Kroening, and M. Lewis, "Evaluation of Measures for Statistical Fault Localisation and an Optimising Scheme," in &lt;em&gt;International conference on fundamental approaches to software engineering&lt;/em&gt;, 2015, vol. 9033, pp. 115-129, doi:&lt;a href="https://doi.org/10.1007/978-3-662-46675-9"&gt;10.1007/978-3-662-46675-9&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zheng2018"&gt;
&lt;p&gt;[34] Y. Zheng, Z. Wang, X. Fan, X. Chen, and Z. Yang, "Localizing multiple software faults based on evolution algorithm," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 139, pp. 107-123, 2018, doi:&lt;a href="https://doi.org/10.1016/j.jss.2018.02.001"&gt;10.1016/j.jss.2018.02.001&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-ChaoLiu2006"&gt;
&lt;p&gt;[35] C. Liu, L. Fei, X. Yan, J. Han, and S. P. Midkiff, "Statistical debugging: A hypothesis testing-based approach," &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt;, vol. 32, no. 10, pp. 831-847, Oct. 2006, doi:&lt;a href="https://doi.org/10.1109/TSE.2006.105"&gt;10.1109/TSE.2006.105&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Ferrante1987"&gt;
&lt;p&gt;[36] J. Ferrante, K. J. Ottenstein, and J. D. Warren, "The program dependence graph and its use in optimization," vol. 9. pp. 319-349, Jul-1987.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Ali2009"&gt;
&lt;p&gt;[37] S. Ali, J. H. Andrews, T. Dhandapani, and W. Wang, "Evaluating the Accuracy of Fault Localization Techniques," &lt;em&gt;2009 IEEE/ACM International Conference on Automated Software Engineering&lt;/em&gt;, pp. 76-87, 2009, doi:&lt;a href="https://doi.org/10.1109/ASE.2009.89"&gt;10.1109/ASE.2009.89&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Moon2014"&gt;
&lt;p&gt;[38] S. Moon, Y. Kim, M. Kim, and S. Yoo, "Ask the Mutants: Mutating faulty programs for fault localization," &lt;em&gt;Proceedings - IEEE 7th International Conference on Software Testing, Verification and Validation, ICST 2014&lt;/em&gt;, pp. 153-162, 2014, doi:&lt;a href="https://doi.org/10.1109/ICST.2014.28"&gt;10.1109/ICST.2014.28&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Liu2005"&gt;
&lt;p&gt;[39] C. Liu, H. Yu, P. S. Yu, X. Yan, H. Yu, J. Han, and P. S. Yu, "Mining Behavior Graphs for ‘Backtrace' of Noncrashing Bugs," in &lt;em&gt;Proceedings of the 2005 siam international conference on data mining&lt;/em&gt;, 2005, pp. 286-297, doi:&lt;a href="https://doi.org/10.1137/1.9781611972757.26"&gt;10.1137/1.9781611972757.26&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-DiFatta2006"&gt;
&lt;p&gt;[40] G. Di Fatta, S. Leue, and E. Stegantova, "Discriminative Pattern Mining in Software Fault Detection," in &lt;em&gt;Proceedings of the 3rd international workshop on software quality assurance&lt;/em&gt;, 2006, pp. 62-69, doi:&lt;a href="https://doi.org/10.1145/1188895.1188910"&gt;10.1145/1188895.1188910&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Eichinger2008"&gt;
&lt;p&gt;[41] F. Eichinger, K. Böhm, and M. Huber, "Mining Edge-Weighted Call Graphs to Localise Software Bugs," in &lt;em&gt;European conference machine learning and knowledge discovery in databases&lt;/em&gt;, 2008, pp. 333-348, doi:&lt;a href="https://doi.org/10.1007/978-3-540-87479-9_40"&gt;10.1007/978-3-540-87479-9_40&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Eichinger2010"&gt;
&lt;p&gt;[42] F. Eichinger, K. Krogmann, R. Klug, and K. Böhm, "Software-defect Localisation by Mining Dataflow-enabled Call Graphs," in &lt;em&gt;Proceedings of the 2010 european conference on machine learning and knowledge discovery in databases: Part i&lt;/em&gt;, 2010, pp. 425-441.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Mousavian2011"&gt;
&lt;p&gt;[43] Z. Mousavian, M. Vahidi-Asl, and S. Parsa, "Scalable Graph Analyzing Approach for Software Fault-localization," in &lt;em&gt;Proceedings of the 6th international workshop on automation of software test&lt;/em&gt;, 2011, pp. 15-21, doi:&lt;a href="https://doi.org/10.1145/1982595.1982599"&gt;10.1145/1982595.1982599&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Eichinger2011"&gt;
&lt;p&gt;[44] F. Eichinger, C. Oßner, and K. Böhm, "Scalable software-defect localisation by hierarchical mining of dynamic call graphs," &lt;em&gt;Proceedings of the 11th SIAM International Conference on Data Mining, SDM 2011&lt;/em&gt;, no. c, pp. 723-734, 2011.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Parsa2011"&gt;
&lt;p&gt;[45] S. Parsa, S. A. Naree, and N. E. Koopaei, "Software Fault Localization via Mining Execution Graphs," in &lt;em&gt;Proceedings of the 2011 international conference on computational science and its applications - volume part ii&lt;/em&gt;, 2011, pp. 610-623.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Mariani2011"&gt;
&lt;p&gt;[46] L. Mariani, F. Pastore, and M. Pezze, "Dynamic Analysis for Diagnosing Integration Faults," &lt;em&gt;IEEE Trans. Softw. Eng.&lt;/em&gt;, vol. 37, no. 4, pp. 486-508, Jul. 2011, doi:&lt;a href="https://doi.org/10.1109/TSE.2010.93"&gt;10.1109/TSE.2010.93&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yousefi2013"&gt;
&lt;p&gt;[47] A. Yousefi and A. Wassyng, "A Call Graph Mining and Matching Based Defect Localization Technique," in &lt;em&gt;2013 ieee sixth international conference on software testing, verification and validation workshops&lt;/em&gt;, 2013, pp. 86-95, doi:&lt;a href="https://doi.org/10.1109/ICSTW.2013.17"&gt;10.1109/ICSTW.2013.17&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Ioannidis2005"&gt;
&lt;p&gt;[48] J. P. A. Ioannidis, "Why most published research findings are false," &lt;em&gt;PLoS Medicine&lt;/em&gt;, vol. 2, no. 8, pp. 0696-0701, 2005, doi:&lt;a href="https://doi.org/10.1371/journal.pmed.0020124"&gt;10.1371/journal.pmed.0020124&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Grinstead2012"&gt;
&lt;p&gt;[49] C. M. Grinstead and J. L. Snell, &lt;em&gt;Introduction to Probability&lt;/em&gt;, 2nd ed. Providence, RI: American Mathematical Society, 1997.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Kemeny1960"&gt;
&lt;p&gt;[50] J. G. Kemeny and J. L. Snell, &lt;em&gt;Finite Markov Chains&lt;/em&gt;, First. Princeton, NJ: Van Nostrand, 1960.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Davis2004"&gt;
&lt;p&gt;[51] T. A. Davis, "Algorithm 832: UMFPACK V4.3—an Unsymmetric-pattern Multifrontal Method," &lt;em&gt;ACM Trans. Math. Softw.&lt;/em&gt;, vol. 30, no. 2, pp. 196-199, Jun. 2004, doi:&lt;a href="https://doi.org/10.1145/992200.992206"&gt;10.1145/992200.992206&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Just2014"&gt;
&lt;p&gt;[52] R. Just, D. Jalali, and M. D. Ernst, "Defects4J: A Database of Existing Faults to Enable Controlled Testing Studies for Java Programs," in &lt;em&gt;Proceedings of the 2014 international symposium on software testing and analysis&lt;/em&gt;, 2014, pp. 437-440, doi:&lt;a href="https://doi.org/10.1145/2610384.2628055"&gt;10.1145/2610384.2628055&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Steimann2013"&gt;
&lt;p&gt;[53] F. Steimann, M. Frenkel, and R. Abreu, "Threats to the validity and value of empirical assessments of the accuracy of coverage-based fault locators," &lt;em&gt;Proceedings of the 2013 International Symposium on Software Testing and Analysis - ISSTA 2013&lt;/em&gt;, p. 314, 2013, doi:&lt;a href="https://doi.org/10.1145/2483760.2483767"&gt;10.1145/2483760.2483767&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1"&gt;&lt;p&gt;Jones &lt;em&gt;et al.&lt;/em&gt; did not use the term "suspiciousness score" or "suspiciousness metric" in their 2002 paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;. They introduced the term "suspiciousness score" in their 2005 paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;4&lt;/a&gt;]&lt;/span&gt;, in the context of ranking statements. Both terms are now in common use.&lt;a href="#fnref1"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2"&gt;&lt;p&gt;A dependence sphere is computed from the Program Dependence Graph (PDG) &lt;span class="citation"&gt;[&lt;a href="#ref-Horwitz1990"&gt;31&lt;/a&gt;], [&lt;a href="#ref-Ferrante1987"&gt;36&lt;/a&gt;]&lt;/span&gt;. In a PDG, program elements are nodes and their &lt;em&gt;control&lt;/em&gt; and &lt;em&gt;data&lt;/em&gt; dependencies are represented as edges. Given two nodes &lt;span class="math inline"&gt;\(\alpha\)&lt;/span&gt; and &lt;span class="math inline"&gt;\(\beta\)&lt;/span&gt; a graph with a shortest path (ignoring edge directionality) &lt;span class="math inline"&gt;\(\pi\)&lt;/span&gt; between them, the sphere is all those nodes in the graph have have a path from &lt;span class="math inline"&gt;\(\alpha\)&lt;/span&gt; as short (or shorter) than &lt;span class="math inline"&gt;\(\pi\)&lt;/span&gt; (once again ignoring edge directionality).&lt;a href="#fnref2"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3"&gt;&lt;p&gt;Implementations of these two computations maybe found in &lt;span&gt;&lt;code&gt;https://github.com/timtadh/expected-hitting-times&lt;/code&gt;&lt;/span&gt;.&lt;a href="#fnref3"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn4"&gt;&lt;p&gt;See https://hackthology.com/pdfs/scam-2019-supplement.pdf&lt;a href="#fnref4"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Paper"/></entry><entry><title>Gödel's Incompleteness Theorem Does Have Philosophical Implications</title><link href="https://hackthology.com/godels-incompleteness-theorem-does-have-philosophical-implications.html" rel="alternate"/><published>2018-11-05T00:00:00-05:00</published><updated>2018-11-05T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2018-11-05:/godels-incompleteness-theorem-does-have-philosophical-implications.html</id><summary type="html">&lt;p&gt;In 1931 Kurt Gödel published a paper in German that has continued to
reverberate through the scientific community:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;K. Gödel, "On Formally Undecidable Propositions of Principia Mathematica and
Related Systems," Monatshefte für Math. und Phys., vol. 38, pp. 173–198, Jan.
1931.&lt;/p&gt;
&lt;p&gt;Translation: &lt;a href="https://doi.org/10.1111/j.1468-0149.1963.tb00774.x"&gt;doi&lt;/a&gt;
&lt;a href="http://hope.simons-rock.edu/~pshields/cs/cmpt300/easiergoedel.pdf"&gt;pdf&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This paper sets clear limits …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In 1931 Kurt Gödel published a paper in German that has continued to
reverberate through the scientific community:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;K. Gödel, "On Formally Undecidable Propositions of Principia Mathematica and
Related Systems," Monatshefte für Math. und Phys., vol. 38, pp. 173–198, Jan.
1931.&lt;/p&gt;
&lt;p&gt;Translation: &lt;a href="https://doi.org/10.1111/j.1468-0149.1963.tb00774.x"&gt;doi&lt;/a&gt;
&lt;a href="http://hope.simons-rock.edu/~pshields/cs/cmpt300/easiergoedel.pdf"&gt;pdf&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This paper sets clear limits on what is "rationally computable" and what that
means. There have been those that argue this work has little to no philosophical
significance. I believe it does have philosophical significance as I explain at
the end.&lt;/p&gt;
&lt;h2&gt;First some definitions.&lt;/h2&gt;
&lt;p&gt;By rational I mean reasoning (that is thinking) through the means of logical
inference without outside facts or "intuition." Such a manner of thought would
have been foreign to most in 1931 (except those pursuing &lt;a href="https://en.wikipedia.org/wiki/Principia_Mathematica"&gt;&lt;em&gt;formal&lt;/em&gt;
mathematics&lt;/a&gt;). Today it has
become explicit through our interaction with computers -- who can only reason
rationally.*&lt;/p&gt;
&lt;p&gt;By computable I mean a question (such as does 2 + 2 = 4?) can be provably
answered in a finite number of discrete steps in the logical system of choice.
By logical system of choice I mean the allowed methods of reasoning and the set
of base "facts" (called axioms). For example:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Facts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;0 == 0&lt;/li&gt;
&lt;li&gt;0 + 1 != 0&lt;/li&gt;
&lt;li&gt;x + 1 == y + 1 ---&amp;gt; x == y&lt;/li&gt;
&lt;li&gt;x + (y + 1) == (x + y) + 1&lt;/li&gt;
&lt;li&gt;0 + x == x&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;allowed deductions:&lt;/p&gt;
&lt;p&gt;if A is true and A implies B then B is true&lt;/p&gt;
&lt;p&gt;2 + 2 == 4?&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;2 ==&amp;gt; 0 + 1 + 1 ("de-sugaring the natural number")&lt;/li&gt;
&lt;li&gt;4 ==&amp;gt; 0 + 1 + 1 + 1 + 1 ("de-sugaring the natural number")&lt;/li&gt;
&lt;li&gt;(0 + 1 + 1) + (0 + 1 + 1) == (0 + 1 + 1 + 1 + 1) ("restatement of lemma")&lt;/li&gt;
&lt;li&gt;((0 + 1 + 1) + (0 + 1)) + 1 (rule 4)&lt;/li&gt;
&lt;li&gt;((0 + 1 + 1) + (0)) + 1 + 1 (rule 4)&lt;/li&gt;
&lt;li&gt;(0 + 1 + 1) + 1 + 1 (rule 5)&lt;/li&gt;
&lt;li&gt;(0 + 1) + 1 + 1 + 1 (rule 4)&lt;/li&gt;
&lt;li&gt;0 + 1 + 1 + 1 + 1 (rule 4)&lt;/li&gt;
&lt;li&gt;(0 + 1 + 1 + 1 + 1) == (0 + 1 + 1 + 1 + 1) ("restatement of lemma using previous step")&lt;/li&gt;
&lt;li&gt;(0 + 1 + 1 + 1) == (0 + 1 + 1 + 1) (rule 3)&lt;/li&gt;
&lt;li&gt;(0 + 1 + 1) == (0 + 1 + 1) (rule 3)&lt;/li&gt;
&lt;li&gt;(0 + 1) == (0 + 1) (rule 3)&lt;/li&gt;
&lt;li&gt;0 == 0 (rule 3)&lt;/li&gt;
&lt;li&gt;true (rule 1)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;h2&gt;What did Gödel prove?&lt;/h2&gt;
&lt;p&gt;In laymen's terms, Gödel proved that any logical system with finite "axioms"
(read: starting facts) could not be both "complete" and "consistent." By
complete logicians mean the system can answer any question. By consistent
logicians mean the system never gives two answers (both true and false) to a
single question.**&lt;/p&gt;
&lt;h2&gt;Why does this matter?&lt;/h2&gt;
&lt;p&gt;It matters because, like &lt;a href="https://en.wikipedia.org/wiki/Halting_problem"&gt;the Halting
Theorem&lt;/a&gt;, the Incompleteness
Theorem shows there are computations (answers to logical questions) which cannot
be decided by mechanistic means -- that is they are &lt;em&gt;uncomputable&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Some say that these results are both ordinary and without profound implications.
For instance consider this comment from &lt;a href="https://blogs.scientificamerican.com/cross-check/philosophy-has-made-plenty-of-progress/"&gt;an interview with Tim
Maudlin&lt;/a&gt;:&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Does Gödel's incompleteness theorem have implications beyond mathematics? Is
it a worm in the apple of rationality? &lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;No. Absolutely no one should have ever been surprised that mathematical truth
cannot be equated with theoremhood in some finite axiomatic system. An
infinitude of mathematical truths are uninteresting trivia, with no obvious
route to being proved. Example: let's say that the decimal expressions of the
square root of 17 and pi to the 27th power “match” just in case either they
have the same digit in the tenths place, or the same two digits in the next
two places, or the same three digits in the next three places, etc. If we
treat these decimal expressions as essentially random sequences of digits,
then the a priori chance that these two numbers match is one out of nine.&lt;/p&gt;
&lt;p&gt;Now: how do we tell if they match or not? Well, we can just calculate out the
sequences of digits and check. And if they match we will eventually find the
match and prove that they match. But what if, as is likely, they don't match?
No amount of just grinding out the digits and checking will ever prove it:
there are always more digits to check. And I see zero prospect of any other
way to prove that they don't match. So if they don't match, that is an
unprovable mathematical fact. It is also a very, very, very uninteresting one.
All Gödel did was find a clever way to construct a provably unprovable
mathematical fact, given any consistent and finite set of axioms to work with.
The work is clever but in no way profound. It should have come as no surprise
at all.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, it is (particularly in the historical context) profound to be able to
&lt;em&gt;prove&lt;/em&gt; that a particular question has no &lt;em&gt;computable&lt;/em&gt; answer. The answer may be
out there but if we (humans) discover it will be by luck not will. There are
limits and important ones about what we as humans and machines can and cannot
prove and know. From a philosophical point of view this argues for the concept
of &lt;em&gt;mystery&lt;/em&gt;. That there are and will be those areas of truth for which we can
grasp but never hold, for we reach for but do not touch. Thus, we must strive on
in our collective quest to know who and what we. All the while &lt;em&gt;knowing&lt;/em&gt; there are
parts of the world and ourselves for which there is no final a HA!&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;* - Of course those who work on stochastic algorithms and machine learning may
quibble on this point. However, I believe even those algorithms and systems --
and indeed our brains at a fundamental level -- reason rationally. Indeed this
is &lt;em&gt;why&lt;/em&gt; Gödel's theorem is of such interest.&lt;/p&gt;
&lt;p&gt;** - This and this article necessarily simplifies and collapses much of the
nuance in the work. For instance there are actually 2 incompleteness theorems
that work in concert with each other. I am interested in this article with the
effect of the theorems not in giving a rigorous introduction to them.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>How to Evaluate Statistical Fault Localization</title><link href="https://hackthology.com/how-to-evaluate-statistical-fault-localization.html" rel="alternate"/><published>2018-07-27T00:00:00-04:00</published><updated>2018-07-27T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2018-07-27:/how-to-evaluate-statistical-fault-localization.html</id><summary type="html">&lt;h4&gt;Cite as:&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;. &lt;em&gt;How To Evaluate Statistical Fault Localization&lt;/em&gt;.
Blog. 2018.  &lt;a href="https://hackthology.com/how-to-evaluate-statistical-fault-localization.html"&gt;https://hackthology.com/how-to-evaluate-statistical-fault-localization.html&lt;/a&gt;
&lt;br/&gt;
&lt;a href="https://hackthology.com/pdfs/how-to-eval-fault-localization.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/how-to-evaluate-statistical-fault-localization.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/how-to-eval-fault-localization.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;I now have a pulished …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;h4&gt;Cite as:&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;. &lt;em&gt;How To Evaluate Statistical Fault Localization&lt;/em&gt;.
Blog. 2018.  &lt;a href="https://hackthology.com/how-to-evaluate-statistical-fault-localization.html"&gt;https://hackthology.com/how-to-evaluate-statistical-fault-localization.html&lt;/a&gt;
&lt;br/&gt;
&lt;a href="https://hackthology.com/pdfs/how-to-eval-fault-localization.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/how-to-evaluate-statistical-fault-localization.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct you should read the
&lt;a href="https://hackthology.com/pdfs/how-to-eval-fault-localization.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;I now have a pulished paper on this topic. You probably want to read that as
well.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;, Yiğit Küçük, and Andy Podgurski.
&lt;a href="https://hackthology.com/evaluating-automatic-fault-localization-using-markov-processes.html"&gt;Evaluating Automatic Fault Localization Using Markov Processes&lt;/a&gt;. SCAM 2019.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;
&lt;h1 id="introduction"&gt;Introduction&lt;/h1&gt;
&lt;p&gt;Automatic fault localization is a software engineering technique to assist a programmer during the debugging process by suggesting suspicious locations that may be related to the root cause of the bug. The big idea behind behind automatic fault localization (or just fault localization) is by pointing the programmer towards the right area of the program the programmer will find the cause of the bug more quickly.&lt;/p&gt;
&lt;p&gt;One approach to fault localization is &lt;em&gt;Spectrum Based Fault Localization&lt;/em&gt; which is also known as &lt;em&gt;Coverage Based Statistical Fault Localization&lt;/em&gt; (CBSFL) &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]-[&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;]&lt;/span&gt;. This approach uses test coverage information to rank the statements from most "suspicious" to least suspicious. To perform CBSFL, test cases are run through an instrumented program. The instrumentation collects coverage profiles which report each statement&lt;a href="#fn1" class="footnoteRef" id="fnref1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt; executed during the test run. A &lt;em&gt;test oracle&lt;/em&gt; is used to label each execution profile with whether or not the test passed or failed. Such oracles can be either automatic or manual (i.e. a human). The labeled execution profiles are referred to as the &lt;em&gt;coverage spectra&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;CBSFL techniques score each program element (location in the program) by its "statistical suspiciousness" such that the most suspicious element has the highest score. The scores are computed by &lt;em&gt;suspiciousness metrics&lt;/em&gt; which attempt to quantify the relationship between the execution each program element and the occurrence of program failure.&lt;/p&gt;
&lt;p&gt;There have been a great many statistical fault localization suspiciousness metrics proposed &lt;span class="citation"&gt;[&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;]&lt;/span&gt; since the idea was first proposed by Jones, Harrold and Stasko in 2002 &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;. The majority of the metrics are computed from just a few values: the number of tests &lt;span class="math inline"&gt;\(n\)&lt;/span&gt;, the number of passing tests &lt;span class="math inline"&gt;\(p\)&lt;/span&gt;, the number failing tests &lt;span class="math inline"&gt;\(f\)&lt;/span&gt;, the number of test runs an element &lt;span class="math inline"&gt;\(e\)&lt;/span&gt; was executed in &lt;span class="math inline"&gt;\(n_e\)&lt;/span&gt;, the number of passing test runs an element was executed in &lt;span class="math inline"&gt;\(p_e\)&lt;/span&gt;, and the number of failing test runs an element was executed in &lt;span class="math inline"&gt;\(f_e\)&lt;/span&gt;. For instance, using these simple statistics one can estimate the conditional probability of program failure &lt;span class="math inline"&gt;\(F\)&lt;/span&gt; given that a particular element &lt;span class="math inline"&gt;\(e\)&lt;/span&gt; was executed: &lt;span class="math display"&gt;\[\begin{aligned}

  {\textrm{Pr}\left[{F|e}\right]} &amp;amp;= \frac{{\textrm{Pr}\left[{F \cap e}\right]}}{{\textrm{Pr}\left[{e}\right]}}
                        \approx \frac{\frac{f_{e}}{n}}{\frac{n_{e}}{n}}
                        = \frac{f_e}{n_e}\end{aligned}\]&lt;/span&gt; While many of the studies in statistical fault localization use more complex formulas &lt;span class="citation"&gt;[&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;], [&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;]&lt;/span&gt; (with various technical motivations) most of the metrics are measures statistical association as in the equation above.&lt;/p&gt;
&lt;p&gt;The runtime information used to compute the above statistics is commonly referred to as the &lt;em&gt;coverage spectra&lt;/em&gt; of the program. Coverage spectra is a matrix &lt;span class="math inline"&gt;\({\bf C}\)&lt;/span&gt; where &lt;span class="math inline"&gt;\({\bf C}_{i,j} &amp;gt; 0\)&lt;/span&gt; indicates that the program element &lt;span class="math inline"&gt;\(\mathcal{E}_i\)&lt;/span&gt; was executed at least once during test &lt;span class="math inline"&gt;\(\mathcal{T}_j\)&lt;/span&gt;. Additionally, there is an additional "test status" vector &lt;span class="math inline"&gt;\({\bf S}\)&lt;/span&gt; where &lt;span class="math inline"&gt;\({\bf S}_{j} = \text{"F&amp;#39;&amp;#39;}\)&lt;/span&gt; if test &lt;span class="math inline"&gt;\(\mathcal{T}_j\)&lt;/span&gt; failed and &lt;span class="math inline"&gt;\({\bf S}_{j} =
\text{"P&amp;#39;&amp;#39;}\)&lt;/span&gt; if test &lt;span class="math inline"&gt;\(j\)&lt;/span&gt; passed.&lt;/p&gt;
&lt;p&gt;To collect the coverage spectra the program is instrumented to collect a runtime profile of the executed elements. This instrumentation can be done (in principle) at any granularity including: expression, statement, basic block&lt;a href="#fn2" class="footnoteRef" id="fnref2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt;, function, class, file, or package. The statistical methods which make use of spectra are agnostic to their granularity. While the granularity does not effect the statistical computation it changes how the localization results are perceived by the programmer. In the past, programmers have indicated a desire for finer grained results: at statement, basic block, or function level &lt;span class="citation"&gt;[&lt;a href="#ref-Kochhar2016"&gt;5&lt;/a&gt;]&lt;/span&gt; over very coarse grained results at the class, file, or package level.&lt;/p&gt;
&lt;p&gt;Some statistical fault localization techniques use additional information to either improve accuracy or provide more explainable results. For instance, work on &lt;em&gt;Causal Fault Localization&lt;/em&gt; uses additional static and dynamic information to control for statistical confounding &lt;span class="citation"&gt;[&lt;a href="#ref-Baah2010"&gt;6&lt;/a&gt;]&lt;/span&gt;. In contrast &lt;em&gt;Suspicious Behavior Based Fault Localization&lt;/em&gt; (SBBFL) uses runtime control flow information (the behavior) to identify groups of collaborating suspicious elements &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;]&lt;/span&gt;. These techniques leverage data mining techniques &lt;span class="citation"&gt;[&lt;a href="#ref-Aggarwal2014"&gt;8&lt;/a&gt;]&lt;/span&gt; such as frequent &lt;span class="citation"&gt;[&lt;a href="#ref-Agrawal1993"&gt;9&lt;/a&gt;]-[&lt;a href="#ref-Aggarwal2014a"&gt;11&lt;/a&gt;]&lt;/span&gt; or significant pattern mining &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;], [&lt;a href="#ref-Yan2008"&gt;12&lt;/a&gt;]&lt;/span&gt;. When significant patterns are mined metrics (such as statistical fault localization suspiciousness metrics) are used to identify the most significant patterns &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;], [&lt;a href="#ref-Cheng2009a"&gt;13&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Finally, a variety of non-statistical (or mixed methods) techniques for fault localization have been explored &lt;span class="citation"&gt;[&lt;a href="#ref-Abreu2006"&gt;14&lt;/a&gt;]-[&lt;a href="#ref-Wong2016"&gt;17&lt;/a&gt;]&lt;/span&gt;. These range from delta debugging &lt;span class="citation"&gt;[&lt;a href="#ref-Zeller1999"&gt;18&lt;/a&gt;]&lt;/span&gt; to nearest neighbor queries &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;19&lt;/a&gt;]&lt;/span&gt; to program slicing &lt;span class="citation"&gt;[&lt;a href="#ref-Tip1995"&gt;20&lt;/a&gt;], [&lt;a href="#ref-Mao2014"&gt;21&lt;/a&gt;]&lt;/span&gt; to information retrieval &lt;span class="citation"&gt;[&lt;a href="#ref-Marcus2004"&gt;22&lt;/a&gt;]-[&lt;a href="#ref-Le2015"&gt;24&lt;/a&gt;]&lt;/span&gt; to test case generation &lt;span class="citation"&gt;[&lt;a href="#ref-Artzi2010"&gt;25&lt;/a&gt;]-[&lt;a href="#ref-Perez2014"&gt;27&lt;/a&gt;]&lt;/span&gt;. Despite differences in the technical and theoretical approach of these alternate methods they also suggest locations (or groups of locations) for the programmer to consider when debugging.&lt;/p&gt;
&lt;h1 id="evaluation-methods"&gt;Evaluation Methods&lt;/h1&gt;
&lt;p&gt;Some of the earliest papers in fault localization do not provide a quantitative method for evaluating performance (as is seen in later papers &lt;span class="citation"&gt;[&lt;a href="#ref-Pearson2017"&gt;28&lt;/a&gt;]&lt;/span&gt;). For instance, in the earliest CBSFL paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt; (by Jones &lt;em&gt;et al.&lt;/em&gt;'s) the technique is evaluated using a qualitative visualization. At the time, this was entirely appropriate as Jones was proposing a technique for visualizing test coverage for assisting the debugging process. The test coverage visualization was driven by what is now called a statistical fault localization metric (Tarantula). The evaluation visualization aggregated the visualizations all of the programs included in the study.&lt;/p&gt;
&lt;p&gt;While, the evaluation method used in the Jones paper effectively communicated the potential of CBSFL (and got many researchers excited about the idea) it was not good way to compare multiple fault localization techniques. In 2005 Jones and Harrold &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;29&lt;/a&gt;]&lt;/span&gt; conducted a study which compared their Tarantula technique to 3 other techniques: Set Union and Intersection &lt;span class="citation"&gt;[&lt;a href="#ref-Agrawal1995"&gt;30&lt;/a&gt;]&lt;/span&gt;, Nearest Neighbor &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;19&lt;/a&gt;]&lt;/span&gt;, and Cause-Transitions &lt;span class="citation"&gt;[&lt;a href="#ref-Cleve2005"&gt;31&lt;/a&gt;]&lt;/span&gt;. These techniques all took unique approaches toward the fault localization problem and were originally evaluated in different ways. Jones and Harrold re-evaluated all 5 methods under a new common evaluation framework.&lt;/p&gt;
&lt;p&gt;In the 2005 paper, Jones and Harrold evaluate the effectiveness of each technique by using the technique to rank the statements in the subject programs. Each technique ranked the statements from most likely to be the cause of the fault to least likely. For Tarantula, the statements are ranked using the Tarantula suspiciousness score:&lt;a href="#fn3" class="footnoteRef" id="fnref3"&gt;&lt;sup&gt;3&lt;/sup&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4 id="definition.-tarantula-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Tarantula Rank Score &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;29&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l
  \in L\)&lt;/span&gt; the Rank Score for a location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; is: &lt;span class="math display"&gt;\[\begin{aligned}
    {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) &amp;gt; s(l) \right\} }\right|}} +
    {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \right\} }\right|}}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;For Set Union and Intersection, Nearest Neighbor and Cause-Transitions the statements are ranked using a System Dependence Graph (SDG) &lt;span class="citation"&gt;[&lt;a href="#ref-Horwitz1990"&gt;32&lt;/a&gt;]&lt;/span&gt; technique from Renieres and Reiss &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;19&lt;/a&gt;]&lt;/span&gt; who first suggested the ranking idea. The ranks are then used to calculate the Tarantula Rank Score.&lt;/p&gt;
&lt;p&gt;In the Jones and Harrold evaluation the authors do not use the Tarantula Rank Score directly but instead use a version normalized by program size:&lt;/p&gt;
&lt;h4 id="definition.-tarantula-effectiveness-score-expense"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Tarantula Effectiveness Score (Expense) &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;29&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;The percentage of program elements that do not need to be examined to find the fault when the elements are arranged according to their rank. Formally: let &lt;span class="math inline"&gt;\(n\)&lt;/span&gt; be the total number of program elements, and let &lt;span class="math inline"&gt;\(r(f)\)&lt;/span&gt; be the Tarantula Rank Score of the faulty element &lt;span class="math inline"&gt;\(f\)&lt;/span&gt; then the score is: &lt;span class="math display"&gt;\[\begin{aligned}
    \frac{n-r(f)}{n}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Using the normalized effectiveness score Jones and Harrold directly compare the fault localization effectiveness of each of the considered methods. They did this in two ways. First, they presented a table (Table 2) which bucketed all the buggy versions form all the programs by the percentage given by the Tarantula Effectiveness Score. Second, they presented a figure (Figure 2) which showed the data in Table 2 as a cumulative curve.&lt;/p&gt;
&lt;p&gt;The basic evaluation method presented by Jones and Harrold has become the standard evaluation method. Faulty statements are scored, ranked, rank-scored, normalized, and then aggregated over all versions and programs to provide an overall representation of the fault localization method's performance (a few examples: &lt;span class="citation"&gt;[&lt;a href="#ref-Lucia2014"&gt;2&lt;/a&gt;], [&lt;a href="#ref-Sun2016"&gt;3&lt;/a&gt;], [&lt;a href="#ref-Steimann2013"&gt;33&lt;/a&gt;]-[&lt;a href="#ref-Zheng2018"&gt;36&lt;/a&gt;]&lt;/span&gt;). While the basic method has stayed fairly consistent, there has been some innovation in the scoring (both the Rank Score and the Effectiveness Scores).&lt;/p&gt;
&lt;p&gt;For instance, Wong &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2008"&gt;34&lt;/a&gt;]&lt;/span&gt; introduced the most commonly used Effectiveness Score the &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; score. This score is essentially the same as the Expense score except it gives the percentage of elements which need to be examined rather than those avoided.&lt;/p&gt;
&lt;h4 id="definition.-mathcalexam-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; Score &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2008"&gt;34&lt;/a&gt;]&lt;/span&gt;&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;The percentage of program elements that need to be examined to find the fault when the elements are arranged according to their rank. Formally: let &lt;span class="math inline"&gt;\(n\)&lt;/span&gt; be the total number of program elements, and let &lt;span class="math inline"&gt;\(r(f)\)&lt;/span&gt; be the Tarantula Rank Score of the faulty element &lt;span class="math inline"&gt;\(f\)&lt;/span&gt; then the score is: &lt;span class="math display"&gt;\[\begin{aligned}
    \frac{r(f)}{n}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Ali &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Ali2009"&gt;37&lt;/a&gt;]&lt;/span&gt; identified an important problem with the Jones and Harrold evaluation: some fault localization metrics and algorithms rank statements equally. This is captured in the second term in the definition for the Tarantula Rank Score. However, Ali points out that this introduces bias towards algorithms that always assign unique scores (that are close together) rather than those that would score the same group of statement equally. The fix is to instead compute the expected number of statements the programmer would examine if they chose the next equally scored element at random.&lt;/p&gt;
&lt;h4 id="definition.-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Rank Score&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Gives the expected number of locations a programmer would inspect before finding the bug. Formally, given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; the Rank Score for a location &lt;span class="math inline"&gt;\(l
  \in L\)&lt;/span&gt; is &lt;span class="citation"&gt;[&lt;a href="#ref-Ali2009"&gt;37&lt;/a&gt;]&lt;/span&gt;: &lt;span class="math display"&gt;\[\begin{aligned}
    {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) &amp;gt; s(l) \right\} }\right|}} +
    \frac{
      {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \right\} }\right|}}
    }{
      2
    }
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Following Ali, we recommend utilizing the above definition for Rank Score over the Tarantula definition.&lt;/p&gt;
&lt;p&gt;Parin and Orso &lt;span class="citation"&gt;[&lt;a href="#ref-Parnin2011"&gt;38&lt;/a&gt;]&lt;/span&gt; conducted a user study which looked at the programmer experience of using a statistical fault localization tool (Tarantula &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;). Among their findings they found that programmers would not look deeply through the list of locations and would instead only consider the first few items. As a result they encouraged studies to no longer report scores as percentages. While some studies still report the percentages most studies are now reporting the absolute (non-percentage) rank scores. Reporting as absolute scores is important for another reason, if percentage ranks are reported larger programs can have much larger absolute ranks for the same percentage rank. This biases the evaluation toward large programs even when the actual localization result is poor.&lt;/p&gt;
&lt;p&gt;Steimann &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Steimann2013"&gt;33&lt;/a&gt;]&lt;/span&gt; identified a number of threats to validity in CBSFL studies including: heterogeneous subject programs, poor test suites, small sample sizes, unclear sample spaces, flaky tests, total number of faults, and masked faults. For evaluation they used the Rank Score modified to deal with &lt;span class="math inline"&gt;\(k\)&lt;/span&gt; faults tied at the same rank.&lt;/p&gt;
&lt;h4 id="definition.-steimann-rank-score"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. Steimann Rank Score&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Gives the expected number of locations a programmer would inspect before finding the bug when multiple faulty statements have the same rank. Formally, given a set of locations &lt;span class="math inline"&gt;\(L\)&lt;/span&gt; with their suspiciousness scores &lt;span class="math inline"&gt;\(s(l)\)&lt;/span&gt; for &lt;span class="math inline"&gt;\(l
  \in L\)&lt;/span&gt; the Rank Score for a location &lt;span class="math inline"&gt;\(l \in L\)&lt;/span&gt; is &lt;span class="citation"&gt;[&lt;a href="#ref-Steimann2013"&gt;33&lt;/a&gt;]&lt;/span&gt;: &lt;span class="math display"&gt;\[\begin{aligned}
    &amp;amp; {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) &amp;gt; s(l) \right\} }\right|}}\\
    &amp;amp; + \frac{
          {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \right\} }\right|}} + 1
        }{
          {{\left|{ \left\{ x ~:~ x \in L \wedge s(x) = s(l) \wedge x \text{ is a
          faulty location} \right\}}\right|}} + 1
        }
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Moon &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Moon2014"&gt;39&lt;/a&gt;]&lt;/span&gt; proposed Locality Information Loss (LIL) as an alternative evaluation framework. LIL models the localization result as a probability distribution constructed from the suspiciousness scores:&lt;/p&gt;
&lt;h4 id="definition.-lil-probability-distribution"&gt;&lt;strong&gt;Definition&lt;/strong&gt;. LIL Probability Distribution&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math inline"&gt;\(\tau\)&lt;/span&gt; be a suspicious metric normalized to the &lt;span class="math inline"&gt;\([0,1]\)&lt;/span&gt; range of reals. Let &lt;span class="math inline"&gt;\(n\)&lt;/span&gt; be the number statements in the program. Let &lt;span class="math inline"&gt;\(S\)&lt;/span&gt; be the set of statements. For all &lt;span class="math inline"&gt;\(1 \le i \le n\)&lt;/span&gt; let &lt;span class="math inline"&gt;\(s_i \in S\)&lt;/span&gt;. The constructed probability distribution is: &lt;span class="math display"&gt;\[\begin{aligned}
    P_{\tau}(s_i) = \frac{\tau(s_i)}{\sum^{n}_{j=1} \tau(s_j)}
  \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;LIL uses a measure of distribution divergence (Kullback-Leibler) to compute a score of how different the constructed distribution is from the "perfect" expected distribution. The advantage of the LIL framework is it does not depend on a list of ranked statements and can be applied to non-statistical methods (using a synthetic &lt;span class="math inline"&gt;\(\tau\)&lt;/span&gt;). The disadvantage of LIL is it does not indicate programmer effort (as indicated by the Rank Score). However, it may be a better metric to use when evaluating fault localization systems as a component for automated bug repair systems.&lt;/p&gt;
&lt;p&gt;Pearson &lt;em&gt;et al.&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Pearson2017"&gt;28&lt;/a&gt;]&lt;/span&gt; re-evaluated a number of previous results using new real world subject programs with real defects and test suites. In contrast to previous work they made use of statistical hypothesis testing and confidence intervals to test the significance of the results. To evaluate the performance of each technique under study they used the &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; score reporting best, average, and worst case results for multi-statement faults.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;T-Score&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Liu2006"&gt;40&lt;/a&gt;]&lt;/span&gt; is designed for non-statistical fault localization methods which produce a small set of suspicious statements in the program. To evaluate how helpful these reports are &lt;em&gt;T-Score&lt;/em&gt; uses the Program Dependence Graph (PDG) &lt;span class="citation"&gt;[&lt;a href="#ref-Horwitz1990"&gt;32&lt;/a&gt;], [&lt;a href="#ref-Ferrante1987"&gt;41&lt;/a&gt;]&lt;/span&gt; to compute a set of vertices in the graph that must be examined in order to reach any faulty vertex. This set is computed via a breadth first search from the set of vertices in the report. Finally, the score is computed as the percentage of examined vertices out of the total number of vertices in the graph.&lt;/p&gt;
&lt;h1 id="multiple-fault-evaluations"&gt;Multiple Fault Evaluations&lt;/h1&gt;
&lt;p&gt;With the exception of LIL, the evaluation methods discussed so far are generally defined to operate with a single faulty location. However, there may be multiple faults or multiple locations associated with a single fault or both. Multiple faults can interact &lt;span class="citation"&gt;[&lt;a href="#ref-DiGiuseppe2011"&gt;42&lt;/a&gt;]&lt;/span&gt; and interfere with the performance of the fault localizer. For evaluation purposes one of the most popular methods is to take either best result &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2007"&gt;43&lt;/a&gt;]&lt;/span&gt;, the average result &lt;span class="citation"&gt;[&lt;a href="#ref-Abreu2006"&gt;14&lt;/a&gt;], [&lt;a href="#ref-Naish2011"&gt;44&lt;/a&gt;]&lt;/span&gt;, or the worst result &lt;span class="citation"&gt;[&lt;a href="#ref-Wong2007"&gt;43&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;h1 id="evaluating-other-techniques"&gt;Evaluating Other Techniques&lt;/h1&gt;
&lt;p&gt;One of the challenges with the methods presented so far is they may not work well for evaluating alternate fault localization methods. For instance, information retrieval based localization methods do not necessarily score and rank every program location. Instead they produce a report of associated regions. Jones and Harrold &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;29&lt;/a&gt;]&lt;/span&gt; used a synthetic ranking system &lt;span class="citation"&gt;[&lt;a href="#ref-Renieres2003"&gt;19&lt;/a&gt;]&lt;/span&gt; based on the SDG &lt;span class="citation"&gt;[&lt;a href="#ref-Horwitz1990"&gt;32&lt;/a&gt;]&lt;/span&gt; which in principle could be used in such situation. However, like the &lt;em&gt;T-Score&lt;/em&gt; it uses an arbitrary method (minimal dependence spheres) to compute the number of SDG nodes which must be examined.&lt;/p&gt;
&lt;p&gt;The LIL method could also potentially be used to evaluate alternative methods. It does not rely on ranking but instead on the suspiciousness scores which it converts into a probability distribution. To support evaluating report based localization the reports are converted to a probability distribution with all locations in the report set to a equal high probability and all locations not in the report set to a tiny probability.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Suspicious Behavior Based Fault Localization&lt;/em&gt; &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;]&lt;/span&gt; requires particular care. These methods are produce a ranked set of "behaviors" which are structured groups of interacting program locations. The structure could be a call invocation structure &lt;span class="citation"&gt;[&lt;a href="#ref-Liu2005"&gt;45&lt;/a&gt;]-[&lt;a href="#ref-Diamantopoulos2014"&gt;49&lt;/a&gt;]&lt;/span&gt;, a general control flow structure &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;], [&lt;a href="#ref-Cheng2009a"&gt;13&lt;/a&gt;], [&lt;a href="#ref-Mousavian2011"&gt;50&lt;/a&gt;]&lt;/span&gt;, or even an information flow structure &lt;span class="citation"&gt;[&lt;a href="#ref-Eichinger2010"&gt;51&lt;/a&gt;]&lt;/span&gt;. The structures are scored and ranked similar to CBSFL. However, unlike in CBSFL all program locations are not necessarily included. In the past, studies have used a variety of techniques to evaluated the effectiveness including precision and recall &lt;span class="citation"&gt;[&lt;a href="#ref-Cheng2009a"&gt;13&lt;/a&gt;]&lt;/span&gt; and scores based off of the &lt;span class="math inline"&gt;\(\mathcal{EXAM}\)&lt;/span&gt; score &lt;span class="citation"&gt;[&lt;a href="#ref-Henderson2018"&gt;7&lt;/a&gt;]&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Another subtle special case involves comparing statistical techniques which operate on different granularity levels. As mentioned previously, coverage can be collected at any granularity level: expression, statement, basic block, method or function, class, file, and even non-structural elements such as paths. Any of the CBSFL metrics can be used with any of these granularities. However, a single study using any of the previous evaluation methods must keep the granularity consistent. This makes it impossible to compare across granularity levels. This is makes it particularly difficult to accurately compare method level behavioral approaches &lt;span class="citation"&gt;[&lt;a href="#ref-Liu2005"&gt;45&lt;/a&gt;]&lt;/span&gt; to CBSFL.&lt;/p&gt;
&lt;h1 id="assumptions"&gt;Assumptions&lt;/h1&gt;
&lt;p&gt;The biggest assumption that all evaluation models make is so-called &lt;em&gt;perfect bug understanding&lt;/em&gt; which assumes programmers will recognize a bug as soon as they "examine" the faulty location. This assumption is obviously false &lt;span class="citation"&gt;[&lt;a href="#ref-Parnin2011"&gt;38&lt;/a&gt;]&lt;/span&gt;. However, it continues to be a useful simplifying assumption for evaluation purposes of the localization algorithms. From the standpoint of automated fault localization there are really two tasks: 1) finding the fault and 2) explaining the fault. Assuming perfect bug understanding is reasonable for evaluating a tools performance on task 1. However, there is the important caveat that programmers need more assistance at task 2. As a research community we do not currently have a standard method for evaluating our algorithmic performance on task 2.&lt;/p&gt;
&lt;p&gt;The second assumption is that programmers will follow the rank list or suspiciousness scores when debugging a program using a fault localization tool. This assumption is obviously false as well &lt;span class="citation"&gt;[&lt;a href="#ref-Parnin2011"&gt;38&lt;/a&gt;]&lt;/span&gt;. A programmer may follow the list for the very first item and even the second but where they go from there is likely only partially influenced by the list. The bigger influence will be from the conclusions they are drawing from what they learn upon inspecting each location.&lt;/p&gt;
&lt;div id="refs" class="references"&gt;
&lt;h1&gt;References&lt;/h1&gt;
&lt;div id="ref-Jones2002"&gt;
&lt;p&gt;[1] J. Jones, M. Harrold, and J. Stasko, "Visualization of test information to assist fault localization," &lt;em&gt;Proceedings of the 24th International Conference on Software Engineering. ICSE 2002&lt;/em&gt;, 2002, doi:&lt;a href="https://doi.org/10.1145/581339.581397"&gt;10.1145/581339.581397&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Lucia2014"&gt;
&lt;p&gt;[2] Lucia, D. Lo, L. Jiang, F. Thung, and A. Budi, "Extended comprehensive study of association measures for fault localization," &lt;em&gt;Journal of Software: Evolution and Process&lt;/em&gt;, vol. 26, no. 2, pp. 172-219, Feb. 2014, doi:&lt;a href="https://doi.org/10.1002/smr.1616"&gt;10.1002/smr.1616&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Sun2016"&gt;
&lt;p&gt;[3] S.-F. Sun and A. Podgurski, "Properties of Effective Metrics for Coverage-Based Statistical Fault Localization," in &lt;em&gt;2016 ieee international conference on software testing, verification and validation (icst)&lt;/em&gt;, 2016, pp. 124-134, doi:&lt;a href="https://doi.org/10.1109/ICST.2016.31"&gt;10.1109/ICST.2016.31&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Aho2007"&gt;
&lt;p&gt;[4] A. Aho, R. Sethi, M. S. Lam, and J. D. Ullman, &lt;em&gt;Compilers: principles, techniques, and tools&lt;/em&gt;. 2007.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Kochhar2016"&gt;
&lt;p&gt;[5] P. S. Kochhar, X. Xia, D. Lo, and S. Li, "Practitioners' expectations on automated fault localization," in &lt;em&gt;Proceedings of the 25th international symposium on software testing and analysis - issta 2016&lt;/em&gt;, 2016, pp. 165-176, doi:&lt;a href="https://doi.org/10.1145/2931037.2931051"&gt;10.1145/2931037.2931051&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Baah2010"&gt;
&lt;p&gt;[6] G. G. K. Baah, A. Podgurski, and M. J. M. Harrold, "Causal inference for statistical fault localization," in &lt;em&gt;Proceedings of the 19th international symposium on software testing and analysis&lt;/em&gt;, 2010, pp. 73-84, doi:&lt;a href="https://doi.org/10.1145/1831708.1831717"&gt;10.1145/1831708.1831717&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Henderson2018"&gt;
&lt;p&gt;[7] T. A. D. Henderson and A. Podgurski, "Behavioral Fault Localization by Sampling Suspicious Dynamic Control Flow Subgraphs," in &lt;em&gt;IEEE conference on software testing, validation and verification&lt;/em&gt;, 2018.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Aggarwal2014"&gt;
&lt;p&gt;[8] C. C. Aggarwal and J. Han, Eds., &lt;em&gt;Frequent Pattern Mining&lt;/em&gt;. Cham: Springer International Publishing, 2014.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agrawal1993"&gt;
&lt;p&gt;[9] R. Agrawal, T. Imieliński, and A. Swami, "Mining association rules between sets of items in large databases," &lt;em&gt;ACM SIGMOD Record&lt;/em&gt;, vol. 22, no. 2, pp. 207-216, Jun. 1993, doi:&lt;a href="https://doi.org/10.1145/170036.170072"&gt;10.1145/170036.170072&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yan2002"&gt;
&lt;p&gt;[10] X. Yan and J. Han, "gSpan: graph-based substructure pattern mining," in &lt;em&gt;2002 ieee international conference on data mining, 2002. proceedings.&lt;/em&gt;, 2002, pp. 721-724, doi:&lt;a href="https://doi.org/10.1109/ICDM.2002.1184038"&gt;10.1109/ICDM.2002.1184038&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Aggarwal2014a"&gt;
&lt;p&gt;[11] C. C. Aggarwal, M. A. Bhuiyan, and M. A. Hasan, "Frequent Pattern Mining Algorithms: A Survey," in &lt;em&gt;Frequent pattern mining&lt;/em&gt;, Cham: Springer International Publishing, 2014, pp. 19-64.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yan2008"&gt;
&lt;p&gt;[12] X. Yan, H. Cheng, J. Han, and P. S. Yu, "Mining Significant Graph Patterns by Leap Search," in &lt;em&gt;Proceedings of the 2008 acm sigmod international conference on management of data&lt;/em&gt;, 2008, pp. 433-444, doi:&lt;a href="https://doi.org/10.1145/1376616.1376662"&gt;10.1145/1376616.1376662&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Cheng2009a"&gt;
&lt;p&gt;[13] H. Cheng, D. Lo, Y. Zhou, X. Wang, and X. Yan, "Identifying Bug Signatures Using Discriminative Graph Mining," in &lt;em&gt;Proceedings of the eighteenth international symposium on software testing and analysis&lt;/em&gt;, 2009, pp. 141-152, doi:&lt;a href="https://doi.org/10.1145/1572272.1572290"&gt;10.1145/1572272.1572290&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Abreu2006"&gt;
&lt;p&gt;[14] R. Abreu, P. Zoeteweij, and A. Van Gemund, "An Evaluation of Similarity Coefficients for Software Fault Localization," in &lt;em&gt;2006 12th pacific rim international symposium on dependable computing (prdc'06)&lt;/em&gt;, 2006, pp. 39-46, doi:&lt;a href="https://doi.org/10.1109/PRDC.2006.18"&gt;10.1109/PRDC.2006.18&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Abreu2009"&gt;
&lt;p&gt;[15] R. Abreu, P. Zoeteweij, R. Golsteijn, and A. J. C. van Gemund, "A practical evaluation of spectrum-based fault localization," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 82, no. 11, pp. 1780-1792, 2009, doi:&lt;a href="https://doi.org/10.1016/j.jss.2009.06.035"&gt;10.1016/j.jss.2009.06.035&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agarwal2014"&gt;
&lt;p&gt;[16] P. Agarwal and A. P. Agrawal, "Fault-localization Techniques for Software Systems: A Literature Review," &lt;em&gt;SIGSOFT Softw. Eng. Notes&lt;/em&gt;, vol. 39, no. 5, pp. 1-8, Sep. 2014, doi:&lt;a href="https://doi.org/10.1145/2659118.2659125"&gt;10.1145/2659118.2659125&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Wong2016"&gt;
&lt;p&gt;[17] W. E. Wong, R. Gao, Y. Li, R. Abreu, and F. Wotawa, "A Survey on Software Fault Localization," &lt;em&gt;IEEE Transactions on Software Engineering&lt;/em&gt;, vol. 42, no. 8, pp. 707-740, Aug. 2016, doi:&lt;a href="https://doi.org/10.1109/TSE.2016.2521368"&gt;10.1109/TSE.2016.2521368&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zeller1999"&gt;
&lt;p&gt;[18] A. Zeller, "Yesterday, My Program Worked. Today, It Does Not. Why?" &lt;em&gt;SIGSOFT Softw. Eng. Notes&lt;/em&gt;, vol. 24, no. 6, pp. 253-267, Oct. 1999, doi:&lt;a href="https://doi.org/10.1145/318774.318946"&gt;10.1145/318774.318946&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Renieres2003"&gt;
&lt;p&gt;[19] M. Renieres and S. Reiss, "Fault localization with nearest neighbor queries," in &lt;em&gt;18th ieee international conference on automated software engineering, 2003. proceedings.&lt;/em&gt;, 2003, pp. 30-39, doi:&lt;a href="https://doi.org/10.1109/ASE.2003.1240292"&gt;10.1109/ASE.2003.1240292&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Tip1995"&gt;
&lt;p&gt;[20] F. Tip, "A survey of program slicing techniques," &lt;em&gt;Journal of programming languages&lt;/em&gt;, vol. 3, no. 3, pp. 121-189, 1995.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Mao2014"&gt;
&lt;p&gt;[21] X. Mao, Y. Lei, Z. Dai, Y. Qi, and C. Wang, "Slice-based statistical fault localization," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 89, no. 1, pp. 51-62, 2014, doi:&lt;a href="https://doi.org/10.1016/j.jss.2013.08.031"&gt;10.1016/j.jss.2013.08.031&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Marcus2004"&gt;
&lt;p&gt;[22] A. Marcus, A. Sergeyev, V. Rajlieh, and J. I. Maletic, "An information retrieval approach to concept location in source code," &lt;em&gt;Proceedings - Working Conference on Reverse Engineering, WCRE&lt;/em&gt;, pp. 214-223, 2004, doi:&lt;a href="https://doi.org/10.1109/WCRE.2004.10"&gt;10.1109/WCRE.2004.10&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zhou2012"&gt;
&lt;p&gt;[23] J. Zhou, H. Zhang, and D. Lo, "Where should the bugs be fixed? More accurate information retrieval-based bug localization based on bug reports," &lt;em&gt;Proceedings - International Conference on Software Engineering&lt;/em&gt;, pp. 14-24, 2012, doi:&lt;a href="https://doi.org/10.1109/ICSE.2012.6227210"&gt;10.1109/ICSE.2012.6227210&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Le2015"&gt;
&lt;p&gt;[24] T.-D. B. Le, R. J. Oentaryo, and D. Lo, "Information retrieval and spectrum based bug localization: better together," in &lt;em&gt;Proceedings of the 2015 10th joint meeting on foundations of software engineering - esec/fse 2015&lt;/em&gt;, 2015, pp. 579-590, doi:&lt;a href="https://doi.org/10.1145/2786805.2786880"&gt;10.1145/2786805.2786880&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Artzi2010"&gt;
&lt;p&gt;[25] S. Artzi, J. Dolby, F. Tip, and M. Pistoia, "Directed Test Generation for Effective Fault Localization," in &lt;em&gt;Proceedings of the 19th international symposium on software testing and analysis&lt;/em&gt;, 2010, pp. 49-60, doi:&lt;a href="https://doi.org/10.1145/1831708.1831715"&gt;10.1145/1831708.1831715&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Sahoo2013"&gt;
&lt;p&gt;[26] S. K. Sahoo, J. Criswell, C. Geigle, and V. Adve, "Using likely invariants for automated software fault localization," in &lt;em&gt;Proceedings of the eighteenth international conference on architectural support for programming languages and operating systems&lt;/em&gt;, 2013, vol. 41, p. 139, doi:&lt;a href="https://doi.org/10.1145/2451116.2451131"&gt;10.1145/2451116.2451131&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Perez2014"&gt;
&lt;p&gt;[27] A. Perez, R. Abreu, and A. Riboira, "A Dynamic Code Coverage Approach to Maximize Fault Localization Efficiency," &lt;em&gt;J. Syst. Softw.&lt;/em&gt;, vol. 90, pp. 18-28, Apr. 2014, doi:&lt;a href="https://doi.org/10.1016/j.jss.2013.12.036"&gt;10.1016/j.jss.2013.12.036&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Pearson2017"&gt;
&lt;p&gt;[28] S. Pearson, J. Campos, R. Just, G. Fraser, R. Abreu, M. D. Ernst, D. Pang, and B. Keller, "Evaluating and Improving Fault Localization," in &lt;em&gt;Proceedings of the 39th international conference on software engineering&lt;/em&gt;, 2017, pp. 609-620, doi:&lt;a href="https://doi.org/10.1109/ICSE.2017.62"&gt;10.1109/ICSE.2017.62&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Jones2005"&gt;
&lt;p&gt;[29] J. A. Jones and M. J. Harrold, "Empirical Evaluation of the Tarantula Automatic Fault-localization Technique," in &lt;em&gt;Proceedings of the 20th ieee/acm international conference on automated software engineering&lt;/em&gt;, 2005, pp. 273-282, doi:&lt;a href="https://doi.org/10.1145/1101908.1101949"&gt;10.1145/1101908.1101949&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Agrawal1995"&gt;
&lt;p&gt;[30] H. Agrawal, J. Horgan, S. London, and W. Wong, "Fault localization using execution slices and dataflow tests," in &lt;em&gt;Proceedings of sixth international symposium on software reliability engineering. issre'95&lt;/em&gt;, 1995, pp. 143-151, doi:&lt;a href="https://doi.org/10.1109/ISSRE.1995.497652"&gt;10.1109/ISSRE.1995.497652&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Cleve2005"&gt;
&lt;p&gt;[31] H. Cleve and A. Zeller, "Locating causes of program failures," &lt;em&gt;Proceedings of the 27th international conference on Software engineering - ICSE '05&lt;/em&gt;, p. 342, 2005, doi:&lt;a href="https://doi.org/10.1145/1062455.1062522"&gt;10.1145/1062455.1062522&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Horwitz1990"&gt;
&lt;p&gt;[32] S. Horwitz, "Identifying the Semantic and Textual Differences Between Two Versions of a Program," &lt;em&gt;SIGPLAN Not.&lt;/em&gt;, vol. 25, no. 6, pp. 234-245, Jun. 1990, doi:&lt;a href="https://doi.org/10.1145/93548.93574"&gt;10.1145/93548.93574&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Steimann2013"&gt;
&lt;p&gt;[33] F. Steimann, M. Frenkel, and R. Abreu, "Threats to the validity and value of empirical assessments of the accuracy of coverage-based fault locators," &lt;em&gt;Proceedings of the 2013 International Symposium on Software Testing and Analysis - ISSTA 2013&lt;/em&gt;, p. 314, 2013, doi:&lt;a href="https://doi.org/10.1145/2483760.2483767"&gt;10.1145/2483760.2483767&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Wong2008"&gt;
&lt;p&gt;[34] E. Wong, T. Wei, Y. Qi, and L. Zhao, "A Crosstab-based Statistical Method for Effective Fault Localization," in &lt;em&gt;2008 international conference on software testing, verification, and validation&lt;/em&gt;, 2008, pp. 42-51, doi:&lt;a href="https://doi.org/10.1109/ICST.2008.65"&gt;10.1109/ICST.2008.65&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Landsberg2015"&gt;
&lt;p&gt;[35] D. Landsberg, H. Chockler, D. Kroening, and M. Lewis, "Evaluation of Measures for Statistical Fault Localisation and an Optimising Scheme," in &lt;em&gt;International conference on fundamental approaches to software engineering&lt;/em&gt;, 2015, vol. 9033, pp. 115-129, doi:&lt;a href="https://doi.org/10.1007/978-3-662-46675-9"&gt;10.1007/978-3-662-46675-9&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Zheng2018"&gt;
&lt;p&gt;[36] Y. Zheng, Z. Wang, X. Fan, X. Chen, and Z. Yang, "Localizing multiple software faults based on evolution algorithm," &lt;em&gt;Journal of Systems and Software&lt;/em&gt;, vol. 139, pp. 107-123, 2018, doi:&lt;a href="https://doi.org/10.1016/j.jss.2018.02.001"&gt;10.1016/j.jss.2018.02.001&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Ali2009"&gt;
&lt;p&gt;[37] S. Ali, J. H. Andrews, T. Dhandapani, and W. Wang, "Evaluating the Accuracy of Fault Localization Techniques," &lt;em&gt;2009 IEEE/ACM International Conference on Automated Software Engineering&lt;/em&gt;, pp. 76-87, 2009, doi:&lt;a href="https://doi.org/10.1109/ASE.2009.89"&gt;10.1109/ASE.2009.89&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Parnin2011"&gt;
&lt;p&gt;[38] C. Parnin and A. Orso, "Are Automated Debugging Techniques Actually Helping Programmers?" in &lt;em&gt;ISSTA&lt;/em&gt;, 2011, pp. 199-209.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Moon2014"&gt;
&lt;p&gt;[39] S. Moon, Y. Kim, M. Kim, and S. Yoo, "Ask the Mutants: Mutating faulty programs for fault localization," &lt;em&gt;Proceedings - IEEE 7th International Conference on Software Testing, Verification and Validation, ICST 2014&lt;/em&gt;, pp. 153-162, 2014, doi:&lt;a href="https://doi.org/10.1109/ICST.2014.28"&gt;10.1109/ICST.2014.28&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Liu2006"&gt;
&lt;p&gt;[40] C. Liu, C. Chen, J. Han, and P. S. Yu, "GPLAG: Detection of Software Plagiarism by Program Dependence Graph Analysis," in &lt;em&gt;Proceedings of the 12th acm sigkdd international conference on knowledge discovery and data mining&lt;/em&gt;, 2006, pp. 872-881, doi:&lt;a href="https://doi.org/10.1145/1150402.1150522"&gt;10.1145/1150402.1150522&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Ferrante1987"&gt;
&lt;p&gt;[41] J. Ferrante, K. J. Ottenstein, and J. D. Warren, "The program dependence graph and its use in optimization," vol. 9. pp. 319-349, Jul-1987.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-DiGiuseppe2011"&gt;
&lt;p&gt;[42] N. DiGiuseppe and J. A. Jones, "On the influence of multiple faults on coverage-based fault localization," in &lt;em&gt;Proceedings of the 2011 international symposium on software testing and analysis - issta '11&lt;/em&gt;, 2011, p. 210, doi:&lt;a href="https://doi.org/10.1145/2001420.2001446"&gt;10.1145/2001420.2001446&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Wong2007"&gt;
&lt;p&gt;[43] W. E. Wong, Y. Qi, L. Zhao, and K. Y. Cai, "Effective fault localization using code coverage," &lt;em&gt;Proceedings - International Computer Software and Applications Conference&lt;/em&gt;, vol. 1, no. Compsac, pp. 449-456, 2007, doi:&lt;a href="https://doi.org/10.1109/COMPSAC.2007.109"&gt;10.1109/COMPSAC.2007.109&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Naish2011"&gt;
&lt;p&gt;[44] L. Naish, H. J. Lee, and K. Ramamohanarao, "A model for spectra-based software diagnosis," &lt;em&gt;ACM Transactions on Software Engineering and Methodology&lt;/em&gt;, vol. 20, no. 3, pp. 1-32, 2011, doi:&lt;a href="https://doi.org/10.1145/2000791.2000795"&gt;10.1145/2000791.2000795&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Liu2005"&gt;
&lt;p&gt;[45] C. Liu, H. Yu, P. S. Yu, X. Yan, H. Yu, J. Han, and P. S. Yu, "Mining Behavior Graphs for ‘Backtrace' of Noncrashing Bugs," in &lt;em&gt;Proceedings of the 2005 siam international conference on data mining&lt;/em&gt;, 2005, pp. 286-297, doi:&lt;a href="https://doi.org/10.1137/1.9781611972757.26"&gt;10.1137/1.9781611972757.26&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Eichinger2008"&gt;
&lt;p&gt;[46] F. Eichinger, K. Böhm, and M. Huber, "Mining Edge-Weighted Call Graphs to Localise Software Bugs," in &lt;em&gt;European conference machine learning and knowledge discovery in databases&lt;/em&gt;, 2008, pp. 333-348, doi:&lt;a href="https://doi.org/10.1007/978-3-540-87479-9_40"&gt;10.1007/978-3-540-87479-9_40&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Chilimbi2009"&gt;
&lt;p&gt;[47] T. M. Chilimbi, B. Liblit, K. Mehra, A. V. Nori, and K. Vaswani, "HOLMES: Effective Statistical Debugging via Efficient Path Profiling," in &lt;em&gt;Proceedings of the 31st international conference on software engineering&lt;/em&gt;, 2009, pp. 34-44, doi:&lt;a href="https://doi.org/10.1109/ICSE.2009.5070506"&gt;10.1109/ICSE.2009.5070506&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Yousefi2013"&gt;
&lt;p&gt;[48] A. Yousefi and A. Wassyng, "A Call Graph Mining and Matching Based Defect Localization Technique," in &lt;em&gt;2013 ieee sixth international conference on software testing, verification and validation workshops&lt;/em&gt;, 2013, pp. 86-95, doi:&lt;a href="https://doi.org/10.1109/ICSTW.2013.17"&gt;10.1109/ICSTW.2013.17&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Diamantopoulos2014"&gt;
&lt;p&gt;[49] T. Diamantopoulos and A. Symeonidis, "Localizing Software Bugs using the Edit Distance of Call Traces," &lt;em&gt;International Journal on Advances in Software&lt;/em&gt;, vol. 7, no. 1 &amp;amp; 2, pp. 277-288, 2014.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Mousavian2011"&gt;
&lt;p&gt;[50] Z. Mousavian, M. Vahidi-Asl, and S. Parsa, "Scalable Graph Analyzing Approach for Software Fault-localization," in &lt;em&gt;Proceedings of the 6th international workshop on automation of software test&lt;/em&gt;, 2011, pp. 15-21, doi:&lt;a href="https://doi.org/10.1145/1982595.1982599"&gt;10.1145/1982595.1982599&lt;/a&gt;.&lt;/p&gt;
&lt;/div&gt;
&lt;div id="ref-Eichinger2010"&gt;
&lt;p&gt;[51] F. Eichinger, K. Krogmann, R. Klug, and K. Böhm, "Software-defect Localisation by Mining Dataflow-enabled Call Graphs," in &lt;em&gt;Proceedings of the 2010 european conference on machine learning and knowledge discovery in databases: Part i&lt;/em&gt;, 2010, pp. 425-441.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1"&gt;&lt;p&gt;The coverage can be collected at other levels as well. For instance there has been work which collects it at the class, method, and basic block levels.&lt;a href="#fnref1"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2"&gt;&lt;p&gt;A basic block is a sequence of sequential instructions, always entered from the first instruction and exited from the last &lt;span class="citation"&gt;[&lt;a href="#ref-Aho2007"&gt;4&lt;/a&gt;]&lt;/span&gt;.&lt;a href="#fnref2"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3"&gt;&lt;p&gt;It is ahistorical to call Tarantula metric a suspiciousness score when referring to the 2002 paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2002"&gt;1&lt;/a&gt;]&lt;/span&gt;. Jones introduced the term suspiciousness score in the 2005 paper &lt;span class="citation"&gt;[&lt;a href="#ref-Jones2005"&gt;29&lt;/a&gt;]&lt;/span&gt; for the purpose of ranking the statements. However, the term is now in common use and it was explained above.&lt;a href="#fnref3"&gt;↩&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Behavioral Fault Localization by Sampling Suspicious Dynamic Control Flow Subgraphs</title><link href="https://hackthology.com/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html" rel="alternate"/><published>2018-04-03T00:00:00-04:00</published><updated>2018-04-03T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt; and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2018-04-03:/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html</id><summary type="html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski.
&lt;em&gt;Behavioral Fault Localization by Sampling Suspicious Dynamic Control Flow
Subgraphs&lt;/em&gt;.  &lt;a href="http://www.es.mdh.se/icst2018/"&gt;ICST 2018&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://dx.doi.org/10.1109/ICST.2018.00019"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2018.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;We present a new algorithm, Score Weighted Random Walks (SWRW), for behavioral
fault localization. Behavioral fault localization localizes faults (bugs) in
programs to a group of interacting …&lt;/p&gt;</summary><content type="html">&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski.
&lt;em&gt;Behavioral Fault Localization by Sampling Suspicious Dynamic Control Flow
Subgraphs&lt;/em&gt;.  &lt;a href="http://www.es.mdh.se/icst2018/"&gt;ICST 2018&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://dx.doi.org/10.1109/ICST.2018.00019"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/icst-2018.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/behavioral-fault-localization-by-sampling-suspicious-dynamic-control-flow-subgraphs.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;We present a new algorithm, Score Weighted Random Walks (SWRW), for behavioral
fault localization. Behavioral fault localization localizes faults (bugs) in
programs to a group of interacting program elements such as basic blocks or
functions.  SWRW samples suspicious (or discriminative) subgraphs from
basic-block level dynamic control flow graphs collected during the execution of
passing and failing tests.  The suspiciousness of a subgraph may be measured by
any one of a family of new metrics adapted from probabilistic formulations of
existing coverage-based statistical fault localization metrics.  We conducted an
empirical evaluation of SWRW with nine subgraph-suspiciousness measures on five
real-world subject programs.  The results indicate that SWRW outperforms
previous fault localization techniques based on discriminative subgraph mining.&lt;/p&gt;
&lt;h1&gt;Introduction&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;Automated fault localization&lt;/em&gt; techniques have been developed to help
programmers locate software faults (bugs) responsible for observed software
failures.  Many of these techniques are statistical in nature (e.g., {&lt;a href="https://dx.doi.org/10.1145/581339.581397"&gt;Jones
2002&lt;/a&gt;, &lt;a href="https://dx.doi.org/10.1145/1064978.1065014"&gt;Liblit
2005&lt;/a&gt;, &lt;a href="https://dx.doi.org/10.1137/1.9781611972757.26"&gt;Liu
2005&lt;/a&gt;}).  They employ statistical
measures of the &lt;em&gt;association&lt;/em&gt;, if any, between the occurrence of failures and
the execution of particular program elements like statements or conditional
branches.  The program elements that are most strongly associated with failures
are identified as "suspicious", so that developers can examine them to see if
they are faulty.  The association measures that are used are often called
&lt;em&gt;suspiciousness metrics&lt;/em&gt; {&lt;a href="https://dx.doi.org/10.1109/ICSE.2004.1317420"&gt;Jones
2004&lt;/a&gt;}.  Such &lt;em&gt;statistical fault
localization&lt;/em&gt; (SFL) techniques typically require &lt;em&gt;execution profiles&lt;/em&gt; (or
&lt;em&gt;spectra&lt;/em&gt;) and PASS/FAIL labels for a set of both passing and failing program
runs.  Each profile entry characterizes the execution of a
particular program element during a run.  For example, a statement-coverage
profile for a run indicates which statements were executed at least once.  The
profiles are collected with program instrumentation, while the labels are
typically supplied by software testers or end users.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Coverage Based Statistical Fault Localization&lt;/em&gt; (CBSFL) techniques compute a
suspiciousness score for each program element. The elements are presented to the
programmer as a ranked list with the most suspicious elements at the top
{&lt;a href="https://dx.doi.org/10.1145/1064978.1065014"&gt;Liblit 2005&lt;/a&gt;}.  Programmers
utilize the list to guide their debugging effort by starting at the most
suspicious element and moving down. The effectiveness of a CBSFL suspiciousness
metric is judged by how accurately it ranks a bug's (or bugs) location in a
program. The higher in the list the bug's location appears the better the metric
performs {&lt;a href="https://dx.doi.org/10.1002/smr.1616"&gt;Lucia 2014&lt;/a&gt;}.&lt;/p&gt;
&lt;p&gt;Kochhar &lt;em&gt;et al.&lt;/em&gt;  {&lt;a href="https://dx.doi.org/10.1145/2931037.2931051"&gt;Kochhar 2016&lt;/a&gt;}
recently surveyed 386 software engineering practitioners about their
expectations for automated fault localization. While practitioners indicated
their preference for very accurate algorithms, over 85% of respondents also
indicated their preference for tools which help them understand the output of
fault localization algorithms. This is an important finding as most statistical
approaches do not provide an explanation of their results. The SFL techniques
often simply compute suspiciousness measures and rank the program elements
accordingly.  These rankings may be helpful, but without more information
programmers could overlook the faulty element even when it is ranked highly.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Localization Process" src="/images/icst-localization-process.png"&gt;&lt;/p&gt;
&lt;div style="text-align: center; margin-top: -2em;"&gt;
&lt;strong&gt;Figure 1.&lt;/strong&gt; Process for localizing faults  with discriminative graph mining.
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Suspicious-Behavior Based Fault Localization&lt;/em&gt; (SBBFL) is a statistical fault
localization technique that aids the programmer in understanding suspiciousness
scores by providing a &lt;em&gt;context&lt;/em&gt; of interacting elements.
&lt;span style="color: gray"&gt;(&lt;em&gt;NB: Dynamic slicing {&lt;a href="https://www.franktip.org/pubs/jpl1995.pdf"&gt;Tip
1995&lt;/a&gt;} also provides such a context, but does
not in itself involve suspiciousness measures&lt;/em&gt;)&lt;/span&gt; Instead of implicating a
single element, SBBFL implicates a larger runtime behavior (see process in
Figure 1). The implicated control flow paths (or subgraphs) may help the
programmer understand the nature of a bug {&lt;a href="https://dx.doi.org/10.1145/1572272.1572290"&gt;Cheng
2009&lt;/a&gt;}.&lt;/p&gt;
&lt;p&gt;We present a new algorithm, &lt;em&gt;Score-Weighted Random Walks&lt;/em&gt; (SWRW), for
behavioral fault-localization.  SWRW belongs to a family of
&lt;em&gt;discriminative graph-mining algorithms&lt;/em&gt;  that have previously been used
for behavioral fault localization 
{
&lt;a href="https://dx.doi.org/10.1137/1.9781611972757.26"&gt;Liu 2005&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1145/1188895.1188910"&gt;DiFatta 2006&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1007/978-3-540-87479-9_40"&gt;Eichinger 2008&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1145/1572272.1572290"&gt;Cheng 2009&lt;/a&gt;,
&lt;a href="http://dl.acm.org/citation.cfm?id=1888258.1888293"&gt;Eichinger 2010&lt;/a&gt;,
&lt;a href="http://www.scopus.com/inward/record.url?eid=2-s2.0-84880082474&amp;amp;partnerID=tZOtx3y1"&gt;Eichinger 2011&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1145/1982595.1982599"&gt;Mousavian 2011&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1109/TSE.2010.93"&gt;Mariani 2011&lt;/a&gt;,
&lt;a href="http://dl.acm.org/citation.cfm?id=2029256.2029305"&gt;Parsa 2011&lt;/a&gt;,
&lt;a href="https://dx.doi.org/10.1109/ICSTW.2013.17"&gt;Yousefi 2013&lt;/a&gt;
}. Graph mining is very powerful in principle but algorithms must
make trade-offs to address the challenging combinatorics of the graph mining
problem.  Our new algorithm, SWRW, mitigates the combinatorics by randomly
sampling "suspicious" subgraphs from dynamic control flow graphs.  During the
sampling process, the most suspicious subgraphs (as judged by a suitable
suspiciousness metric) are favored for selection. Unlike previous algorithms,
SWRW can be used with a wide variety of suspiciousness metrics --- which allows
it to use better metrics than available to previous work.  Even when using the
same metric as similar algorithms, SWRW localizes faults more accurately than
they do.&lt;/p&gt;
&lt;h2&gt;Summary of Contributions&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A new behavioral fault localization algorithm, SWRW, that samples suspicious
   subgraphs from dynamic control flow graphs.  Unlike similar algorithms, SWRW
   can be used with a variety of suspiciousness metrics.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;New generalizations of existing suspiciousness metrics that allow them to be
   applied to behaviors represented by subgraphs of dynamic control flow graphs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;An empirical study whose results suggest that SWRW is more accurate than
   similar algorithms.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Dynagrok, a new instrumentation, mutation, and analysis tool for the Go
   programming language.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Dynagrok: A New Profiling Tool&lt;/h1&gt;
&lt;p&gt;All &lt;em&gt;Coverage-Based Statistical Fault Localization&lt;/em&gt; (CBSFL) techniques use
&lt;em&gt;coverage profiles&lt;/em&gt; to gather information on how software behaved when
executed on a set of test inputs. A coverage profile typically contains an entry
for each program element of a given kind (e.g., statement, basic block, branch,
or function), which records whether (and possibly how many times) the element
was executed during the corresponding program run.  The profiles and PASS/FAIL
labels for all tests are then used to compute a statistical
&lt;em&gt;suspiciousness score&lt;/em&gt; for each program element.&lt;/p&gt;
&lt;p&gt;The process of gathering the coverage information from running programs is
called &lt;em&gt;profiling&lt;/em&gt; and there are many different varieties of profilers and
profiling techniques available. Coverage profiling is a simple and widely
implemented technique, which is why it has been widely used by the fault
localization community. Another technique is &lt;em&gt;tracing&lt;/em&gt;, which logs the sequence
of program locations as they are executed. The traces provide detailed
information on the behavior of the program but could grow to be very large for
long running programs. This paper uses &lt;em&gt;execution flow profiling&lt;/em&gt; which
computes the dynamic interprocedural control flow graph of a program's
execution.  This provides some of the benefits of tracing without recording an
excessive amount of data.&lt;/p&gt;
&lt;p&gt;To capture execution flow profiles we developed
&lt;a href="https://github.com/timtadh/dynagrok"&gt;Dynagrok&lt;/a&gt;, a new analysis, instrumentation
and mutation platform for the Go programming language. Go is a newer language
(2009) from Google that has been seeing increasing adoption in industry. It has
been adopted for web programming, systems programming, "DevOps," network
programing, and databases {&lt;a href="http://tiobe.com/tiobe-index/"&gt;http://tiobe.com/tiobe-index/&lt;/a&gt;,
&lt;a href="http://blog.golang.org/survey2017-results"&gt;http://blog.golang.org/survey2017-results&lt;/a&gt;}.  Dynagrok builds upon the
&lt;em&gt;abstract syntax tree&lt;/em&gt; (AST) representation provided by the Go standard
library.&lt;/p&gt;
&lt;p&gt;
Dynagrok collects profiles by inserting instrumentation into the AST of the
subject program.  The profiles currently collected are &lt;em&gt;dynamic control flow
graphs&lt;/em&gt; (DCFGs) whose vertices represent basic blocks. A &lt;em&gt;basic
block&lt;/em&gt; is a sequence of program operations that can only be entered at the
start of the sequence and can only be exited after the last operation in the
sequence 
{&lt;a href="https://www.worldcat.org/title/compilers-principles-techniques-and-tools/oclc/12285707"&gt;Aho 2007&lt;/a&gt;}.
A basic-block level &lt;em&gt;control flow graph&lt;/em&gt; (CFG) is a directed labeled
graph &lt;span class="math"&gt;\(g = (V, E, l)\)&lt;/span&gt; comprised of a finite set of
vertices &lt;span class="math"&gt;\(V\)&lt;/span&gt;, a set of edges &lt;span class="math"&gt;\(E
\subseteq V \times V\)&lt;/span&gt;, and a labeling function &lt;span
class="math"&gt;\(l\)&lt;/span&gt; mapping vertices and edges to labels.  Each vertex
&lt;span class="math"&gt;\(v \in V\)&lt;/span&gt; represents a basic block of the program.
Each edge &lt;span class="math"&gt;\((u, v) \in E\)&lt;/span&gt; represents a transition in
program execution from block &lt;span class="math"&gt;\(u\)&lt;/span&gt; to block &lt;span
class="math"&gt;\(v\)&lt;/span&gt;. The labeling function &lt;span class="math"&gt;\(l\)&lt;/span&gt;
labels the basic blocks with a unique identifier (e.g.
&lt;code&gt;function-name:block-id&lt;/code&gt;), which is consistently applied across
multiple executions but is never repeated in the same execution.
&lt;/p&gt;

&lt;p&gt;Figure 2 shows an example DCFG collected by Dynagrok for a simple program that
computes terms of the Fibonacci sequence. To collect such graphs Dynagrok parses
the program into an AST using Go's standard library.  Dynagrok then uses a
custom control flow analysis to build static control flow graphs. Each basic
block holds pointers to the statements inside of the AST. The blocks also have a
pointer to the enclosing &lt;em&gt;lexical block&lt;/em&gt; in the AST.  Using this information,
Dynagrok inserts profiling instructions into the AST at the beginning of each
basic block. The instructions inserted by Dynagrok use its &lt;code&gt;dgruntime&lt;/code&gt; library
to track the control flow of each thread (which is called a &lt;em&gt;goroutine&lt;/em&gt; in Go).
When the program shuts down (either normally or abnormally) the &lt;code&gt;dgruntime&lt;/code&gt;
library merges the flow graphs from all the threads together and writes out the
result.&lt;/p&gt;
&lt;p&gt;(&lt;a href="https://hackthology.com/pdfs/icst-2018.pdf"&gt;Read the rest of the paper as a pdf&lt;/a&gt;)&lt;/p&gt;
&lt;div style="text-align: center;"&gt;
&lt;img src="/images/icst-dcfg.png"
     text="Example Dynamic Control Flow Graph"
     style="width: 65%;"/&gt;
&lt;/div&gt;
&lt;div style="text-align: center; margin-top: -1em;"&gt;
&lt;strong&gt;Figure 2.&lt;/strong&gt; 
The dynamic control flow graph (DCFG) for the program &lt;br&gt;
in  Listing 1 (see below).
&lt;/div&gt;
&lt;div style="width: 90%; left:05%; position: relative;"&gt;
Each vertex is a basic block with a basic block identifer (e.g.
&lt;code&gt;b1&lt;/code&gt;) that, in conjunction with the name of the containing function,
serves as the label for the block (e.g. &lt;code&gt;main:b1&lt;/code&gt;). Each edge shows
the number of traversals taken during the execution of the program.  Note that
the loop update blocks (&lt;code&gt;main:b3&lt;/code&gt; and &lt;code&gt;fib:b7&lt;/code&gt;) will not
be in the profiles because Dynagrok instruments the Go source code and profiling
instructions cannot be syntactically inserted in those locations.  The
instrumented program is shown on the right.
&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div style="text-align: center; margin-top: -1em;"&gt;
&lt;strong&gt;Listing 1.&lt;/strong&gt; 
An example Go program to compute the Fibonacci Sequence.
&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;dgruntime&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Shutdown&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExitFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;main&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlkFromCond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fib&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ExitFunc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fib&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlkFromCond&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;dgruntime&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EnterBlk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div style="text-align: center; margin-top: -1em;"&gt;
&lt;strong&gt;Listing 2.&lt;/strong&gt; 
The program shown in Listing 1 after the instrumentation has been inserted by
dynagrok.
&lt;/div&gt;</content><category term="Paper"/></entry><entry><title>How to Tokenize Complex Strings with Lexmachine</title><link href="https://hackthology.com/how-to-tokenize-complex-strings-with-lexmachine.html" rel="alternate"/><published>2017-12-08T00:00:00-05:00</published><updated>2017-12-08T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2017-12-08:/how-to-tokenize-complex-strings-with-lexmachine.html</id><summary type="html">&lt;p&gt;This article is about using &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt;
to tokenize strings (split up into component parts) in the Go (golang)
programming language. If you find yourself processing a complex file format or
network protocol this article will walk you through how to use &lt;code&gt;lexmachine&lt;/code&gt; to
process both accurately and quickly. If you …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This article is about using &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt;
to tokenize strings (split up into component parts) in the Go (golang)
programming language. If you find yourself processing a complex file format or
network protocol this article will walk you through how to use &lt;code&gt;lexmachine&lt;/code&gt; to
process both accurately and quickly. If you need more help after reading this
article take a look at the
&lt;a href="https://github.com/timtadh/lexmachine#documentation"&gt;documentation&lt;/a&gt;, a
&lt;a href="http://hackthology.com/writing-a-lexer-in-go-with-lexmachine.html"&gt;tutorial&lt;/a&gt;,
or an &lt;a href="http://hackthology.com/faster-tokenization-with-a-dfa-backend-for-lexmachine.html"&gt;explainer
article&lt;/a&gt;
on how it all works.&lt;/p&gt;
&lt;h1&gt;What is string tokenization?&lt;/h1&gt;
&lt;p&gt;String tokenization takes a piece of text and splits it into categorized
substrings. When conducted as part of parsing or compiling a programming
language it may also be called &lt;em&gt;lexical analysis&lt;/em&gt;. Depending on the kind of text
being processed splitting it up might be very simple or extremely complicated.
For instance, some simple text formats (such as basic CSV or TSV files) separate
each record by newline characters (&lt;code&gt;\n&lt;/code&gt; or ASCII &lt;code&gt;0x0A&lt;/code&gt;). At the other end of
the spectrum, natural language (such as English text) may be very difficult to
correctly tokenize.&lt;/p&gt;
&lt;p&gt;Let's look at a quick example of tokenizing an English sentence. &lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Mary had a little lamb and its fleece was white as snow.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Each word will be a separate token.  A &lt;em&gt;token&lt;/em&gt; is a pair made up of the &lt;em&gt;lexeme&lt;/em&gt;
(or substring) and the &lt;em&gt;token type&lt;/em&gt; (or category). When tokenizing English,
often the token type will be the part of speech.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt; Mary           had     a          little      lamb    and            ...
&amp;lt;Proper Noun&amp;gt;  &amp;lt;Verb&amp;gt;  &amp;lt;Article&amp;gt;  &amp;lt;Adjetive&amp;gt;  &amp;lt;Noun&amp;gt;  &amp;lt;Conjunction&amp;gt;   ...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Tokenizing English is very difficult in general because determining the part of
speech of a particular word is not always obvious. The same word can play
multiple &lt;em&gt;semantic&lt;/em&gt; roles in a sentence. Humans consider the sentence in its
entirety when determining the parts of speech for each word. This allows us to
"noun verbs" and "verb nouns."&lt;/p&gt;
&lt;h2&gt;String tokenization as part of parsing&lt;/h2&gt;
&lt;p&gt;There are many common applications of tokenization which are not as difficult as
assigning parts of speech to words in English. For instance, computer languages,
configuration files, log files, network protocols, data interchange formats,
etc... are all easy to tokenize. In these applications (as with natural
language), tokenization is the first step in parsing or compilation and is
called lexical analysis.&lt;/p&gt;
&lt;p&gt;Modern compilers are designed as a "pipeline" or series of steps (called passes)
which operate over a program. They take the source code and transform it step
by step into the desired output (machine code, assembly, another programming
language). Breaking compilation into steps simplifies each stage and makes the
individual passes reusable. The start of the pipeline is shown in Figure 1.&lt;/p&gt;
&lt;p&gt;&lt;img alt="The pipeline of a compiler. Source Code - Lexing - Tokens - Parsing - AST -
..." src="/images/compiler-structure.png"&gt;&lt;/p&gt;
&lt;div style="text-align: center; margin-top: -2em;"&gt;
&lt;strong&gt;Figure 1.&lt;/strong&gt; The start of a compiler's pipeline of passes.&lt;br/&gt;
A compiler starts with source code and then preforms lexical analysis to split
the code up into *tokens*. Then, the *parser* transforms that stream or list of
tokens into a structured format (often an Abstract Syntax Tree).
&lt;/div&gt;

&lt;p&gt;But why tokenize before parsing? Surely, the parser could operate on the bytes
of the source code rather than on a list of tokens. Some parsers do operate
directly on the bytes. However, the parser can be simplified and made shorter
and often more robust by defining it over tokens rather than bytes.&lt;/p&gt;
&lt;p&gt;Consider the following, programming languages often have keywords: &lt;code&gt;func&lt;/code&gt;,
&lt;code&gt;return&lt;/code&gt;, &lt;code&gt;if&lt;/code&gt;. They also have "identifiers" or names. The keywords are set
aside as special names and are treated by a parser the same way other names are
treated as they often denote the start of special syntactic regions. In this
way, they really operate in a similar manner to punctuation in written English.&lt;/p&gt;
&lt;p&gt;However, since keywords would be valid names if they were not reserved special
care must be taken in a parser which operates on bytes directly not to
accidentally classify a keyword as a name. Parsers which work on tokens rather
than bytes can ignore this problem as it is handled at the lexical analysis
stage.&lt;/p&gt;
&lt;h2&gt;Processing a custom configuration file format&lt;/h2&gt;
&lt;p&gt;As a motivating example for why you might need to perform a tokenization
operation in your daily life as a programmer let's take a look at processing a
customer configuration file format. Linux has a library &lt;code&gt;libsensor&lt;/code&gt; which allows
it to read and understand the output of hardware sensors (such as CPU
temperature probes). It has a custom configuration file format,
&lt;a href="https://linux.die.net/man/5/sensors.conf"&gt;sensors.conf&lt;/a&gt;, which describes how
Linux should translate the raw readings hardware monitoring chips to real-world
values -- such as voltage and temperature. The first part of my laptop's
&lt;code&gt;sensors.conf&lt;/code&gt; file begins with the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; It is recommended not to modify this file, but to drop your local
&lt;span class="gh"&gt;#&lt;/span&gt; changes in /etc/sensors.d/. File with names that start with a dot
&lt;span class="gh"&gt;#&lt;/span&gt; are ignored.

chip &amp;quot;lm78-*&amp;quot; &amp;quot;lm79-*&amp;quot; &amp;quot;lm80-*&amp;quot; &amp;quot;lm96080-*&amp;quot;

    label temp1 &amp;quot;M/B Temp&amp;quot;


chip &amp;quot;w83792d-*&amp;quot;

    label in0 &amp;quot;VcoreA&amp;quot;
    label in1 &amp;quot;VcoreB&amp;quot;
    label in6 &amp;quot;+5V&amp;quot;
    label in7 &amp;quot;5VSB&amp;quot;
    label in8 &amp;quot;Vbat&amp;quot;

    set in6_min  5.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in6_max  5.0 *&lt;/span&gt; 1.10
    set in7_min  5.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in7_max  5.0 *&lt;/span&gt; 1.10
    set in8_min  3.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in8_max  3.0 *&lt;/span&gt; 1.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Let's pretend we want to extract some information from &lt;code&gt;sensors.conf&lt;/code&gt; files. For
instance, maybe we want to know for each chip what labels have been defined.
Straightforward enough and definitely doable "by hand" if necessary but much
easier if the file is preprocessed to pull out the tokens:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Type    | Lexeme
-------------------
COMMENT | # It is recommended not to modify this file, but to drop your local
COMMENT | # changes in /etc/sensors.d/. File with names that start with a dot
COMMENT | # are ignored.
CHIP    | chip
NAME    | &amp;quot;lm78-*&amp;quot;
NAME    | &amp;quot;lm78-*&amp;quot;
NAME    | &amp;quot;lm79-*&amp;quot;
NAME    | &amp;quot;lm80-*&amp;quot;
NAME    | &amp;quot;lm96080-*&amp;quot;
LABEL   | label
NAME    | temp1
NAME    | &amp;quot;M/B Temp&amp;quot;
CHIP    | chip
NAME    | &amp;quot;w83792d-*&amp;quot;
...
SET     | set
NAME    | in8_max
FLOAT   | 3.0
STAR    | *
FLOAT   | 1.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;According to the &lt;a href="https://linux.die.net/man/5/sensors.conf"&gt;man page&lt;/a&gt; the chip
and label statements have the following structure (other bits left out):&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;&lt;em&gt;chip&lt;/em&gt; Statement&lt;/h4&gt;
&lt;p&gt;A  chip  statement selects for which chips all following &lt;em&gt;compute&lt;/em&gt;, &lt;em&gt;label&lt;/em&gt;,
&lt;em&gt;ignore&lt;/em&gt; and &lt;em&gt;set&lt;/em&gt; statements are meant for.&lt;/p&gt;
&lt;h4&gt;&lt;em&gt;label&lt;/em&gt; Statement&lt;/h4&gt;
&lt;p&gt;A  label statement describes how a feature should be called.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;chip&lt;/em&gt; &lt;strong&gt;NAME-LIST&lt;/strong&gt; &lt;br/&gt;
&lt;em&gt;label&lt;/em&gt; &lt;strong&gt;NAME&lt;/strong&gt; &lt;strong&gt;NAME&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A  &lt;strong&gt;NAME&lt;/strong&gt;  is  a string. If it only contains letters, digits and
underscores, it does not have to be quoted; in all other cases, you must use
double quotes around it.  Within quotes, you can use the normal escape-codes
from C.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;NAME-LIST&lt;/strong&gt; is one or more &lt;strong&gt;NAME&lt;/strong&gt; items behind each other, separated by
whitespace.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;So to find all of the labeled "features" of a chip we need to do two things.
First, find a &lt;code&gt;chip&lt;/code&gt; statement and collect all the names associated with it.
These names are actually patterns which match multiple chips but we will ignore
that for this example. Second, collect all the &lt;code&gt;label&lt;/code&gt; statements (and the two
associated names). The labels go with the chips which immediately proceed them.&lt;/p&gt;
&lt;p&gt;To implement the above idea we are going to use
&lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; to construct a &lt;em&gt;lexer&lt;/em&gt; (or
tokenizer) which split up the file into the appropriate tokens.&lt;/p&gt;
&lt;h1&gt;Defining a lexer with lexmachine&lt;/h1&gt;
&lt;p&gt;A &lt;em&gt;lexer&lt;/em&gt; (or tokenizer) is defined by a set of &lt;em&gt;categories&lt;/em&gt; (token types) which
are defined by &lt;em&gt;patterns&lt;/em&gt;. The patterns (in a traditional lexer) are expressed
as &lt;a href="https://github.com/timtadh/lexmachine#regular-expressions"&gt;regular
expressions&lt;/a&gt;.   As a
quick and incomplete review, regular expressions (regex) are a "pattern" which
describe a set of strings. A regex is made up of characters (&lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;,
...) which combine with the operators: concatenation &lt;code&gt;abc&lt;/code&gt;, alternation &lt;code&gt;a|b&lt;/code&gt;,
grouping &lt;code&gt;a(b|c)d&lt;/code&gt;, and repetition &lt;code&gt;a*&lt;/code&gt;. Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;abc&lt;/code&gt; matches {&lt;code&gt;"abc"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a|b&lt;/code&gt; matches {&lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"b"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a(b|c)d&lt;/code&gt; matches {&lt;code&gt;"abd"&lt;/code&gt;, &lt;code&gt;"acd"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a*&lt;/code&gt; matches {&lt;code&gt;""&lt;/code&gt;, &lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"aa"&lt;/code&gt;, ...}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a(b(c|d))*&lt;/code&gt; matches {&lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"abc"&lt;/code&gt;, &lt;code&gt;"abd"&lt;/code&gt;, &lt;code&gt;"abcbc"&lt;/code&gt;, &lt;code&gt;"abcbd"&lt;/code&gt;, ...}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A fairly close reading of the &lt;a href="https://linux.die.net/man/5/sensors.conf"&gt;man
page&lt;/a&gt; for &lt;code&gt;sensors.conf&lt;/code&gt; gives the
following regular expressions to tokenize the file. (Note: &lt;code&gt;[]&lt;/code&gt; define
&lt;a href="https://github.com/timtadh/lexmachine#character-classes"&gt;character classes&lt;/a&gt;
which express a number of alternative characters to match)&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;AT&lt;/code&gt;: &lt;code&gt;@&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PLUS&lt;/code&gt;: &lt;code&gt;\+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;STAR&lt;/code&gt;: &lt;code&gt;\*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DASH&lt;/code&gt;: &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SLASH&lt;/code&gt;: &lt;code&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BACKSLASH&lt;/code&gt;: &lt;code&gt;\\&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CARROT&lt;/code&gt;: &lt;code&gt;\^&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BACKTICK&lt;/code&gt;: &lt;code&gt;`&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COMMA&lt;/code&gt;: &lt;code&gt;,&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LPAREN&lt;/code&gt;: &lt;code&gt;\(&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RPAREN&lt;/code&gt;: &lt;code&gt;\)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;BUS&lt;/code&gt;: &lt;code&gt;bus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;CHIP&lt;/code&gt;: &lt;code&gt;chip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;LABEL&lt;/code&gt;: &lt;code&gt;label&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COMPUTE&lt;/code&gt;: &lt;code&gt;compute&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;IGNORE&lt;/code&gt;: &lt;code&gt;ignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SET&lt;/code&gt;: &lt;code&gt;set&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NUMBER&lt;/code&gt;: &lt;code&gt;[0-9]*\.?[0-9]+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;COMMENT&lt;/code&gt;: &lt;code&gt;#[^\n]*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SPACE&lt;/code&gt;: &lt;code&gt;\s+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NAME&lt;/code&gt;: &lt;code&gt;[a-zA-Z_][a-zA-Z0-9_]*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;NAME&lt;/code&gt;: &lt;code&gt;"((\\\\)|(\\.)|([^"\\]))*"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these regular expressions in hand let's define a lexer using
&lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; and use it to tokenize an
example &lt;code&gt;sensors.conf&lt;/code&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h4&gt;Aside, can't we just use &lt;a href="https://golang.org/pkg/regexp/"&gt;regexp&lt;/a&gt;?&lt;/h4&gt;
&lt;p&gt;A lexical analysis engine is very similar to a
standard regular expression engine. However, the problem which regular
expression engines solve (matching whole strings or finding patterns inside of
strings) is slightly different than the lexial analysis problem. You could
implement a lexical analyzer with the &lt;code&gt;regexp&lt;/code&gt; package but it would be much
slower than &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt;.  Lexical
analysis engines are fast because they use the same &lt;a href="http://hackthology.com/faster-tokenization-with-a-dfa-backend-for-lexmachine.html"&gt;theoretical
framework&lt;/a&gt;
as is used to implement regular expression engines with the following
adjustments:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prefixes of a string are matched&lt;/li&gt;
&lt;li&gt;All patterns are matched at the same time&lt;/li&gt;
&lt;li&gt;The pattern which matches the longest prefix wins&lt;/li&gt;
&lt;li&gt;In case of ties, the pattern with the highest precedence wins&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Constructing a &lt;code&gt;*lexmachine.Lexer&lt;/code&gt;&lt;/h2&gt;
&lt;h3&gt;Importing the packages&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/lexmachine&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/lexmachine/machines&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Defining the tokens types&lt;/h3&gt;
&lt;p&gt;There are many ways to represent the token types (categories). In this example,
the names of the types are defined as a list of strings. The types themselves
(&lt;code&gt;id&lt;/code&gt;s) will be the index of the names. An &lt;code&gt;init&lt;/code&gt; function is used to construct
a reverse mapping from name to &lt;code&gt;id&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;AT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PLUS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;STAR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SLASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BACKSLASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CARROT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BACKTICK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LPAREN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;RPAREN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BUS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMPUTE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CHIP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IGNORE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LABEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NUMBER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SPACE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Constructing a new lexer object&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Adding a single pattern&lt;/h3&gt;
&lt;p&gt;Patterns are added using the
&lt;a href="https://godoc.org/github.com/timtadh/lexmachine#Lexer.Add"&gt;lexer.Add&lt;/a&gt; method.
Let's add the pattern for the &lt;code&gt;chip&lt;/code&gt; keyword:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`chip`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Add&lt;/code&gt; method takes two arguments. The first is the regular expression and
the second is the &lt;em&gt;lexing action&lt;/em&gt; function. The action is called on pattern
discovery. This action typically takes a low-level
&lt;a href="https://godoc.org/github.com/timtadh/lexmachine/machines#Match"&gt;*machines.Match&lt;/a&gt;
object and turns it into a token representation of your (the user's) choice.&lt;/p&gt;
&lt;p&gt;For users who do not have strict requirements for how tokens are represented
the &lt;a href="https://godoc.org/github.com/timtadh/lexmachine#Token"&gt;*lexmachine.Token&lt;/a&gt;
object provides a useful implementation. &lt;a href="https://godoc.org/github.com/timtadh/lexmachine#Scanner"&gt;*lexmachine.Scanner&lt;/a&gt; has a utility
method for constructing the tokens which helps us write a simple &lt;code&gt;getToken&lt;/code&gt;
action:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokenType&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Adding all the patterns&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;@&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;AT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;PLUS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;STAR&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SLASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BACKSLASH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\^`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CARROT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;`&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BACKTICK&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\(`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LPAREN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\)`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;RPAREN&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;BUS&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CHIP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LABEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;compute&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMPUTE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ignore&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;IGNORE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SET&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[0-9]*\.?[0-9]+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NUMBER&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[a-zA-Z_][a-zA-Z0-9_]*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`&amp;quot;((\\.)|([^&amp;quot;\\]))*&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`#[^\n]*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`( |\t|\f)+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SPACE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\\\n`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SPACE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\n|\r|\n\r`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NEWLINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Skipping a pattern&lt;/h3&gt;
&lt;p&gt;Sometimes it is advantageous to not emit tokens for certain patterns and to
instead skip them. Commonly this occurs for whitespace and comments.  To skip a
pattern simply have the action &lt;code&gt;return nil, nil&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\s+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;// skip whitespace&lt;/span&gt;
&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`#[^\n]*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// skip comments&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In our example for &lt;code&gt;sensors.conf&lt;/code&gt; we only care about the keywords and the &lt;code&gt;NAME&lt;/code&gt;
tokens. Let's skip the rest:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`@`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\^`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;`&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\(`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\)`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bus&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CHIP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LABEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;compute&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ignore&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;set&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[0-9]*\.?[0-9]+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`[a-zA-Z_][a-zA-Z0-9_]*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`&amp;quot;((\\.)|([^&amp;quot;\\]))*&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`#[^\n]*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`( |\t|\f)+`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\\\n`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\n|\r|\n\r`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getToken&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NEWLINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Constructing the lexer exactly once&lt;/h3&gt;
&lt;p&gt;The lexer should be constructed and compiled exactly once: on program startup
(unless the regular expressions are defined dynamically). This ensures that you
only pay the compilation costs at program startup and get the maximum benefit
from the efficient &lt;a href="http://hackthology.com/faster-tokenization-with-a-dfa-backend-for-lexmachine.html"&gt;DFA
representation&lt;/a&gt;
produced by compilation.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;newLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Example tokenization&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip chip1 chip2 label name value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%-7v | %-25q | %v:%v-%v:%v\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;CHIP    | &amp;quot;chip&amp;quot;                    | 1:1-1:4
NAME    | &amp;quot;chip1&amp;quot;                   | 1:6-1:10
NAME    | &amp;quot;chip2&amp;quot;                   | 1:12-1:16
LABEL   | &amp;quot;label&amp;quot;                   | 1:18-1:22
NAME    | &amp;quot;name&amp;quot;                    | 1:24-1:27
NAME    | &amp;quot;value&amp;quot;                   | 1:29-1:33
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For more details on the scanner interface consult the &lt;a href="https://github.com/timtadh/lexmachine#tokenizing-a-string"&gt;narrative
documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Associating &lt;code&gt;label&lt;/code&gt;s with &lt;code&gt;chip&lt;/code&gt;s&lt;/h2&gt;
&lt;p&gt;There are several ways we could approach taking the output of the &lt;code&gt;scanner&lt;/code&gt;
above and using it to find what labels go with what chip names. In this example,
a very simple, short, but ugly method is going to be demonstrated. Inside of the
scanning for-loop a simple state machine will track what the current statement a
particular &lt;code&gt;NAME&lt;/code&gt; token belongs to. If it belongs to a &lt;code&gt;chip&lt;/code&gt; statement or a
&lt;code&gt;label&lt;/code&gt; statement it is appropriately associated. Finally, whenever a new &lt;code&gt;CHIP&lt;/code&gt;
token is encountered the current buffer of labels are associated with the
previous chip statement.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;printChipLabels&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;chipLabels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;][]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;curChips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;curLabels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;addChips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;curChips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chipLabels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;chipLabels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chipLabels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;curLabels&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;curChips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;curLabels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scanner&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tk&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lexmachine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;CHIP&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;addChips&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;LABEL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NAME&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;curChips&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curChips&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;label&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;curLabels&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curLabels&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;curLabel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tokmap&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NEWLINE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;none&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;addChips&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// close the final chip statement&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;chip %v: %v\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;chipLabels&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;chip&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;, &amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt; for the &lt;code&gt;sensors.conf&lt;/code&gt; file on my machine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;chip lm78-*: temp1:M/B Temp
chip lm79-*: temp1:M/B Temp
chip lm80-*: temp1:M/B Temp
chip lm96080-*: temp1:M/B Temp
chip w83792d-*: in0:VcoreA, in1:VcoreB, in6:+5V, in7:5VSB, in8:Vbat
chip w83793-*: in0:VcoreA, in1:VcoreB, in7:+5V, in8:5VSB, in9:Vbat
chip w83795g-*: in12:+3.3V, in13:3VSB, in14:Vbat
chip w83795adg-*: in12:+3.3V, in13:3VSB, in14:Vbat
chip via686a-*: in0:Vcore, in2:+3.3V, in3:+5V, in4:+12V
chip adm1025-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, in5:VCC, temp1:CPU Temp, temp2:M/B Temp
chip ne1619-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, in5:VCC, temp1:CPU Temp, temp2:M/B Temp
chip lm87-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp1:M/B Temp, temp2:CPU Temp
chip adm1024-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp1:M/B Temp, temp2:CPU Temp
chip it87-*: in8:Vbat
chip it8712-*: in8:Vbat
chip it8716-*: in8:Vbat
chip it8718-*: in8:Vbat
chip it8720-*: in8:Vbat
chip fscpos-*: in0:+12V, in1:+5V, in2:Vbat, temp1:CPU Temp, temp2:M/B Temp, temp3:Aux Temp
chip fscher-*: in0:+12V, in1:+5V, in2:Vbat, temp1:CPU Temp, temp2:M/B Temp, temp3:Aux Temp
chip fscscy-*: in0:+12V, in1:+5V, in2:+3.3V, temp1:CPU0 Temp, temp2:CPU1 Temp, temp3:M/B Temp, temp4:Aux Temp
chip fschds-*: temp1:CPU Temp, temp2:Super I/O Temp, temp3:System Temp, an1:PSU Fan, an2:CPU Fan, an3:System FAN2, an4:System FAN3, an5:System FAN4, in0:+12V, in1:+5V, in2:Vbat
chip fscsyl-*: temp1:CPU Temp, temp4:Super I/O Temp, temp5:Northbridge Temp, an1:CPU Fan, an2:System FAN2, an3:System FAN3, an4:System FAN4, an7:PSU Fan, in0:+12V, in1:+5V, in2:Vbat, in3:+3.3V, in5:+3.3V-Aux
chip vt1211-*: in5:+3.3V, temp2:SIO Temp
chip vt8231-*: in5:+3.3V
chip smsc47m192-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, in5:VCC, temp1:SIO Temp
chip lm85-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip lm85b-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip lm85c-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip adm1027-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip adt7463-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip adt7468-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip emc6d100-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip emc6d102-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip emc6d103-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip emc6d103s-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip emc6w201-*: in2:+3.3V, in3:+5V, temp6:M/B Temp
chip pc87365-*: in7:3VSB, in8:VDD, in9:Vbat, in10:AVDD, temp3:SIO Temp
chip pc87366-*: in7:3VSB, in8:VDD, in9:Vbat, in10:AVDD, temp3:SIO Temp
chip adm1030-*: temp1:M/B Temp
chip adm1031-*: temp1:M/B Temp
chip w83627thf-*: in3:+5V, in7:5VSB, in8:Vbat
chip w83627ehf-*: in0:Vcore, in2:AVCC, in3:+3.3V, in7:3VSB, in8:Vbat
chip w83627dhg-*: in0:Vcore, in2:AVCC, in3:+3.3V, in7:3VSB, in8:Vbat
chip w83667hg-*: in0:Vcore, in2:AVCC, in3:+3.3V, in7:3VSB, in8:Vbat
chip nct6775-*: in0:Vcore, in2:AVCC, in3:+3.3V, in7:3VSB, in8:Vbat
chip nct6776-*: in0:Vcore, in2:AVCC, in3:+3.3V, in7:3VSB, in8:Vbat
chip w83627uhg-*: in2:AVCC, in3:+5V, in7:5VSB, in8:Vbat
chip f71805f-*: in0:+3.3V
chip f71872f-*: in0:+3.3V, in9:Vbat, in10:3VSB
chip k8temp-*: temp1:Core0 Temp, temp2:Core0 Temp, temp3:Core1 Temp, temp4:Core1 Temp
chip dme1737-*: in0:5VSB, in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, in5:3VSB, in6:Vbat, temp2:SIO Temp
chip sch311x-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, in5:3VSB, in6:Vbat, temp2:SIO Temp
chip sch5027-*: in0:5VSB, in1:Vcore, in2:+3.3V, in5:3VSB, in6:Vbat, temp2:SIO Temp
chip sch5127-*: in2:+3.3V, in5:3VSB, in6:Vbat
chip f71808e-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71808a-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71862fg-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71869-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71869a-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71882fg-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71889fg-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71889ed-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71889a-*: in0:+3.3V, in7:3VSB, in8:Vbat
chip f71858fg-*: in0:+3.3V, in1:3VSB, in2:Vbat
chip f8000-*: in0:+3.3V, in1:3VSB, in2:Vbat
chip f81865f-*: in0:+3.3V, in5:3VSB, in6:Vbat
chip adt7473-*: in2:+3.3V, temp2:Board Temp
chip adt7475-*: in2:+3.3V, temp2:Board Temp
chip adt7476-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
chip adt7490-*: in1:Vcore, in2:+3.3V, in3:+5V, in4:+12V, temp2:M/B Temp
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;This article presented &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; a
library that helps you break up complex strings into their component parts
safely, reliably, and quickly. To learn more visit the &lt;a href="https://github.com/timtadh/lexmachine"&gt;project
page&lt;/a&gt;,
browse the &lt;a href="https://github.com/timtadh/lexmachine#documentation"&gt;documentation&lt;/a&gt;,
look at another
&lt;a href="http://hackthology.com/writing-a-lexer-in-go-with-lexmachine.html"&gt;tutorial&lt;/a&gt;,
or read an &lt;a href="http://hackthology.com/faster-tokenization-with-a-dfa-backend-for-lexmachine.html"&gt;explainer
article&lt;/a&gt;
on how it all works.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Faster Tokenization with a DFA Backend for Lexmachine</title><link href="https://hackthology.com/faster-tokenization-with-a-dfa-backend-for-lexmachine.html" rel="alternate"/><published>2017-11-27T00:00:00-05:00</published><updated>2017-11-27T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2017-11-27:/faster-tokenization-with-a-dfa-backend-for-lexmachine.html</id><summary type="html">&lt;style&gt;
div.dfa-scroller {
    overflow-x: unset;
}
div.dfa-scroller img {
    margin-left: -25%;
}
@media screen and (max-width: 1100px) {
    div.dfa-scroller {
        overflow-x: scroll;
    }
    div.dfa-scroller img {
        margin-left: unset;
    }
}
div.dfa-scroller {
    overflow-x: unset;
}
div.dfa-scroller img {
    margin-left: -25%;
}
@media screen and (max-width: 1100px) {
    div.dfa-scroller {
        overflow-x: scroll;
    }
    div.dfa-scroller img {
        margin-left: unset;
    }
}
&lt;/style&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;&lt;a href="https://github.com/timtadh/lexmachine"&gt;Lexmachine&lt;/a&gt; is a lexical …&lt;/p&gt;</summary><content type="html">&lt;style&gt;
div.dfa-scroller {
    overflow-x: unset;
}
div.dfa-scroller img {
    margin-left: -25%;
}
@media screen and (max-width: 1100px) {
    div.dfa-scroller {
        overflow-x: scroll;
    }
    div.dfa-scroller img {
        margin-left: unset;
    }
}
div.dfa-scroller {
    overflow-x: unset;
}
div.dfa-scroller img {
    margin-left: -25%;
}
@media screen and (max-width: 1100px) {
    div.dfa-scroller {
        overflow-x: scroll;
    }
    div.dfa-scroller img {
        margin-left: unset;
    }
}
&lt;/style&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;&lt;a href="https://github.com/timtadh/lexmachine"&gt;Lexmachine&lt;/a&gt; is a lexical analysis (or
tokenization) library for Go (golang) and it just got faster thanks to a new
backend I wrote. This article is going to explain the new backend, how it works,
and why it is faster. If you want to use lexmachine checkout the
&lt;a href="https://github.com/timtadh/lexmachine#documentation"&gt;documentation&lt;/a&gt; or the
&lt;a href="https://hackthology.com/writing-a-lexer-in-go-with-lexmachine.html"&gt;tutorial&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Lexical analysis is the process of breaking strings up into substrings, called
&lt;em&gt;lexemes&lt;/em&gt;, and putting them into categories called &lt;em&gt;tokens&lt;/em&gt;. This process is
also called &lt;em&gt;tokenization&lt;/em&gt; and is the first step in parsing complex file
formats, programming languages, network protocols, and other information. Let's
look at a quick example, suppose we wanted to process a custom configuration
file format.  For instance,
&lt;a href="https://linux.die.net/man/5/sensors.conf"&gt;sensors.conf&lt;/a&gt; describes how Linux
should translate the raw readings hardware monitoring chips to real-world values
-- such as voltage and temperature. The first part of my laptop's &lt;code&gt;sensors.conf&lt;/code&gt;
file begins with the following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; It is recommended not to modify this file, but to drop your local
&lt;span class="gh"&gt;#&lt;/span&gt; changes in /etc/sensors.d/. File with names that start with a dot
&lt;span class="gh"&gt;#&lt;/span&gt; are ignored.

chip &amp;quot;lm78-*&amp;quot; &amp;quot;lm79-*&amp;quot; &amp;quot;lm80-*&amp;quot; &amp;quot;lm96080-*&amp;quot;

    label temp1 &amp;quot;M/B Temp&amp;quot;


chip &amp;quot;w83792d-*&amp;quot;

    label in0 &amp;quot;VcoreA&amp;quot;
    label in1 &amp;quot;VcoreB&amp;quot;
    label in6 &amp;quot;+5V&amp;quot;
    label in7 &amp;quot;5VSB&amp;quot;
    label in8 &amp;quot;Vbat&amp;quot;

    set in6_min  5.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in6_max  5.0 *&lt;/span&gt; 1.10
    set in7_min  5.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in7_max  5.0 *&lt;/span&gt; 1.10
    set in8_min  3.0 &lt;span class="gs"&gt;* 0.90&lt;/span&gt;
&lt;span class="gs"&gt;    set in8_max  3.0 *&lt;/span&gt; 1.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;According to the &lt;a href="https://linux.die.net/man/5/sensors.conf"&gt;man page&lt;/a&gt;, there are
several syntactic elements in this file: keywords (&lt;code&gt;chip&lt;/code&gt;, &lt;code&gt;label&lt;/code&gt;, &lt;code&gt;set&lt;/code&gt;, ...),
names (&lt;code&gt;in0&lt;/code&gt;, &lt;code&gt;in6_min&lt;/code&gt;, ..., &lt;code&gt;"lm78-*"&lt;/code&gt;, &lt;code&gt;"VcoreA"&lt;/code&gt;, ...), floats (&lt;code&gt;5.0&lt;/code&gt;,
&lt;code&gt;0.90&lt;/code&gt;, ...), operators (&lt;code&gt;+&lt;/code&gt;, &lt;code&gt;-&lt;/code&gt;, &lt;code&gt;*&lt;/code&gt;, ...), and comments which start with &lt;code&gt;#&lt;/code&gt;.
A lexical analysis would break down the file as follows:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Type    | Lexeme
-------------------
COMMENT | # It is recommended not to modify this file, but to drop your local
COMMENT | # changes in /etc/sensors.d/. File with names that start with a dot
COMMENT | # are ignored.
CHIP    | chip
NAME    | &amp;quot;lm78-*&amp;quot;
NAME    | &amp;quot;lm78-*&amp;quot;
NAME    | &amp;quot;lm79-*&amp;quot;
NAME    | &amp;quot;lm80-*&amp;quot;
NAME    | &amp;quot;lm96080-*&amp;quot;
LABEL   | label
NAME    | temp1
NAME    | &amp;quot;M/B Temp&amp;quot;
CHIP    | chip
NAME    | &amp;quot;w83792d-*&amp;quot;
...
SET     | set
NAME    | in8_max
FLOAT   | 3.0
STAR    | *
FLOAT   | 1.10
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The categories are defined by &lt;em&gt;patterns&lt;/em&gt; which are expressed as &lt;a href="https://github.com/timtadh/lexmachine#regular-expressions"&gt;regular
expressions&lt;/a&gt;.  As a
quick review, regular expressions (regex) are a "pattern" which describe a set
of strings. A regex is made up of characters (&lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt;, &lt;code&gt;@&lt;/code&gt;, ...) which
combine with the operators: concatenation &lt;code&gt;abc&lt;/code&gt;, alternation &lt;code&gt;a|b&lt;/code&gt;, grouping
&lt;code&gt;a(b|c)d&lt;/code&gt;, and repetition &lt;code&gt;a*&lt;/code&gt;. Some examples:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;abc&lt;/code&gt; matches {&lt;code&gt;"abc"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a|b&lt;/code&gt; matches {&lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"b"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a(b|c)d&lt;/code&gt; matches {&lt;code&gt;"abd"&lt;/code&gt;, &lt;code&gt;"acd"&lt;/code&gt;}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a*&lt;/code&gt; matches {&lt;code&gt;""&lt;/code&gt;, &lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"aa"&lt;/code&gt;, ...}&lt;/li&gt;
&lt;li&gt;&lt;code&gt;a(b(c|d))*&lt;/code&gt; matches {&lt;code&gt;"a"&lt;/code&gt;, &lt;code&gt;"abc"&lt;/code&gt;, &lt;code&gt;"abd"&lt;/code&gt;, &lt;code&gt;"abcbc"&lt;/code&gt;, &lt;code&gt;"abcbd"&lt;/code&gt;, ...}&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the running example of the &lt;code&gt;sensors.conf&lt;/code&gt; file one might define the following
patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AT: &lt;code&gt;@&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;PLUS: &lt;code&gt;+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;STAR: &lt;code&gt;*&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;DASH: &lt;code&gt;-&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SLASH: &lt;code&gt;/&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CARROT: &lt;code&gt;^&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;BACKTICK: &lt;code&gt;`&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;LPAREN: &lt;code&gt;(&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;RPAREN: &lt;code&gt;)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;BUS: &lt;code&gt;bus&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;CHIP: &lt;code&gt;chip&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;LABEL: &lt;code&gt;label&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;COMPUTE: &lt;code&gt;compute&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;IGNORE: &lt;code&gt;ignore&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;SET: &lt;code&gt;set&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;NUMBER: &lt;code&gt;[0-9]*\.?[0-9]+&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;NAME: &lt;code&gt;[a-zA-Z_][a-zA-Z0-9_]*|"[^"]*"&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These patterns define how text in the input should categorized according to the
rules for the &lt;code&gt;sensors.conf&lt;/code&gt; file.&lt;/p&gt;
&lt;h1&gt;Efficiently Categorizing Substrings with Automata&lt;/h1&gt;
&lt;p&gt;Now we turn our attention from &lt;em&gt;what&lt;/em&gt; lexical analysis is to &lt;em&gt;how&lt;/em&gt; it works.
Specifically we are going to concern ourselves with the following matters:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;How the lexical analysis problem is different than the one solved by standard
   implementations of regular expression engines (such as the
   &lt;a href="https://golang.org/pkg/regexp/"&gt;regexp&lt;/a&gt; standard library package).&lt;/li&gt;
&lt;li&gt;How to solve the lexical analysis problem with non-deterministic
   finite automatons (NFA).&lt;/li&gt;
&lt;li&gt;How deterministic automatons (DFAs) improve on the solution presented by NFAs&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;The Lexical Analysis Problem&lt;/h2&gt;
&lt;p&gt;The &lt;a href="https://en.wikipedia.org/wiki/Regular_expression"&gt;regular expression&lt;/a&gt;
problem decides whether a &lt;em&gt;pattern&lt;/em&gt; (as specified by a regular expression)
&lt;em&gt;matches&lt;/em&gt; a given &lt;em&gt;string&lt;/em&gt;. If the pattern does describe the string a regular
expression engine will answer: yes it matches. Otherwise, it answers: no it does
not.&lt;/p&gt;
&lt;p&gt;The lexical analysis problem on the other hand seeks to break up (tokenize) a
long piece of text based on an ordered set of regular expressions. It does this
by proceeding from the start of the string and finding the longest &lt;em&gt;prefix&lt;/em&gt; of
the string that matches at least one pattern. It then chooses a matching pattern
with the &lt;em&gt;highest precedence&lt;/em&gt; and outputs the matched text (&lt;em&gt;lexeme&lt;/em&gt;) and the
category the pattern defines (&lt;em&gt;token type&lt;/em&gt;).  Solving the lexical analysis
problem with a standard regular expression engine is possible but not efficient.
With a standard regex engine, the whole piece of text has to be repeatedly
scanned for each token to decide on the longest prefix match and highest
precedence token type to use.&lt;/p&gt;
&lt;p&gt;However, we can use the theory that is used to implement efficient regular
expression engines to implement efficient lexical analysis engines. The
following adjustments must be made:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Prefixes of a string are matched&lt;/li&gt;
&lt;li&gt;Several patterns are matched at once&lt;/li&gt;
&lt;li&gt;The pattern which matches the longest prefix wins&lt;/li&gt;
&lt;li&gt;In case of ties, the pattern with the highest precedence wins&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Finite Automata&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://swtch.com/~rsc/regexp/"&gt;Efficient regular expression engines&lt;/a&gt; are
implemented using the theory of finite automata. Automata or automatons are
theoretical mathematical constructs which specify a machine. Specifically, a
machine that reads a string, character by character, and decides whether it is
in some &lt;em&gt;language&lt;/em&gt; or not (see Figure 1). The language is a type of formal
language called a &lt;em&gt;regular&lt;/em&gt; language or a Type-3 language in the Chomsky Formal
Language Hierarchy.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Finite Automata" src="/images/regex-machine.png"&gt;&lt;/p&gt;
&lt;div style="text-align: center; margin-top: -2em;"&gt;
&lt;strong&gt;Figure 1.&lt;/strong&gt; A Simple Finite State Automaton.&lt;br/&gt;
If the string matches the Accept light lights up, otherwise the error light
lights up.
&lt;/div&gt;

&lt;p&gt; Finite state automatons encode their matching "program" as a set of states
&lt;span class="math"&gt;\(S\)&lt;/span&gt;, an alphabet &lt;span
class="math"&gt;\(\Sigma\)&lt;/span&gt;, and a transition function which maps the current
state and next symbol to the next state &lt;span class="math"&gt;\( T: S \times \Sigma
\rightarrow S \)&lt;/span&gt;. There are several distinguished states: the
&lt;em&gt;starting state&lt;/em&gt;, and one or more &lt;em&gt;accepting states&lt;/em&gt;. At each step
through the input string the machine reads a character and consults the
transition function to determine the next state. If at the end of the string the
state has reached an &lt;em&gt;accepting state&lt;/em&gt; the string is said to match the
automaton.
&lt;/p&gt;

&lt;p&gt;
When the transition function &lt;span class="math"&gt;\(T\)&lt;/span&gt; produces multiple
states for the same input combination the automaton is said to be
&lt;em&gt;non-deterministic&lt;/em&gt;. Figure 2 shows a non-deterministic finite automaton
(NFA) for our running example for &lt;code&gt;sensors.conf&lt;/code&gt;. In the figure,
the &lt;em&gt;starting state&lt;/em&gt; (state 0) may transition on character &lt;code&gt;c&lt;/code&gt;
to states 12, 21, and 40. This may be interpreted as the machine transitioning
to all of these states simultaneously and maintaining multiple threads of
execution. Simulations of NFAs must keep track of each independent thread of
execution.  If an NFA has &lt;span class="math"&gt;\(n\)&lt;/span&gt; states and a string
has &lt;span class="math"&gt;\(m\)&lt;/span&gt; characters it can be matched in &lt;span
class="math"&gt;\(\mathcal{O}(n \cdot m)\)&lt;/span&gt; steps.
&lt;/p&gt;

&lt;p&gt;&lt;img alt="Non-deterministic Finite Automata" src="/images/nfa.png"&gt;&lt;/p&gt;
&lt;div style="text-align: center; margin-top: -2em;"&gt;
&lt;strong&gt;Figure 2.&lt;/strong&gt; A Non-deterministic Finite Automaton for
&lt;code&gt;sensors.conf&lt;/code&gt;.&lt;br/&gt;
States with double circles are accepting states. Each accepting state is labeled
with the category it corresponds to. The starting state is marked.
&lt;/div&gt;

&lt;p&gt;To use an NFA for the lexical analysis problem several adjustments need to be
made.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To match prefixes, keep scanning until no new states are found (that is all
   threads of execution have either reached end of the string or the error
   state).&lt;/li&gt;
&lt;li&gt;Track all accepting states reached during the scanning.&lt;/li&gt;
&lt;li&gt;Return the "most relevant" match on state exhaustion by returning the
   accepting state which matched the longest prefix. Ties are broken by user
   supplied precedence.&lt;/li&gt;
&lt;li&gt;When the user requests the next token, reset the simulation to the starting
   state and rerun starting at the next character after the previously returned
   prefix.&lt;/li&gt;
&lt;li&gt;After all input has been consumed check all of the input was successfully
   matched. Return an error otherwise.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;
As languages get more complex the cost of tokenization goes up when using NFAs
because the cost for matching a regular expression is dependent in the size of
the NFA (&lt;span class="math"&gt;\(\mathcal{O}(n \cdot m)\)&lt;/span&gt; where &lt;span
class="math"&gt;\(n\) is the number of states in the NFA and &lt;span
class="math"&gt;\(m\) is the length of the string). Can we do better?  We can! If
we do not allow the transition function &lt;span class="math"&gt;\(T\)&lt;/span&gt; to
produce more than one state for each input combination the automaton will be
deterministic finite automaton (DFA). If the automaton is deterministic then
simulation is greatly simplified versus a non-deterministic automaton. Recall,
in the case of NFA simulation non-deterministic steps are modeled by having the
machine transition to all possible next states at once and keeping track of
multiple threads of execution.  In a DFA, there will always be one (and only
one) state to transition to -- and therefore only one thread of execution. If
there is only one thread of execution the simulation can be run in &lt;span
class="math"&gt;\(\mathcal{O}(m)\)&lt;/span&gt; steps (where &lt;span
class="math"&gt;\(m\)&lt;/span&gt; is the length of string).
&lt;/p&gt;

&lt;p&gt;
Figure 3 shows the minimal DFA for the NFA given in Figure 2. By coincidence
there is one fewer states in the DFA than in the NFA. In general, this will not
be the case. Indeed, in the worst case if the NFA has &lt;span
class="math"&gt;\(n\)&lt;/span&gt; states the DFA could have as many as &lt;span
class="math"&gt;\(2^{n}\)&lt;/span&gt; states. However, on average the DFA will only have
&lt;span class="math"&gt;\(n^3\)&lt;/span&gt; states. Thus, a DFA makes the classic space
vs. time tradeoff. It uses more space (in the form of a larger transition table
on average) to get faster execution time.
&lt;/p&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;

&lt;div style="text-align: center; margin-top: -2em;"&gt;
&lt;div class=dfa-scroller&gt;
&lt;img alt="Deterministic Finite Automata" src="/images/dfa.png" style="width: 150%;"&gt;
&lt;/div&gt;
&lt;strong&gt;Figure 3.&lt;/strong&gt; A Minimal Deterministic Finite Automaton for
&lt;code&gt;sensors.conf&lt;/code&gt;.&lt;br/&gt;
States with double circles are accepting states. Each accepting state is labeled
with the category it corresponds to. The starting state is marked.
&lt;/div&gt;

&lt;h2&gt;Practical Results&lt;/h2&gt;
&lt;p&gt;Does the new DFA backend outperform the NFA backend when tokenizing many
strings? The answer is yes. As an quick (non-rigorous) example, let's tokenize
my &lt;code&gt;sensors.conf&lt;/code&gt; file 1000 times using both the NFA backend and the DFA backend.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Using the NFA backend&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;github.com/timtadh/lexmachine/examples/sensors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/etc/sensors*.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;/usr/bin/time&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;sensors&lt;span class="w"&gt; &lt;/span&gt;--nfa&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Command&lt;span class="w"&gt; &lt;/span&gt;being&lt;span class="w"&gt; &lt;/span&gt;timed:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sensors --nfa&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;User&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;.0
&lt;span class="w"&gt;        &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00
&lt;span class="w"&gt;        &lt;/span&gt;Percent&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;job&lt;span class="w"&gt; &lt;/span&gt;got:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;102&lt;/span&gt;%
&lt;span class="w"&gt;        &lt;/span&gt;Elapsed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;wall&lt;span class="w"&gt; &lt;/span&gt;clock&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;h:mm:ss&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;m:ss&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;:02.97
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;shared&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;unshared&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;stack&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Maximum&lt;span class="w"&gt; &lt;/span&gt;resident&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6564&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;resident&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Major&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;requiring&lt;span class="w"&gt; &lt;/span&gt;I/O&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;faults:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Minor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;reclaiming&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;frame&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;faults:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1749&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Voluntary&lt;span class="w"&gt; &lt;/span&gt;context&lt;span class="w"&gt; &lt;/span&gt;switches:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1866&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Involuntary&lt;span class="w"&gt; &lt;/span&gt;context&lt;span class="w"&gt; &lt;/span&gt;switches:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;473&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Swaps:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;inputs:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;outputs:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Socket&lt;span class="w"&gt; &lt;/span&gt;messages&lt;span class="w"&gt; &lt;/span&gt;sent:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Socket&lt;span class="w"&gt; &lt;/span&gt;messages&lt;span class="w"&gt; &lt;/span&gt;received:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Signals&lt;span class="w"&gt; &lt;/span&gt;delivered:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Page&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Exit&lt;span class="w"&gt; &lt;/span&gt;status:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Using the DFA backend&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;go&lt;span class="w"&gt; &lt;/span&gt;install&lt;span class="w"&gt; &lt;/span&gt;github.com/timtadh/lexmachine/examples/sensors&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;cat&lt;span class="w"&gt; &lt;/span&gt;/etc/sensors*.conf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;/usr/bin/time&lt;span class="w"&gt; &lt;/span&gt;-v&lt;span class="w"&gt; &lt;/span&gt;sensors&lt;span class="w"&gt; &lt;/span&gt;--dfa&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Command&lt;span class="w"&gt; &lt;/span&gt;being&lt;span class="w"&gt; &lt;/span&gt;timed:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;sensors --dfa&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;User&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;.01
&lt;span class="w"&gt;        &lt;/span&gt;System&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;seconds&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00
&lt;span class="w"&gt;        &lt;/span&gt;Percent&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;job&lt;span class="w"&gt; &lt;/span&gt;got:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;104&lt;/span&gt;%
&lt;span class="w"&gt;        &lt;/span&gt;Elapsed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;wall&lt;span class="w"&gt; &lt;/span&gt;clock&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;time&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;h:mm:ss&lt;span class="w"&gt; &lt;/span&gt;or&lt;span class="w"&gt; &lt;/span&gt;m:ss&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;:01.93
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;shared&lt;span class="w"&gt; &lt;/span&gt;text&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;unshared&lt;span class="w"&gt; &lt;/span&gt;data&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;stack&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;total&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Maximum&lt;span class="w"&gt; &lt;/span&gt;resident&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;7680&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Average&lt;span class="w"&gt; &lt;/span&gt;resident&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;kbytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Major&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;requiring&lt;span class="w"&gt; &lt;/span&gt;I/O&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;faults:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Minor&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;reclaiming&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;frame&lt;span class="o"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;page&lt;span class="w"&gt; &lt;/span&gt;faults:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2172&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Voluntary&lt;span class="w"&gt; &lt;/span&gt;context&lt;span class="w"&gt; &lt;/span&gt;switches:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2231&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Involuntary&lt;span class="w"&gt; &lt;/span&gt;context&lt;span class="w"&gt; &lt;/span&gt;switches:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;359&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Swaps:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;inputs:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;File&lt;span class="w"&gt; &lt;/span&gt;system&lt;span class="w"&gt; &lt;/span&gt;outputs:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Socket&lt;span class="w"&gt; &lt;/span&gt;messages&lt;span class="w"&gt; &lt;/span&gt;sent:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Socket&lt;span class="w"&gt; &lt;/span&gt;messages&lt;span class="w"&gt; &lt;/span&gt;received:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Signals&lt;span class="w"&gt; &lt;/span&gt;delivered:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Page&lt;span class="w"&gt; &lt;/span&gt;size&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;bytes&lt;span class="o"&gt;)&lt;/span&gt;:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4096&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;Exit&lt;span class="w"&gt; &lt;/span&gt;status:&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note as predicted by the theory presented above, the NFA backend used less
memory but took longer to tokenize the file 1000 times. The DFA backend used
more memory (but not a lot more) and tokenized the file faster than the NFA
backend.&lt;/p&gt;
&lt;p&gt;Intrigued? Try out &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; today!&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Frequent Subgraph Analysis and its Software Engineering Applications</title><link href="https://hackthology.com/frequent-subgraph-analysis-and-its-software-engineering-applications.html" rel="alternate"/><published>2017-08-18T00:00:00-04:00</published><updated>2017-08-18T00:00:00-04:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;</name></author><id>tag:hackthology.com,2017-08-18:/frequent-subgraph-analysis-and-its-software-engineering-applications.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;. &lt;em&gt;Frequent Subgraph Analysis and its Software Engineering Applications&lt;/em&gt;.
&lt;a href="http://case.edu/"&gt;Case Western Reserve University&lt;/a&gt;. Doctoral Dissertation. 2017.
&lt;br/&gt;
&lt;a href="https://hackthology.com/pdfs/dissertation.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/frequent-subgraph-analysis-and-its-software-engineering-applications.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Frequent subgraph analysis is a class of techniques and algorithms to find
repeated sub-structures in graphs known as frequent subgraphs or graph
patterns. In the field of Software …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt;. &lt;em&gt;Frequent Subgraph Analysis and its Software Engineering Applications&lt;/em&gt;.
&lt;a href="http://case.edu/"&gt;Case Western Reserve University&lt;/a&gt;. Doctoral Dissertation. 2017.
&lt;br/&gt;
&lt;a href="https://hackthology.com/pdfs/dissertation.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/frequent-subgraph-analysis-and-its-software-engineering-applications.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;Frequent subgraph analysis is a class of techniques and algorithms to find
repeated sub-structures in graphs known as frequent subgraphs or graph
patterns. In the field of Software Engineering, graph pattern discovery can
help detect semantic code duplication, locate the root cause of bugs, infer
program specifications, and even recommend intelligent auto-complete
suggestions.  Outside of Software Engineering, discovering graph patterns has
enabled important applications in personalized medicine, computer aided drug
design, computer vision, and multimedia.&lt;/p&gt;
&lt;p&gt;As promising as much of the previous work in areas such as semantic code
duplication detection has been, finding all of the patterns in graphs of a
large program's code has previously proven intractable.  Part of what makes
discovering all graphs patterns in a graph of a large program difficult is the
very large number of frequent subgraphs contained in graphs of large programs.
Another impediment arises when graphs contain frequent patterns with many
automorphisms and overlapping embeddings. Such patterns are pathologically
difficult to mine and are found in real programs.&lt;/p&gt;
&lt;p&gt;I present a family of algorithms and techniques for frequent subgraph analysis
with two specific aims. One, address pathological structures. Two, enable
important software engineering applications such as code clone detection and
fault localization without analyzing all frequent subgraphs. The first aim is
addressed by novel optimizations making the system faster and more scalable
than previously published work on both program graphs and other difficult to
mine graphs. The second aim is addressed by new algorithms for sampling,
ranking, and grouping frequent patterns.  Experiments and theoretical results
show the tractability of these new techniques.&lt;/p&gt;
&lt;p&gt;The power of frequent subgraph mining in Software Engineering is demonstrated
with studies on duplicate code (code clone) identification and fault
localization.  Identifying code clones from program dependence graphs allows
the identification of potential semantic clones. The proposed sampling
techniques enable tractable dependence clone identification and analysis.
Fault localization identifies potential locations for the root cause of bugs
in programs. Frequent substructures in dynamic program behavior graphs to
identify suspect behaviors which are further isolated with fully automatic
test case minimization and generation.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Frequent subgraph analysis&lt;/em&gt; (FSA) is a family of techniques to discover
recurring subgraphs in graph databases. The databases can either be composed of
many individual graphs or a single large connected graph. This dissertation
discusses my contributions to frequent subgraph analysis and applies the
technique to address two pressing problems in software engineering: code clone
detection and automatic fault localization.&lt;/p&gt;
&lt;p&gt;The work on frequent subgraph analysis was motivated by the software engineering
problems. Large programs are composed of repeated patterns arising organically
through the process of program construction. Some regions of programs are
duplicated (intentionally or unintentionally). The duplicated regions are
referred to as &lt;em&gt;code clones&lt;/em&gt; (or just &lt;em&gt;clones&lt;/em&gt;). Other regions are
similar to each other because they perform similar tasks or share development
histories.&lt;/p&gt;
&lt;p&gt;Code clones may arise from programmers copying and pasting code, from
limitations of a programming language, from using certain APIs, from following
coding conventions, or from a variety of other causes.  Whatever their causes,
the existing clones in a code base need to be managed. When a programmer
modifies a region of code that is cloned in another location in the program
they should make an active decision whether or not to modify the other location.
Clearly, such decisions can only be made if the programmer is aware of the other
location.&lt;/p&gt;
&lt;p&gt;One type of duplication which is particularly difficult to detect is so called
&lt;em&gt;Type-4 clones&lt;/em&gt; or &lt;em&gt;semantic clones&lt;/em&gt;. Semantic clones are semantically
equivalent regions of code which may or may not be textually similar.
Differences could be small changes such as different variable names or large
changes such as a different algorithms which perform the same function. In
general identifying semantically equivalent regions is undecidable as a
reduction from the halting problem.&lt;/p&gt;
&lt;p&gt;Frequent subgraph analysis (FSA) can be used to identify some &lt;em&gt;Type-4&lt;/em&gt; clones
(as well as easier to identify clone classes). I use FSA to analyze a graphical
representation of the program called the &lt;em&gt;Program Dependence Graph&lt;/em&gt; (PDG)
{&lt;a href="https://doi.org/10.1145/24039.24041"&gt;Ferrante 1987&lt;/a&gt;}. Dependence graphs strip
away syntactic information and focus on the semantic relationships between
operations.  Non-semantic re-orderings of operations in a program do not effect
the structure of its dependence graph {&lt;a href="https://doi.org/10.1145/93548.93574"&gt;Horwitz
1990&lt;/a&gt;, &lt;a href="https://doi.org/10.1145/75309.75328"&gt;Podgurski
1989&lt;/a&gt;, &lt;a href="https://doi.org/10.1109/32.58784"&gt;Podgurski
1990&lt;/a&gt;}. Since PDGs are not sensitive to
unimportant syntactic changes some of the &lt;em&gt;Type-4&lt;/em&gt; clones in a program may
be identified with FSA.&lt;/p&gt;
&lt;p&gt;The other motivating application I applied FSA to is automatic fault
localization.  When programs have faults, defects, or bugs it is often time
consuming and sometimes difficult to find the cause of the bug. To address this
the software engineering community has been working on a variety of techniques
for &lt;em&gt;automatic fault localization&lt;/em&gt;.  The family of statistical fault
localization techniques analyzes the behavior of the program when the faults
manifest and when they do not. These techniques then identify statistical
associations between execution of particular program elements and the occurrence
of program failures.&lt;/p&gt;
&lt;p&gt;While statistical measures can identify suspicious elements of a program they
are blind to the relationships between the elements. If program behavior is
modeled through &lt;em&gt;Dynamic Control Flow Graphs&lt;/em&gt;, then execution relationships
between operations can be analyzed using FSA to identify suspicious
interactions. These suspicious interactions represent larger &lt;em&gt;behaviors&lt;/em&gt; of
the program which are statistically associated with program failure. The
behaviors serve as a context of interacting suspicious program elements which
potentially makes it easier for programmers to comprehend localization results.&lt;/p&gt;
&lt;p&gt;Much of the previous work in frequent subgraph analysis has focused on finding
all of the frequent subgraphs in a graph database (called &lt;em&gt;frequent subgraph
mining&lt;/em&gt; {&lt;a href="https://dx.doi.org/10.1007/3-540-45372-5_2"&gt;Inokuchi 2000&lt;/a&gt;}). I
have shown that finding all of the frequent subgraphs in a database of graphs is
not an efficient or effective way to either detect code clones or automatically
localize faults. Program dependence graphs of large programs have huge numbers
of recurring subgraphs.  Experiments on a number of open source projects (see
Chapter 4) showed that moderately sized Java programs (~70 KLOC) have more than
a hundred of million subgraphs that recur five or more times. Mining all
recurring subgraphs is an impractical way to either identify code clones or
localize faults.&lt;/p&gt;
&lt;p&gt;Furthermore, it turns out that program dependence graphs are particularly
difficult to analyze for recurring subgraphs. These graphs often have certain
structures which contain many &lt;em&gt;automorphisms&lt;/em&gt;. A structure with an automorphism
can be rotated upon itself. Each rotation appears to be a recurrence to
traditional frequent subgraph mining algorithms. However, because it is merely a
rotation, humans (e.g. programmers) do not perceive these rotations as instances
of duplication.&lt;/p&gt;
&lt;p&gt;To enable scalable frequent subgraph analysis of large programs new techniques
were needed. I developed novel optimizations for mining frequent subgraphs and
created a state of the art miner (REGRAX) for connected graphs (Chapter 3).  To
detect code clones from program dependence graphs, I developed an algorithm
(GRAPLE) to collect a representative sample of recurring subgraphs (Chapter 4).
Finally, a new algorithm (SWRW) was created for localizing faults from dynamic
control flow graphs, which outperforms previous algorithms (Chapter 6).&lt;/p&gt;
&lt;p&gt;REGRAX contains low level optimizations to the process of identifying frequent
subgraphs. Chapter 2 provides the necessary background on frequent subgraph
mining for understanding these optimizations. An extensive empirical study was
conducted on REGRAX to quantify the effect of each of the new optimizations on
databases from the SUBDUE corpus {&lt;a href="https://dl.acm.org/citation.cfm?id=1618595.1618605"&gt;Cook
1994&lt;/a&gt;}, on program
dependence graphs, and on random graphs.&lt;/p&gt;
&lt;p&gt;GRAPLE is a new algorithm to sample a representative set of frequent subgraphs
and estimate statistics characterizing properties of the set of all frequent
subgraphs. The sampling algorithm uses the theory of absorbing Markov chains to
model the process of extracting recurring subgraphs from a large connected
graph. By sampling a representative set of recurring subgraphs GRAPLE is able to
conduct frequent subgraph analysis on large programs which normally would not be
amenable to such analysis.&lt;/p&gt;
&lt;p&gt;One of the questions in code clone detection is: "are code clones detected from
program dependence graphs understandable to programmers?" GRAPLE was used to
answer this question, as it not only collects a sample of frequent subgraphs but
allows researchers to estimate the prevalence of features across the entire
population of frequent subgraphs (including those which were not sampled).
Chapter 4 details a case study which was conducted at a software company to
determine whether their programmers could make use of code clones detected from
program dependence graphs. The study would not have been possible without the
estimation framework in GRAPLE, as the software contained too many code clones
to be reviewed in the allocated budget.&lt;/p&gt;
&lt;p&gt;To apply frequent subgraph analysis to automatic fault localization, a new
algorithm named Score Weighted Random Walks (SWRW) was developed. SWRW samples
discriminative, suspicious, or significant subgraphs from a database of graphs.
The database is split into multiple classes where some graphs are labeled
"positive" and others "negative." In fault localization the "positive" graphs
were those dynamic control flow graphs collected from program executions which
exhibited a failure of some type. The "negative" graphs are from executions
which did not fail.&lt;/p&gt;
&lt;p&gt;SWRW, like GRAPLE, models the problem using the theory of absorbing Markov
chains. Unlike GRAPLE, it uses an &lt;em&gt;objective function&lt;/em&gt; (drawn from the
statistical fault localization literature {&lt;a href="https://dx.doi.org/10.1002/smr.1616"&gt;Lucia
2014&lt;/a&gt;}) to guide the sampling process. In
comparison to previous work in fault localization using graph mining, a much
wider variety of objective functions can applied. This allows for functions
better suited to statistical fault localization to be used as the objective
function. SWRW outperforms previous approaches which used discriminative mining
to localize faults in terms of fault localization accuracy.&lt;/p&gt;
&lt;h4&gt;Summary&lt;/h4&gt;
&lt;p&gt;This dissertation makes important and novel contributions to frequent subgraph
analysis which enable scalable semantic code clone detection and behavioral
fault localization. These advances can help programmers maintain their software
more efficiently leading to more stable and secure software for everyone. The
software engineering advances are built on new frequent subgraph analysis
algorithms. The new algorithms improve code clone detection time, fault
localization latency and accuracy, and enable analysis of larger and more
complex programs.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://hackthology.com/pdfs/dissertation.pdf"&gt;Read the full dissertation&lt;/a&gt;.&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>Rethinking Dependence Clones</title><link href="https://hackthology.com/rethinking-dependence-clones.html" rel="alternate"/><published>2017-02-21T00:00:00-05:00</published><updated>2017-02-21T00:00:00-05:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt; and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2017-02-21:/rethinking-dependence-clones.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski.
&lt;em&gt;Rethinking Dependence Clones&lt;/em&gt;.
&lt;a href="https://iwsc2017.github.io/"&gt;IWSC 2017&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/IWSC.2017.7880512"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/iwsc-2017.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/rethinking-dependence-clones.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Semantic code clones&lt;/em&gt; are regions of duplicated code that may appear dissimilar
but compute similar functions. Since in general it is algorithmically
undecidable whether two or more programs compute the same function, locating all …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski.
&lt;em&gt;Rethinking Dependence Clones&lt;/em&gt;.
&lt;a href="https://iwsc2017.github.io/"&gt;IWSC 2017&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://doi.org/10.1109/IWSC.2017.7880512"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/iwsc-2017.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/rethinking-dependence-clones.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;Semantic code clones&lt;/em&gt; are regions of duplicated code that may appear dissimilar
but compute similar functions. Since in general it is algorithmically
undecidable whether two or more programs compute the same function, locating all
semantic code clones is infeasible. One way to dodge the undecidability issue
and find potential semantic clones, using only static information, is to search
for recurring subgraphs of a &lt;em&gt;program dependence graph&lt;/em&gt; (PDG).  PDGs represent
control and data dependence relationships between statements or operations in a
program.  PDG-based clone detection techniques, unlike syntactically-based
techniques, do not distinguish between code fragments that differ only because
of dependence-preserving statement re-orderings, which also preserve semantics.
Consequently, they detect clones that are difficult to find by other means.
Despite this very desirable property, work on PDG-based clone detection has
largely stalled, apparently because of concerns about the scalability of the
approach.  We argue, however, that the time has come to reconsider PDG-based
clone detection, as a part of a holistic strategy for clone management.  We
present evidence that its scalability problems are not as severe as previously
thought.  This suggests the possibility of developing integrated clone
management systems that fuse information from multiple clone detection methods,
including PDG-based ones.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Fragments of similar code are typically scattered throughout large code bases.
These repeated fragments or &lt;em&gt;code clones&lt;/em&gt; often result from programmers copying
and pasting code.  Code clones (or just &lt;em&gt;clones&lt;/em&gt;) may also result from
limitations of a programming language, use of certain APIs or design patterns,
following coding conventions, or a variety of other causes.  Whatever their
causes, existing clones need to be managed. When a programmer modifies a region
of code that is cloned in another location in the program, they should make an
active decision whether or not to modify the other location.  Clearly, such
decisions can only be made if the programmer is aware of the other location.&lt;/p&gt;
&lt;p&gt;In general, there are 4 types of code clones:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Type-1 Clones -&lt;/strong&gt; Identical regions of code (excepting whitespace and
  comments).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type-2 Clones -&lt;/strong&gt; Syntactically equivalent regions (excepting names,
  literals, types, and comments).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type-3 Clones -&lt;/strong&gt; Syntactically similar regions (as in Type-2) but with
  minor differences such as statement additions or deletions.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type-4 Clones -&lt;/strong&gt; Regions of code with functionally equivalent behavior but
  possibly with different syntactic structures.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Much of the research on code clone detection and maintenance has been geared
toward Type-1 and Type-2 clone, as they are easier to detect and validate than
Type-3 and Type-4 clones.  The two most popular detection methods involve
searching for clones in &lt;em&gt;token streams&lt;/em&gt; and &lt;em&gt;abstract syntax trees&lt;/em&gt; (ASTs).&lt;/p&gt;
&lt;p&gt;An alternative approach to clone detection is to search for them in a &lt;em&gt;Program
Dependence Graph&lt;/em&gt; (PDG), which represents the control and data dependences
between statements or operations in a program.  Recurring subgraphs in PDGs
represent potential &lt;em&gt;dependence clones&lt;/em&gt;.  Some of the previous work on PDG-based
clone detection used forward and backward path-slicing to find clones.  This
method can detect matching slices, but it cannot detect all recurring subgraphs.
The latter can be identified using &lt;em&gt;frequent subgraph mining&lt;/em&gt; (FSM).  However,
for low frequency thresholds, the number of PDG subgraphs discovered by FSM may
be enormous.  For example, we found that for a Java program with 70,000 lines of
code (LOC), over 700 million PDG subgraphs with 5 or more instances were
discovered by FSM.&lt;/p&gt;
&lt;p&gt;Since it is infeasible for developers to examine so many subgraphs, we
previously developed &lt;a href="https://hackthology.com/sampling-code-clones-from-program-dependence-graphs-with-graple.html"&gt;GRAPLE&lt;/a&gt;, an algorithm to
select representative samples of maximal frequent subgraphs.  In this paper, the
core sampling process remains the same as in GRAPLE but we present a new
algorithm for traversing the &lt;em&gt;k&lt;/em&gt;-frequent subgraph lattice.  One tricky aspect
of FSM is how to define exactly what "frequency" means in a large connected
graph. In order to handle pathological cases that occur in real programs, we
introduce a new metric to measure subgraph frequency (or "support"), called
the &lt;em&gt;Greedy Independent Subgraphs&lt;/em&gt; (GIS) measure.  The results section details
the first empirical examination of the scalability and speed of sampling
dependence clones from large programs. The study showed that our new system can
quickly sample from programs with 500 KLOC of code and successfully sample from
programs with perhaps 2 MLOC. Finally, since at times the sampling algorithm may
return several potential clones, which are quite similar to each other, we
evaluate the performance of a density-based clustering algorithm on the samples
collected.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;See the &lt;a href="https://hackthology.com/pdfs/iwsc-2017.pdf"&gt;PDF&lt;/a&gt; for the complete paper. IEEE has
the exclusive rights to publish this paper. Follow the
&lt;a href="https://doi.org/10.1109/IWSC.2017.7880512"&gt;DOI&lt;/a&gt; for the IEEE copy.&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>A Job Queue in BASH</title><link href="https://hackthology.com/a-job-queue-in-bash.html" rel="alternate"/><published>2017-02-11T00:00:00-05:00</published><updated>2017-02-11T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2017-02-11:/a-job-queue-in-bash.html</id><summary type="html">&lt;p&gt;A Job Queue is typically a first in first out queue of "work items" or "jobs" to
be processed. Ideally, a good job queue should support multiple workers (also
called readers) so multiple jobs can be processed at one time. For production
systems and clusters there are many robust options …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A Job Queue is typically a first in first out queue of "work items" or "jobs" to
be processed. Ideally, a good job queue should support multiple workers (also
called readers) so multiple jobs can be processed at one time. For production
systems and clusters there are many robust options availble. Sometimes you need
a job queue for a local system but cannot install (or do not want to install)
one of the many networked job queues. But, if you are running Linux you probably
have GNU BASH installed which can be used to create a relatively simple and
robust job queue.&lt;/p&gt;
&lt;p&gt;Below is an example BASH Job Queue made with &lt;code&gt;fifo&lt;/code&gt;s and &lt;code&gt;flock&lt;/code&gt;s. A &lt;code&gt;fifo&lt;/code&gt; is a
first in first out UNIX pipe (&lt;a href="https://linux.die.net/man/4/fifo"&gt;see &lt;code&gt;man
fifo&lt;/code&gt;&lt;/a&gt;). A &lt;code&gt;flock&lt;/code&gt; (&lt;a href="https://linux.die.net/man/1/flock"&gt;see &lt;code&gt;man
flock&lt;/code&gt;&lt;/a&gt;) is a "file lock" which lets the
queue support multiple readers.  This queue may or may not work for other shells
as it relies on the BASH &lt;a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html"&gt;built in
&lt;code&gt;read&lt;/code&gt;&lt;/a&gt;. You
will need to consult the man pages for your shell to determine if this will work
for you.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c1"&gt;## this is the &amp;quot;job&amp;quot; function which is does whatever work&lt;/span&gt;
&lt;span class="c1"&gt;## the queue workers are supposed to be doing&lt;/span&gt;
job&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;work&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;## run the work ....&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# make the files&lt;/span&gt;
&lt;span class="nv"&gt;START&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;start-XXXX&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;FIFO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;fifo-XXXX&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;FIFO_LOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;lock-XXXX&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="nv"&gt;START_LOCK&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;mktemp&lt;span class="w"&gt; &lt;/span&gt;-t&lt;span class="w"&gt; &lt;/span&gt;lock-XXXX&lt;span class="k"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;## mktemp makes a regular file. Delete that an make a fifo.&lt;/span&gt;
rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;
mkfifo&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;

&lt;span class="c1"&gt;## create a trap to cleanup on exit if we fail in the middle.&lt;/span&gt;
cleanup&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$START&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$FIFO_LOCK&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$START_LOCK&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cleanup&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;

&lt;span class="c1"&gt;## This is the worker to read from the queue.&lt;/span&gt;
work&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;## first open the fifo and locks for reading.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&amp;lt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&amp;lt;&lt;span class="nv"&gt;$FIFO_LOCK&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&amp;lt;&lt;span class="nv"&gt;$START_LOCK&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;## signal the worker has started.&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="c1"&gt;# obtain the start lock&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$START&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# put my worker ID in the start file&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="c1"&gt;# release the start lock&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;-&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;# close the start lock file&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;worker&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;started

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;true&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;## try to read the queue&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;# obtain the fifo lock&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-su&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;work_id&lt;span class="w"&gt; &lt;/span&gt;work_item&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# read into work_id and work_item&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nv"&gt;read_status&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;&lt;span class="w"&gt;               &lt;/span&gt;&lt;span class="c1"&gt;# save the exit status of read&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt;                   &lt;/span&gt;&lt;span class="c1"&gt;# release the fifo lock&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;## check the line read.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$read_status&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-eq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;## If read gives an exit code of 0 the read succeeded.&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# got a work item. do the work&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;got&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;work_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$work_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;work_item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$work_item&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;## Run the job in a subshell. That way any exit calls do not kill&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;## the worker process.&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;job&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$work_id&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$work_item&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;## Any other exit code indicates an EOF.&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# clean up the fd(s)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;-
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;-
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$ID&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;done working&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;## Start the workers.&lt;/span&gt;
&lt;span class="nv"&gt;WORKERS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;i&amp;lt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$WORKERS&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;i++&lt;span class="o"&gt;))&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;will&lt;span class="w"&gt; &lt;/span&gt;start&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;work&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;

&lt;span class="c1"&gt;## Open the fifo for writing.&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&amp;gt;&lt;span class="nv"&gt;$FIFO&lt;/span&gt;
&lt;span class="c1"&gt;## Open the start lock for reading&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&amp;lt;&lt;span class="nv"&gt;$START_LOCK&lt;/span&gt;

&lt;span class="c1"&gt;## Wait for the workers to start&lt;/span&gt;
&lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;true&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;started&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;wc&lt;span class="w"&gt; &lt;/span&gt;-l&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$START&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;cut&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\ &lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;flock&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$started&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-eq&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WORKERS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;waiting,&lt;span class="w"&gt; &lt;/span&gt;started&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$started&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;of&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$WORKERS&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;-

&lt;span class="c1"&gt;## utility function to send the jobs to the workers&lt;/span&gt;
send&lt;span class="o"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;work_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$1&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;work_item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$2&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sending&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$work_id&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$work_item&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$work_id&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$work_item&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;## the fifo is fd 3&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;## Produce the jobs to run.&lt;/span&gt;
&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;item&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;{&lt;/span&gt;dataset-A,dataset-B,dataset-C,dataset-D&lt;span class="o"&gt;}&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;send&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$data&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;&lt;span class="nv"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="k"&gt;))&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="c1"&gt;## close the filo&lt;/span&gt;
&lt;span class="nb"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&amp;lt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;-
&lt;span class="c1"&gt;## disable the cleanup trap&lt;/span&gt;
&lt;span class="nb"&gt;trap&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="c1"&gt;## It is safe to delete the files because the workers&lt;/span&gt;
&lt;span class="c1"&gt;## already opened them. Thus, only the names are going away&lt;/span&gt;
&lt;span class="c1"&gt;## the actual files will stay there until the workers&lt;/span&gt;
&lt;span class="c1"&gt;## all finish.&lt;/span&gt;
cleanup
&lt;span class="c1"&gt;## now wait for all the workers.&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;References&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://wiki.osdev.org/Unix_Pipes"&gt;http://wiki.osdev.org/Unix_Pipes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://beej.us/guide/bgipc/output/html/multipage/fifos.html"&gt;https://beej.us/guide/bgipc/output/html/multipage/fifos.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html"&gt;http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_08_02.html&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://linux.die.net/man/1/flock"&gt;https://linux.die.net/man/1/flock&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="Blog"/></entry><entry><title>`xrandr` Script to Setup External Monitor</title><link href="https://hackthology.com/xrandr-script-to-setup-external-monitor.html" rel="alternate"/><published>2017-02-08T00:00:00-05:00</published><updated>2017-02-08T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2017-02-08:/xrandr-script-to-setup-external-monitor.html</id><summary type="html">&lt;p&gt;I have a quirky adapter for my external monitor. The adapter doesn't correctly
report the display's size or refresh rate to the laptop. To solve this problem,
I wrote the following script to automatically setup the external monitor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c1"&gt;## size and refresh rate of the screen&lt;/span&gt;
&lt;span class="nv"&gt;X …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;I have a quirky adapter for my external monitor. The adapter doesn't correctly
report the display's size or refresh rate to the laptop. To solve this problem,
I wrote the following script to automatically setup the external monitor:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="c1"&gt;## size and refresh rate of the screen&lt;/span&gt;
&lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1920&lt;/span&gt;
&lt;span class="nv"&gt;Y&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1200&lt;/span&gt;
&lt;span class="nv"&gt;R&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;

&lt;span class="c1"&gt;## mode string&lt;/span&gt;
&lt;span class="nv"&gt;MODE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$X&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;x&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$Y&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;_&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$R&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;.00

&lt;span class="c1"&gt;## turn the output off in case it is on&lt;/span&gt;
xrandr&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;DP1&lt;span class="w"&gt; &lt;/span&gt;--off

&lt;span class="c1"&gt;## delete the mode from the output in case it exists&lt;/span&gt;
xrandr&lt;span class="w"&gt; &lt;/span&gt;--delmode&lt;span class="w"&gt; &lt;/span&gt;DP1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="c1"&gt;## delete the mode&lt;/span&gt;
xrandr&lt;span class="w"&gt; &lt;/span&gt;--rmmode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="c1"&gt;## create the mode, you need to compute the actual mode line using the `gtf`&lt;/span&gt;
&lt;span class="c1"&gt;## program which computes VESA GTF mode lines from size and refresh rates&lt;/span&gt;
gtf&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$X&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$Y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$R&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;grep&lt;span class="w"&gt; &lt;/span&gt;Modeline&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;sed&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;s/ *Modeline *//&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;xargs&lt;span class="w"&gt; &lt;/span&gt;xrandr&lt;span class="w"&gt; &lt;/span&gt;--newmode

&lt;span class="c1"&gt;## add your newly created mode to the output&lt;/span&gt;
xrandr&lt;span class="w"&gt; &lt;/span&gt;--addmode&lt;span class="w"&gt; &lt;/span&gt;DP1&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;

&lt;span class="c1"&gt;## turn on the output with the new mode. Place it to the right of the laptop&lt;/span&gt;
&lt;span class="c1"&gt;## display but displaced -600 pixels above the laptop display&lt;/span&gt;
xrandr&lt;span class="w"&gt; &lt;/span&gt;--output&lt;span class="w"&gt; &lt;/span&gt;DP1&lt;span class="w"&gt; &lt;/span&gt;--mode&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$MODE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;--pos&lt;span class="w"&gt; &lt;/span&gt;1920x-600
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This script also has the advantage that I never have to run the GUI tool to
change the position of the monitor in relationship to my laptop's monitor.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Frequent Subgraph Mining of Personalized Signaling Pathway Networks Groups Patients with Frequently Dysregulated Disease Pathways and Predicts Prognosis</title><link href="https://hackthology.com/frequent-subgraph-mining-of-personalized-signaling-pathway-networks-groups-patients-with-frequently-dysregulated-disease-pathways-and-predicts-prognosis.html" rel="alternate"/><published>2017-01-03T00:00:00-05:00</published><updated>2017-01-03T00:00:00-05:00</updated><author><name>Arda Durmaz, &lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt;, Doug Brubaker, and &lt;a href="http://gurkan.case.edu"&gt;Gurkan Bebek&lt;/a&gt;</name></author><id>tag:hackthology.com,2017-01-03:/frequent-subgraph-mining-of-personalized-signaling-pathway-networks-groups-patients-with-frequently-dysregulated-disease-pathways-and-predicts-prognosis.html</id><summary type="html">&lt;p&gt;A. Durmaz*, &lt;strong&gt;T. A. D. Henderson&lt;/strong&gt;*, D.  Brubaker, and G. Bebek. &lt;em&gt;Frequent
Subgraph Mining of Personalized Signaling Pathway Networks Groups Patients with
Frequently Dysregulated Disease Pathways and Predicts Prognosis.&lt;/em&gt;
&lt;a href="http://psb.stanford.edu/"&gt;PSB 2017&lt;/a&gt;.  * &lt;strong&gt;Co-First Author&lt;/strong&gt;
&lt;br/&gt;
&lt;a href="http://dx.doi.org/10.1142/9789813207813_0038"&gt;DOI&lt;/a&gt;.
&lt;a href="https://www.ncbi.nlm.nih.gov/pubmed/27896993"&gt;PUBMED&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/psb-2017.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/psb-2017-supplemental.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://hackthology.com/frequent-subgraph-mining-of-personalized-signaling-pathway-networks-groups-patients-with-frequently-dysregulated-disease-pathways-and-predicts-prognosis.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Abstract&lt;/h3&gt;
&lt;h4&gt;Motivation&lt;/h4&gt;
&lt;p&gt;Large scale genomics studies have generated comprehensive molecular
characterization of …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A. Durmaz*, &lt;strong&gt;T. A. D. Henderson&lt;/strong&gt;*, D.  Brubaker, and G. Bebek. &lt;em&gt;Frequent
Subgraph Mining of Personalized Signaling Pathway Networks Groups Patients with
Frequently Dysregulated Disease Pathways and Predicts Prognosis.&lt;/em&gt;
&lt;a href="http://psb.stanford.edu/"&gt;PSB 2017&lt;/a&gt;.  * &lt;strong&gt;Co-First Author&lt;/strong&gt;
&lt;br/&gt;
&lt;a href="http://dx.doi.org/10.1142/9789813207813_0038"&gt;DOI&lt;/a&gt;.
&lt;a href="https://www.ncbi.nlm.nih.gov/pubmed/27896993"&gt;PUBMED&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/psb-2017.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/psb-2017-supplemental.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://hackthology.com/frequent-subgraph-mining-of-personalized-signaling-pathway-networks-groups-patients-with-frequently-dysregulated-disease-pathways-and-predicts-prognosis.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Abstract&lt;/h3&gt;
&lt;h4&gt;Motivation&lt;/h4&gt;
&lt;p&gt;Large scale genomics studies have generated comprehensive molecular
characterization of numerous cancer types. Subtypes for many tumor types have
been established; however, these classifications are based on molecular
characteristics of a small gene sets with limited power to detect dysregulation
at the patient level.  We hypothesize that frequent graph mining of pathways to
gather pathways functionally relevant to tumors can characterize tumor types and
provide opportunities for personalized therapies.&lt;/p&gt;
&lt;h4&gt;Results&lt;/h4&gt;
&lt;p&gt;In this study we present an integrative omics approach to group patients based
on their altered pathway characteristics and show prognostic differences within
breast cancer (p &amp;lt; 9.57e-10) and glioblastoma multiforme (p &amp;lt; 0.05) patients. We
were able validate this approach in secondary RNA-Seq datasets with p &amp;lt; 0.05 and
p &amp;lt; 0.01 respectively. We also performed pathway enrichment analysis to further
investigate the biological relevance of dysregulated pathways. We compared our
approach with network-based classifier algorithms and showed that our
unsupervised approach generates more robust and biologically relevant clustering
whereas previous approaches failed to report specific functions for similar
patient groups or classify patients into prognostic groups.&lt;/p&gt;
&lt;h4&gt;Conclusions&lt;/h4&gt;
&lt;p&gt;These results could serve as a means to improve
prognosis for future cancer patients, and to provide opportunities for
improved treatment options and personalized interventions.  The proposed novel 
graph mining approach is able to integrate PPI networks 
with gene expression in a biologically sound approach and cluster patients in to
clinically distinct groups. We have utilized breast cancer and glioblastoma
multiforme datasets from microarray and RNA-Seq platforms and identified
disease mechanisms differentiating samples.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;See the &lt;a href="https://hackthology.com/pdfs/psb-2017.pdf"&gt;PDF&lt;/a&gt; for the complete paper. Follow the
&lt;a href="http://dx.doi.org/10.1142/9789813207813_0038"&gt;DOI&lt;/a&gt; for the authoritative
version.&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>Sampling Code Clones from Program Dependence Graphs with GRAPLE</title><link href="https://hackthology.com/sampling-code-clones-from-program-dependence-graphs-with-graple.html" rel="alternate"/><published>2016-11-13T00:00:00-05:00</published><updated>2016-11-13T00:00:00-05:00</updated><author><name>&lt;a href="http://hackthology.com"&gt;Tim Henderson&lt;/a&gt; and &lt;a href="http://engineering.case.edu/profiles/hap"&gt;Andy Podgurski&lt;/a&gt;</name></author><id>tag:hackthology.com,2016-11-13:/sampling-code-clones-from-program-dependence-graphs-with-graple.html</id><summary type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski. &lt;em&gt;Sampling Code Clones from Program
Dependence Graphs with GRAPLE&lt;/em&gt;.
&lt;a href="http://softwareanalytics.ca/swan16/Home.html"&gt;SWAN 2016&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://dx.doi.org/10.1145/2989238.2989241"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/swan-2016.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/swan-2016-supplemental.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://github.com/timtadh/graple"&gt;CODE&lt;/a&gt;.
&lt;a href="https://hackthology.com/sampling-code-clones-from-program-dependence-graphs-with-graple.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;We present &lt;a href="https://github.com/timtadh/graple"&gt;GRAPLE&lt;/a&gt;, a method to generate a
representative sample of recurring (frequent) subgraphs of any directed labeled
graph(s).  &lt;code&gt;GRAPLE&lt;/code&gt; is based on frequent subgraph …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Tim A. D. Henderson&lt;/strong&gt; and Andy Podgurski. &lt;em&gt;Sampling Code Clones from Program
Dependence Graphs with GRAPLE&lt;/em&gt;.
&lt;a href="http://softwareanalytics.ca/swan16/Home.html"&gt;SWAN 2016&lt;/a&gt;.
&lt;br/&gt;
&lt;a href="https://dx.doi.org/10.1145/2989238.2989241"&gt;DOI&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/swan-2016.pdf"&gt;PDF&lt;/a&gt;.
&lt;a href="https://hackthology.com/pdfs/swan-2016-supplemental.pdf"&gt;SUPPLEMENT&lt;/a&gt;.
&lt;a href="https://github.com/timtadh/graple"&gt;CODE&lt;/a&gt;.
&lt;a href="https://hackthology.com/sampling-code-clones-from-program-dependence-graphs-with-graple.html"&gt;WEB&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Abstract&lt;/h4&gt;
&lt;p&gt;We present &lt;a href="https://github.com/timtadh/graple"&gt;GRAPLE&lt;/a&gt;, a method to generate a
representative sample of recurring (frequent) subgraphs of any directed labeled
graph(s).  &lt;code&gt;GRAPLE&lt;/code&gt; is based on frequent subgraph mining, absorbing Markov
chains, and Horvitz-Thompson estimation. It can be used to sample any kind of
graph representation for programs. One of many software engineering applications
for finding recurring subgraphs is detecting duplicated code (code clones) from
representations such as program dependence graphs (PDGs) and abstract syntax
trees.  To assess the usefulness of clones detected from PDGs, we conducted a
case study on a 73 KLOC commercial Android application developed over 5 years.
Nine of the application's developers participated. To our knowledge, it is the
first study to have professional developers examine code clones detected from
PDGs.  We describe a new PDG generation tool
&lt;a href="https://github.com/timtadh/jpdg"&gt;jpdg&lt;/a&gt; for JVM languages, which was used to
generate the dependence graphs used in the study.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;Code clones&lt;/em&gt; are similar fragments of program code. They can arise from copying
and pasting, using certain design patterns or certain APIs, or adhering to
coding conventions, among other causes. Code clones create maintenance hazards,
because they often require subtle context-dependent adaptation and because other
changes must be applied to each member of a clone class. To manage clone
evolution the clones must first be found. Clones can be detected using any
program representation: source code text, tokens, abstract syntax trees (ASTs),
flow graphs, dependence graphs, etc. Each representation has advantages and
disadvantages for clone detection.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;PDG-based clone detection&lt;/em&gt; finds &lt;em&gt;dependence clones&lt;/em&gt; corresponding to recurring
subgraphs of a program dependence graph (PDG).  Since PDGs are oblivious to
semantics preserving statement reorderings they are well suited to detect
&lt;em&gt;semantic&lt;/em&gt; (functionally equivalent) clones. A number of algorithms find clones
from PDGs.  However, as Bellon notes, "PDG based techniques are computationally
expensive and often report non-contiguous clones that may not be perceived as
clones by a human evaluator." Most PDG-based clone detection tools are biased,
detecting certain clones but not others.&lt;/p&gt;
&lt;p&gt;The root cause of scalability problems with PDG-based clone detection is the
number of dependence clones. The Background Section (in the
&lt;a href="https://hackthology.com/pdfs/swan-2016.pdf"&gt;pdf&lt;/a&gt;) illustrates this with an example in which
we used an unbiased frequent subgraph mining algorithm to detect all dependence
clones in Java programs. In programs with about 70 KLOC it detected around 10
million clones before disk space was exhausted. Processing all dependence clones
is impractical even for modestly sized programs.&lt;/p&gt;
&lt;p&gt;Instead of exhaustively enumerating all dependence clones, an unbiased random
sample can be used to statistically estimate parameters of the whole
"population" of clones, such as the prevalence of clones exhibiting properties
of interest.  For these reasons, we developed a statistically unbiased method
for &lt;em&gt;sampling&lt;/em&gt; dependence clones and for &lt;em&gt;estimating&lt;/em&gt; parameters of the whole
clone population.&lt;/p&gt;
&lt;p&gt;We present &lt;a href="https://github.com/timtadh/graple"&gt;GRAPLE (GRAph samPLE)&lt;/a&gt;, a method
to generate a representative sample of recurring subgraphs of any directed
labeled graph(s). It can be used to sample subgraphs from any kind of program
graph representation.  &lt;code&gt;GRAPLE&lt;/code&gt; is not a general purpose clone detector but it
can answer questions about dependence clones that other PDG-based clone
detection tools cannot.  We conducted a preliminary case study on a commercial
application and had its developers evaluate whether the sampled subgraphs
represented code duplication.  To our knowledge, it is the first study to have
professional programmers examine dependence clones.  &lt;code&gt;GRAPLE&lt;/code&gt; has applications
in bug mining, test case selection, and bioinformatics. The sampling algorithm
also applies to frequent item sets, subsequences, and subtrees allowing code
clone sampling from tokens and ASTs.&lt;/p&gt;
&lt;h4&gt;Note&lt;/h4&gt;
&lt;p&gt;See the &lt;a href="https://hackthology.com/pdfs/swan-2016.pdf"&gt;PDF&lt;/a&gt; for the complete paper. ACM
has the exclusive rights to publish this paper. Tim Henderson and Andy Podgurski
own the copyright. Follow the &lt;a href="https://dx.doi.org/10.1145/2989238.2989241"&gt;DOI&lt;/a&gt;
for the ACM copy. This copy is posted here with the permission of ACM.&lt;/p&gt;</content><category term="Paper"/></entry><entry><title>Managing Infrastructure with Python, Fabric and Ansible</title><link href="https://hackthology.com/managing-infrastructure-with-python-fabric-and-ansible.html" rel="alternate"/><published>2016-08-01T00:00:00-04:00</published><updated>2016-08-01T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2016-08-01:/managing-infrastructure-with-python-fabric-and-ansible.html</id><summary type="html">&lt;p&gt;For &lt;a href="http://pyohio.org/"&gt;PyOhio&lt;/a&gt; 2016 I gave a short talk on managing
infrastructure. You can watch the talk on &lt;a href="http://youtu.be/4qav2EuXsGU"&gt;youtube&lt;/a&gt;
or look at the
&lt;a href="https://hackthology.com/pdfs/managing-infrastructure-with-python.pdf"&gt;slides&lt;/a&gt;. The talk
starts with a short poem printed below for posterity. I also created a super
simple demo which I did not have time to show. You …&lt;/p&gt;</summary><content type="html">&lt;p&gt;For &lt;a href="http://pyohio.org/"&gt;PyOhio&lt;/a&gt; 2016 I gave a short talk on managing
infrastructure. You can watch the talk on &lt;a href="http://youtu.be/4qav2EuXsGU"&gt;youtube&lt;/a&gt;
or look at the
&lt;a href="https://hackthology.com/pdfs/managing-infrastructure-with-python.pdf"&gt;slides&lt;/a&gt;. The talk
starts with a short poem printed below for posterity. I also created a super
simple demo which I did not have time to show. You can download a &lt;a href="https://hackthology.com/tars/ops-example.tar.gz"&gt;tarball of
the demo&lt;/a&gt;. To run the demo you are going to
need vagrant and the "hasicorp/precise64" box. No guarantees it works, I wrote
it in an hour or so to make sure everything in the presentation was sensible.&lt;/p&gt;
&lt;h2&gt;The World is Changing&lt;/h2&gt;
&lt;p&gt;by Tim Henderson&lt;/p&gt;
&lt;h3&gt;death of a sys-admin&lt;/h3&gt;
&lt;p&gt;One person.&lt;br/&gt;
Alone.&lt;br/&gt;
Do the many keyboards&lt;br/&gt;
Make the work light?&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;In the dead of the night,&lt;br/&gt;
How the flickers&lt;br/&gt;
Of the tubes&lt;br/&gt;
Shine so bright.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Two hands&lt;br/&gt;
Ten fingers&lt;br/&gt;
Typing so swift.&lt;br/&gt;
On keys, mechanical,&lt;br/&gt;
You can hear them click.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;A machine.&lt;br/&gt;
One then another,&lt;br/&gt;
Fixed.&lt;br/&gt;
The backlog clean.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Now it is June,&lt;br/&gt;
An evening star in the sky.&lt;br/&gt;
The sys-admin feels the breeze&lt;br/&gt;
As seagulls fly by.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Back in the office&lt;br/&gt;
Are the keyboards lonely?&lt;br/&gt;
A customer wonders:&lt;br/&gt;
Why do my pages&lt;br/&gt;
Load slowly?&lt;br/&gt;&lt;/p&gt;
&lt;h3&gt;there are too many machines&lt;/h3&gt;
&lt;p&gt;The flickering screens,&lt;br/&gt;
Can not keeps pace&lt;br/&gt;
With the whirring fans.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;The blades spin&lt;br/&gt;
As the AC hums.&lt;br/&gt;
The metal racks gleam&lt;br/&gt;
The floor it glows.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;But. Not enough,&lt;br/&gt;
Not enough dollars.&lt;br/&gt;
For too few cents,&lt;br/&gt;
Per page view is made.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Where is the sys-admin?&lt;br/&gt;
They left last May.&lt;br/&gt;
None to replace them,&lt;br/&gt;
For we couldn’t pay.&lt;br/&gt;&lt;/p&gt;
&lt;h3&gt;now, we have become root&lt;/h3&gt;
&lt;p&gt;The humble programmer.&lt;br/&gt;
One keyboard,&lt;br/&gt;
One screen!&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;No rituals on approach.&lt;br/&gt;
No doors to knock.&lt;br/&gt;
Just expensive headphones&lt;br/&gt;
Fuzzing with static.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;In the fields of desks&lt;br/&gt;
By the window so small&lt;br/&gt;
Sits the humble programmer&lt;br/&gt;
Trying to stay away&lt;br/&gt;
From it all.&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;But alas!&lt;br/&gt;
The servers are down.&lt;br/&gt;
Sys-admins?&lt;br/&gt;
None to be found!&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;To the command-line?&lt;br/&gt;
Neigh! &lt;br/&gt;
To the ansible, we pray!&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;Provision&lt;br/&gt;
Config&lt;br/&gt;
Deploy&lt;br/&gt;&lt;/p&gt;
&lt;p&gt;The chant &lt;br/&gt;
Doth resound.&lt;br/&gt;&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Writing a Lexer in Go with LexMachine</title><link href="https://hackthology.com/writing-a-lexer-in-go-with-lexmachine.html" rel="alternate"/><published>2016-05-25T00:00:00-04:00</published><updated>2016-05-25T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2016-05-25:/writing-a-lexer-in-go-with-lexmachine.html</id><summary type="html">&lt;p&gt;This article is about &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt;, a
library I wrote to help you write great lexers in Go. If you are looking to
write a golang lexer or a lexer in golang this article is for you.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;lexer&lt;/strong&gt; is a software component that analyzes a string and breaks it up …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This article is about &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt;, a
library I wrote to help you write great lexers in Go. If you are looking to
write a golang lexer or a lexer in golang this article is for you.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;lexer&lt;/strong&gt; is a software component that analyzes a string and breaks it up into its
component parts. Each part is tagged with what type of thing it is. This is
called &lt;em&gt;lexical analysis&lt;/em&gt;. For natural languages (such as English) lexical
analysis can be difficult to do automatically but is usually easy for a human to
do. Let's look at an example of lexically analyzing the following English
sentence often used in typing practice (because it uses every letter in the
alphabet).&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The quick brown fox jumped over the lazy dog.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The sentence breaks down into individual word each of which has a part of speech&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;article&amp;gt;, &amp;quot;The&amp;quot;
&amp;lt;adjective&amp;gt;, &amp;quot;quick&amp;quot;
&amp;lt;adjective&amp;gt;, &amp;quot;brown&amp;quot;
&amp;lt;noun&amp;gt;, &amp;quot;fox&amp;quot;
&amp;lt;verb&amp;gt;, &amp;quot;jumped&amp;quot;
&amp;lt;adverb&amp;gt;, &amp;quot;over&amp;quot;
&amp;lt;article&amp;gt;, &amp;quot;the&amp;quot;
&amp;lt;adjective&amp;gt;, &amp;quot;lazy&amp;quot;
&amp;lt;noun&amp;gt;, &amp;quot;dog&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note, the word "over" can actually be either a preposition or an adverb. In this
case the context of the sentence (it modifies the verb) makes it an adverb. Many
words in natural languages have this property where the context of the overall
sentence or paragraph determines the role they play in the sentence.&lt;/p&gt;
&lt;p&gt;Luckily, the situation is much simpler for computer languages. Most &lt;em&gt;compilers&lt;/em&gt;,
which are programs that translate computer languages into other computer
languages, start by lexically analyzing their input. They can also be used in a
number of other scenarios where a program needs to understand data in textual
forms.&lt;/p&gt;
&lt;p&gt;In this article, I am going to write and explain a lexer for the
&lt;a href="http://www.graphviz.org"&gt;graphviz&lt;/a&gt; &lt;a href="http://www.graphviz.org/doc/info/lang.html"&gt;dot
language&lt;/a&gt;. &lt;code&gt;graphviz&lt;/code&gt; is a tool to
visualize &lt;a href="https://en.wikipedia.org/wiki/Graph_(abstract_data_type)"&gt;graphs&lt;/a&gt;.
&lt;code&gt;graphviz&lt;/code&gt; takes a string such as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;digraph&lt;span class="w"&gt; &lt;/span&gt;{
&lt;span class="w"&gt;  &lt;/span&gt;rankdir=LR;
&lt;span class="w"&gt;  &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;[label=&amp;quot;a&amp;quot;&lt;span class="w"&gt; &lt;/span&gt;shape=box];
&lt;span class="w"&gt;  &lt;/span&gt;c&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;=&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;u&amp;gt;&lt;/span&gt;C&lt;span class="nt"&gt;&amp;lt;/u&amp;gt;&lt;/span&gt;&amp;gt;];
&lt;span class="w"&gt;  &lt;/span&gt;b&lt;span class="w"&gt; &lt;/span&gt;[label=&amp;quot;bb&amp;quot;];
&lt;span class="w"&gt;  &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;c;
&lt;span class="w"&gt;  &lt;/span&gt;c&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;b;
&lt;span class="w"&gt;  &lt;/span&gt;d&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;c;
&lt;span class="w"&gt;  &lt;/span&gt;b&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;a;
&lt;span class="w"&gt;  &lt;/span&gt;b&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;e;
&lt;span class="w"&gt;  &lt;/span&gt;e&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;f;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And produces :&lt;/p&gt;
&lt;p&gt;&lt;a href="/images/dot-example.png"&gt;&lt;img alt="Dot Example" src="/images/dot-example.png"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Lexing Graphviz's &lt;code&gt;dot&lt;/code&gt; language&lt;/h2&gt;
&lt;p&gt;Before one can "lex" (short for lexically analyze) a language one needs to know
what it is made up of. English is made up of punctuation marks, nouns, verbs and
that sort of thing. Computer languages also have punctuation but also have
keywords, strings, numbers, comments and so forth.&lt;/p&gt;
&lt;p&gt;When a lexer splits up a string into parts the parts are called &lt;em&gt;tokens&lt;/em&gt;. The
process of splitting up is also called &lt;em&gt;tokenizing&lt;/em&gt;. Let's take a look at how
the previous example would get tokenized:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Type&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;Lexeme
-------------------
DIGRAPH&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;digraph&amp;quot;
LCURLY&lt;span class="w"&gt;  &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;{&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;rankdir&amp;quot;
EQUAL&lt;span class="w"&gt;   &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;=&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;LR&amp;quot;
SEMI&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;;&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;\&amp;quot;a\&amp;quot;&amp;quot;
LSQUARE&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;[&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;label&amp;quot;
EQUAL&lt;span class="w"&gt;   &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;=&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;a&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;shape&amp;quot;
EQUAL&lt;span class="w"&gt;   &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;=&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;box&amp;quot;
RSQUARE&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;]&amp;quot;
SEMI&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;;&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;c&amp;quot;
LSQUARE&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;[&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;&amp;quot;
EQUAL&lt;span class="w"&gt;   &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;=&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;u&amp;gt;&lt;/span&gt;C&lt;span class="nt"&gt;&amp;lt;/u&amp;gt;&lt;/span&gt;&amp;gt;&amp;quot;
RSQUARE&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;]&amp;quot;
SEMI&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;;&amp;quot;
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;b&amp;quot;
.
.
.
RCURLY&lt;span class="w"&gt;  &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note, that like when the English sentence was analyzed, spaces, newlines, tabs
and other extraneous characters were dropped. Only the syntactically important
characters are output.&lt;/p&gt;
&lt;p&gt;Each token has two parts: the &lt;em&gt;type&lt;/em&gt; and the &lt;em&gt;lexeme&lt;/em&gt;. The type indicates the
role the token plays. The lexeme is the string the token was extracted from.&lt;/p&gt;
&lt;h3&gt;Specifying Tokens&lt;/h3&gt;
&lt;p&gt;To specify how a string should be tokenized a formalism called &lt;em&gt;regular
expressions&lt;/em&gt; is used. If you don't already know about regular expressions you
could start with the &lt;a href="https://en.wikipedia.org/wiki/Regular_expression"&gt;Wikipedia
page&lt;/a&gt;. For a more advanced
introduction see Russ Cox's &lt;a href="https://swtch.com/~rsc/regexp/"&gt;articles&lt;/a&gt; or Alex
Aiken's &lt;a href="https://www.youtube.com/watch?v=SRhkfvqeA1M"&gt;video lectures&lt;/a&gt; on the
subject.&lt;/p&gt;
&lt;p&gt;To review, a regular expression is a way of specifying a "pattern" which
matches certain strings. For instance, &lt;code&gt;a+b*a&lt;/code&gt; matches &lt;code&gt;aaa&lt;/code&gt; and &lt;code&gt;abbbba&lt;/code&gt; but
not &lt;code&gt;aab&lt;/code&gt;. To see why, note that the pattern says a string must start with 1 or
more &lt;code&gt;a&lt;/code&gt; characters. So all three strings &lt;code&gt;aaa&lt;/code&gt;, &lt;code&gt;abbbba&lt;/code&gt; and &lt;code&gt;aab&lt;/code&gt; satisfy the
first requirement. Next, the pattern says a string can have 0 or more &lt;code&gt;b&lt;/code&gt;
characters. The first string, &lt;code&gt;aaa&lt;/code&gt; has none (and that is ok). The second
string, &lt;code&gt;abbbba&lt;/code&gt; has 4 &lt;code&gt;b&lt;/code&gt; characters. The third string, &lt;code&gt;aab&lt;/code&gt; has 1 &lt;code&gt;b&lt;/code&gt;. So all
three strings satisfy the second requirement. Finally the pattern says a string
must end in an &lt;code&gt;a&lt;/code&gt;. The first and the second string both end in &lt;code&gt;a&lt;/code&gt;. However,
the third string, &lt;code&gt;aab&lt;/code&gt;, does not. Therefore, the first and second strings match
the pattern but the third string does not.&lt;/p&gt;
&lt;h4&gt;The Token's for the &lt;code&gt;dot&lt;/code&gt; Language&lt;/h4&gt;
&lt;p&gt;The &lt;code&gt;dot&lt;/code&gt; language has keywords, punctuation, comments, and a rather unusual
definition for identifier (called &lt;code&gt;ID&lt;/code&gt;). In the listing below, the token type is
on the left side and the regular expression or literal (in quotation marks) is
on the right.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;NODE = &amp;quot;node&amp;quot;
EDGE = &amp;quot;edge&amp;quot;
GRAPH = &amp;quot;graph&amp;quot;
DIGRAPH = &amp;quot;digraph&amp;quot;
SUBGRAPH = &amp;quot;subgraph&amp;quot;
STRICT = &amp;quot;strict&amp;quot;
LSQUARE = &amp;quot;[&amp;quot;
RSQUARE = &amp;quot;]&amp;quot;
LCURLY = &amp;quot;{&amp;quot;
RCURLY = &amp;quot;}&amp;quot;
EQUAL = &amp;quot;=&amp;quot;
COMMA = &amp;quot;,&amp;quot;
SEMI = &amp;quot;;&amp;quot;
COLON = &amp;quot;:&amp;quot;
ARROW = &amp;quot;-&amp;gt;&amp;quot;
DDASH = &amp;quot;--&amp;quot;
COMMENT = (/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*+/)|(//.*$)
ID = ([a-zA-Z_][a-zA-Z0-9_]*)|(&amp;quot;([^\&amp;quot;]|(\\.))*&amp;quot;)|ID-HTML
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Every token type but &lt;code&gt;ID&lt;/code&gt; and &lt;code&gt;COMMENT&lt;/code&gt; are literals: either a keyword or a
punctuation mark. A comment is defined by a complicated regular expression which
defines "c-style" range comments or line comments. Since the comment expression
is defined by a regular expression no nesting is allowed.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;ID&lt;/code&gt; token is more complicated. It consists of three parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;The "usual form" as a name &lt;code&gt;[a-zA-Z_][a-zA-Z0-9_]*&lt;/code&gt;. The pattern means a
   letter (lower case or capital) or underscore followed by 0 or more letters,
   numbers, or under-scores.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A string, &lt;code&gt;"([^\"]|(\\.))*"&lt;/code&gt;. Thus &lt;code&gt;"\\\""&lt;/code&gt; and &lt;code&gt;"asdf\""&lt;/code&gt; are valid but
   &lt;code&gt;"\\""&lt;/code&gt; is not.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A HTML string, which is non-regular (specified here in BNF):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;CHAR = [^&amp;lt;&amp;gt;]
ID-HTML = IdHTML

IdHTML : Tag ;
Tag : &amp;lt; Body &amp;gt; ;
Body : CHAR Body ;
     | Tag Body
     | e                    // denotes epsilon, the empty string
     ;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thus &lt;code&gt;&amp;lt;&amp;lt;xyz&amp;lt;xy&amp;gt;xyz&amp;gt;&amp;lt;asdf&amp;gt;&amp;gt;&lt;/code&gt; is valid but &lt;code&gt;&amp;lt;&amp;lt;&amp;gt;&lt;/code&gt; is not&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The reason the HTML string is not-regular (and therefore cannot be matched by
regular expressions) is the angle brackets, &lt;code&gt;&amp;lt;&lt;/code&gt; and &lt;code&gt;&amp;gt;&lt;/code&gt;, have to be properly
matched. That is, every opening bracket &lt;code&gt;&amp;lt;&lt;/code&gt; must be matched with a closing
bracket &lt;code&gt;&amp;gt;&lt;/code&gt;. This is not possible to specify regular expressions because they
cannot "count." For a formal explanation see the &lt;a href="https://en.wikipedia.org/wiki/Pumping_lemma_for_regular_languages"&gt;Pumping
Lemma&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Consequences of Non-Regular Tokens&lt;/h4&gt;
&lt;p&gt;If all tokens were regular (that is specifiable by a regular expression) then
the full implementation of the lexer could be generated from the regular
expressions for each of the tokens. Since the &lt;code&gt;dot&lt;/code&gt; language contains at least
one token which is non-regular, special consideration needs to be taken.&lt;/p&gt;
&lt;p&gt;This turns out to be a fairly common situation in lexer implementation. For
instance, if you want to support c-style comments such as &lt;code&gt;/* comment */&lt;/code&gt; which
support properly nested comments &lt;code&gt;/* asdf /* asdf */ asdf*/&lt;/code&gt; then the comment
token will no longer be regular. Furthermore, many languages (such as C)
require collaboration between the parser and lexer to properly identify whether
symbols should be variable names or type names. This can also introduce a degree
of non-regularity.&lt;/p&gt;
&lt;p&gt;Thus, to properly lexically analyze such languages our framework must have an
"escape hatch" that allows the analysis of non-regular tokens on demand while
still leveraging &lt;a href="https://swtch.com/~rsc/regexp/"&gt;theory&lt;/a&gt; for most of the work.&lt;/p&gt;
&lt;h2&gt;The LexMachine&lt;/h2&gt;
&lt;p&gt;To create a lexer for the &lt;code&gt;dot&lt;/code&gt; language I am going to use
&lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; a library I wrote for
creating lexers. &lt;code&gt;lexmachine&lt;/code&gt; handles all the tricky bits of converting regular
expressions into &lt;em&gt;Non-Deterministic Finite Automata&lt;/em&gt; (NFA) and using the the NFA
to tokenize strings. It also provides the aformentioned "escape hatch" to deal
with non-regular Token specifications.&lt;/p&gt;
&lt;p&gt;Let's get started!&lt;/p&gt;
&lt;h3&gt;The Implementation&lt;/h3&gt;
&lt;p&gt;As a reminder, the implementation is written in &lt;a href="https://golang.org"&gt;Go&lt;/a&gt;. In
your workspace, create a new package called dot:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;dot
$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;dot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now create a file for the lexer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;touch&lt;span class="w"&gt; &lt;/span&gt;lexer.go
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All of the code for the lexer is going in lexer.go.&lt;/p&gt;
&lt;h4&gt;Preamble&lt;/h4&gt;
&lt;p&gt;To begin, put in the package directive and import the &lt;code&gt;lexmachine&lt;/code&gt; and
&lt;code&gt;machines&lt;/code&gt; packages. I also import the standard library packages &lt;code&gt;fmt&lt;/code&gt; and
&lt;code&gt;strings&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dot&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;strings&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/lexmachine&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/lexmachine/machines&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note how I group the imports. In general, have three groups of imports. The first
group is for standard library packages, the second for third party, and the
third group is for other packages in your code.&lt;/p&gt;
&lt;h4&gt;Defining the Tokens&lt;/h4&gt;
&lt;p&gt;Next, I create global variables and initialize them. They contain the literal
tokens, the keywords, the token names, and a mapping from the names of the
tokens to their type ids. Finally, there is a variable &lt;code&gt;Lexer *lex.Lexer&lt;/code&gt; which
will hold our &lt;code&gt;Lexer&lt;/code&gt; object once constructed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Literals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// The tokens representing literal strings&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// The keyword tokens&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// All of the tokens (including literals and keywords)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenIds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// A map from the token names to their int ids&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// The lexer object. Use this to construct a Scanner&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To initialize the lists of tokens we are going to need a function. The reason is
although, &lt;code&gt;Literals&lt;/code&gt; and &lt;code&gt;Keywords&lt;/code&gt; could be defined in place the rest of the
variables cannot be.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initTokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Literals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;[&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;]&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;=&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;,&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;:&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;-&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;NODE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;EDGE&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;GRAPH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DIGRAPH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;SUBGRAPH&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;STRICT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Keywords&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Literals&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;TokenIds&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;TokenIds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Right now, the &lt;code&gt;initTokens()&lt;/code&gt; function is not being called. Later, I will show
you how to call it on package initialization inside of an &lt;code&gt;init&lt;/code&gt; function.&lt;/p&gt;
&lt;h4&gt;Defining the Lexer&lt;/h4&gt;
&lt;p&gt;Creating a new lexer object is straight forward.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Lexer object has three methods:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;regex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Add&lt;/code&gt; method is what we are interested in right now. It adds a new token to
the lexer. The token is defined by a pattern expressed as a regular expression
and an Action function. When the pattern is matched the &lt;code&gt;Action&lt;/code&gt; function gets
called.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;An &lt;code&gt;Action&lt;/code&gt; takes a &lt;code&gt;*Scanner&lt;/code&gt; (which is a object which is scanning a particular
string using the &lt;code&gt;*Lexer&lt;/code&gt; object), and a &lt;code&gt;*Match&lt;/code&gt; (which represents the string
that was matched by the Regular expression. It returns a token and an error.&lt;/p&gt;
&lt;p&gt;If the &lt;code&gt;token&lt;/code&gt; return value is nil, the &lt;code&gt;*Match&lt;/code&gt; is skipped. This can be used to
skip whitespace and other things you would rather ignore. Let's go head and code
up the the skip Action:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Super simple! It is a no op!&lt;/p&gt;
&lt;p&gt;However, most of the time you will want to create a token. First, we need to
have a *Token object to construct. Luckily, &lt;code&gt;lexmachine&lt;/code&gt; defines one (although
you don't have to use it). Let's take a look at the definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// the token type&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// a value associate with the token&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// the string that was matched&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// the index (text counter) in the string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;other&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;*Scanner&lt;/code&gt; object provides a convience function &lt;code&gt;Token&lt;/code&gt; which constructs a
token for you. Here is the definition:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So, with this in mind, here is a simple &lt;code&gt;Action&lt;/code&gt; which will construct a Token
with a string version of the lexeme as the &lt;code&gt;Value&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Action&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;TokenIds&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; paramter is the name of the token (eg. &lt;code&gt;COMMENT&lt;/code&gt;, &lt;code&gt;ID&lt;/code&gt;, &lt;code&gt;STRICT&lt;/code&gt;,
&lt;code&gt;{&lt;/code&gt;, ...). The &lt;code&gt;token&lt;/code&gt; function will constuct a &lt;code&gt;*Token&lt;/code&gt; of correct type (eg.
the one you specified with &lt;code&gt;name&lt;/code&gt;) and return it.&lt;/p&gt;
&lt;h4&gt;Adding Patterns to the Lexer&lt;/h4&gt;
&lt;p&gt;Now that we have &lt;code&gt;Action&lt;/code&gt; functions to work with (&lt;code&gt;skip&lt;/code&gt; and &lt;code&gt;token&lt;/code&gt;) we are
ready to add patterns to the lexer. Since &lt;code&gt;lexmachine&lt;/code&gt; is built on automata
theory patterns are matched with these priorities:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Patterns match prefixes of string being scanned. Normally, a regular
   expression matches the entire string or the first substring (depending on the
   mode). After a prefix is matched, the lexer is restarted at the end of the
   previously matched prefix and matches another prefix until the string is
   consumed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Through use of automata theory, all patterns are matched in parallel.
   Currently, &lt;code&gt;lexmachine&lt;/code&gt; uses an Non-Deterministic Finite Automata (NFA)
   simulation "under-the-hood" to do the matching. NFA simulations take O(P*S)
   where S is the size of the string and P is the size of the pattern (or in the
   case of a lexer the sum of the sizes of all of the patterns). There is a
   Deterministic Finite Automata (DFA) code generator under development (but not
   ready at this time) which will be able to generate Go code to lex a string in
   linear time O(S).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The pattern which matches the longest prefix is chosen as the "matching
   pattern". The matching pattern determines which lexing action gets run (and
   thus what kind of token gets created).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In case of tie, the pattern which was defined first is chosen.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Since order that patterns are added to the lexer matters, literals and keywords
should be added first. This is important as other token's patterns (such as
&lt;code&gt;ID&lt;/code&gt;) could match them. Since, the literals and keywords are both stored in
their own lists this is easy to do in a loop:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Literals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note: I add escapes to every character in the literals. So that literals like
&lt;code&gt;[&lt;/code&gt; have patterns such as &lt;code&gt;\[&lt;/code&gt;. This ensures those characters (which have
syntactic meaning in regular expressions) are interpreted as themselves.
Otherwise, they would be parsed by the regular expression parser incorrectly.&lt;/p&gt;
&lt;p&gt;Second Note: The patterns constructed for the keywords is the lower case version
of the token name. I could have had the token names for the keywords be in lower
case but it is tradition for token names to be capitalized. This helps
distinguish token names from production names in context free grammar.&lt;/p&gt;
&lt;h4&gt;Adding More Complex Patterns&lt;/h4&gt;
&lt;p&gt;The simple patterns are now added to the lexer. For the &lt;code&gt;COMMENT&lt;/code&gt; and &lt;code&gt;ID&lt;/code&gt;
tokens I will add a separate pattern for each of the alternative construction
options:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`//[^\n]*\n?`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`/\*([^*]|\r|\n|(\*+([^*/]|\r|\n)))*\*+/`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`&amp;quot;([^\\&amp;quot;]|(\\.))*&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Note: I left out the last form of &lt;code&gt;ID&lt;/code&gt; the HTML string. We will get back to that
in a second. The final pattern to add is for whitespace: spaces, tabs, newlines,
and carriage returns. I don't want tokens produced for these characters to I
will use the &lt;code&gt;skip&lt;/code&gt; function as the lexer &lt;code&gt;Action&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;( |\t|\n|\r)+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Using the "Escape Hatch"&lt;/h4&gt;
&lt;p&gt;Now, to deal with the third form of the &lt;code&gt;ID&lt;/code&gt; token: the HTML string. I need a
pattern that fires when the beginning of the string is found. This is easy as
the HTML strings always start with a &lt;code&gt;&amp;lt;&lt;/code&gt; character and the &lt;code&gt;&amp;lt;&lt;/code&gt; is not found
elsewhere in the language. Then, I write a very special &lt;code&gt;Action&lt;/code&gt; function. It
turns out, that &lt;code&gt;Actions&lt;/code&gt; are allowed to make modifications to the internal
state of the &lt;code&gt;*Scanner&lt;/code&gt;. In particular they are allowed to change where the
index into the string being tokenized is located. That index is called the text
counter and is stored in the &lt;code&gt;TC&lt;/code&gt; variable. Let's take a look at what &lt;code&gt;*Scanner&lt;/code&gt;
exports:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// contains filtered or unexported fields&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;typ&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;Text&lt;/code&gt; variable can be read but you should not modify it. Modifying it will
have no effect on the tokenization as the NFA simulation keeps its own pointer
to the text being scanned. The &lt;code&gt;TC&lt;/code&gt; variable is the text counter and we can both
read and write it inside of an &lt;code&gt;Action&lt;/code&gt;. What this allows us to do is find the
starting point of an HTML string with the pattern &lt;code&gt;&amp;lt;&lt;/code&gt; and then scan along
manually counting the opening and closing angle brackets. Once, the initial open
bracket has been closed by a matching &lt;code&gt;&amp;gt;&lt;/code&gt; the HTML string has been found.&lt;/p&gt;
&lt;p&gt;The only trick is we need to keep track of the text counter and update it. We
also have to update the &lt;code&gt;*Match&lt;/code&gt; object to contain the correct values for the
end lines and columns for our token.&lt;/p&gt;
&lt;p&gt;Let's see how it works:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\&amp;lt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unclosed HTML literal starting at %d, (%d, %d)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here, I defined the action in-line since it will not be reused using Go's
support for anonymous functions. The text counter, &lt;code&gt;scan.TC&lt;/code&gt;, is initially
pointing at the character directly following the matched pattern. Thus, the
bracket count in &lt;code&gt;brackets&lt;/code&gt; is initialized to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When &lt;code&gt;brackets&lt;/code&gt; reaches &lt;code&gt;0&lt;/code&gt; through incrementing and decrementing everytime a
&lt;code&gt;&amp;lt;&lt;/code&gt; or &lt;code&gt;&amp;gt;&lt;/code&gt; is seen the match is found. When the match is found, the &lt;code&gt;scan.TC&lt;/code&gt;
variable &lt;strong&gt;must&lt;/strong&gt; be updated to communicate back to the scanner where to look
for the next token. The &lt;code&gt;*Match&lt;/code&gt; is also updated to reflect the full lexeme that
was found. Finally, an &lt;code&gt;ID&lt;/code&gt; token is constructed using the &lt;code&gt;token&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;If the function runs out of text before &lt;code&gt;brackets&lt;/code&gt; reaches &lt;code&gt;0&lt;/code&gt; an error is
returned reporting an unclosed &lt;code&gt;HTML&lt;/code&gt; literal.&lt;/p&gt;
&lt;h4&gt;Compiling the NFA&lt;/h4&gt;
&lt;p&gt;The last step in &lt;code&gt;*Lexer&lt;/code&gt; construction is to compile the NFA. This will be done
automatically when a &lt;code&gt;*Scanner&lt;/code&gt; is constructed to tokenize the string. However,
we can have the NFA precomputed by calling &lt;code&gt;Compile&lt;/code&gt;. This is important so that
we don't spend time parsing regular expressions every time we want to lex a
string&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Putting it all Together&lt;/h4&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Creates the lexer object and compiles the NFA.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;NewLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Literals&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\\&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lit&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Keywords&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;strings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ToLower&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`//[^\n]*\n?`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`/\*([^*]|\r|\n|(\*+([^*/]|\r|\n)))*\*+/`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;COMMENT&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`([a-z]|[A-Z])([a-z]|[A-Z]|[0-9]|_)*`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`&amp;quot;([^\\&amp;quot;]|(\\.))*&amp;quot;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;( |\t|\n|\r)+&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;skip&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`\&amp;lt;`&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;machines&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;&amp;lt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;brackets&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;str&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ID&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;scan&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;unclosed HTML literal starting at %d, (%d, %d)&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Compile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Initializing the Package&lt;/h4&gt;
&lt;p&gt;To ensure that the regular expressions are only compiled once, we are going to
call &lt;code&gt;initLexer&lt;/code&gt; once at the start of the program. To do this we put the call
inside an &lt;a href="https://golang.org/ref/spec#Package_initialization"&gt;&lt;code&gt;init&lt;/code&gt; function&lt;/a&gt;.
Init functions get run once on program start up.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// Called at package initialization. Creates the lexer and populates token lists.&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;init&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;initTokens&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;initLexer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And that is it. Here is the &lt;a href="https://github.com/timtadh/dot/blob/9b5afb350454d8e023e02a0b8b3c828869ec647e/lexer.go"&gt;source code for the full
lexer&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Using the Lexer&lt;/h3&gt;
&lt;p&gt;Let's put it all together. Here is a simple example which uses the lexer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/dot&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;github.com/timtadh/lexmachine&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Scanner&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nb"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;`digraph {&lt;/span&gt;
&lt;span class="s"&gt;  rankdir=LR;&lt;/span&gt;
&lt;span class="s"&gt;  a [label=&amp;quot;a&amp;quot; shape=box];&lt;/span&gt;
&lt;span class="s"&gt;  c [&amp;lt;label&amp;gt;=&amp;lt;&amp;lt;u&amp;gt;C&amp;lt;/u&amp;gt;&amp;gt;];&lt;/span&gt;
&lt;span class="s"&gt;  b [label=&amp;quot;bb&amp;quot;];&lt;/span&gt;
&lt;span class="s"&gt;  a -&amp;gt; c;&lt;/span&gt;
&lt;span class="s"&gt;  c -&amp;gt; b;&lt;/span&gt;
&lt;span class="s"&gt;  d -&amp;gt; c;&lt;/span&gt;
&lt;span class="s"&gt;  b -&amp;gt; a;&lt;/span&gt;
&lt;span class="s"&gt;  b -&amp;gt; e;&lt;/span&gt;
&lt;span class="s"&gt;  e -&amp;gt; f;&lt;/span&gt;
&lt;span class="s"&gt;}`&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Type    | Lexeme     | Position&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;--------+------------+------------&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;eof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Fatal&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tok&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;lex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%-7v | %-10v | %v:%v-%v:%v\n&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;dot&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Tokens&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StartColumn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndLine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EndColumn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Type&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;Lexeme&lt;span class="w"&gt;     &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;Position
--------+------------+------------
DIGRAPH&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;digraph&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;1:1-1:7
{&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;{&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;1:9-1:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;rankdir&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;2:3-2:9
=&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;2:10-2:10
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;LR&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;2:11-2:12
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;2:13-2:13
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:3-3:3
[&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:5-3:5
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;label&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:6-3:10
=&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:11-3:11
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;a&amp;quot;&lt;span class="w"&gt;        &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:12-3:14
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;shape&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:16-3:20
=&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:21-3:21
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;box&lt;span class="w"&gt;        &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:22-3:24
]&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;]&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:25-3:25
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;3:26-3:26
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:3-4:3
[&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:5-4:5
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;label&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:6-4:12
=&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:13-4:13
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;u&amp;gt;&lt;/span&gt;C&lt;span class="nt"&gt;&amp;lt;/u&amp;gt;&lt;/span&gt;&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:14-4:23
]&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;]&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:24-4:24
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;4:25-4:25
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;b&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:3-5:3
[&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;[&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:5-5:5
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;label&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:6-5:10
=&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;=&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:11-5:11
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;&amp;quot;bb&amp;quot;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:12-5:15
]&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;]&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:16-5:16
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;5:17-5:17
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;6:3-6:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;6:5-6:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;6:8-6:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;6:9-6:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;7:3-7:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;7:5-7:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;b&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;7:8-7:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;7:9-7:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;d&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;8:3-8:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;8:5-8:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;c&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;8:8-8:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;8:9-8:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;b&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;9:3-9:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;9:5-9:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;9:8-9:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;9:9-9:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;b&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;10:3-10:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;10:5-10:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;e&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;10:8-10:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;10:9-10:9
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;e&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;11:3-11:3
-&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;-&amp;gt;&lt;span class="w"&gt;         &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;11:5-11:6
ID&lt;span class="w"&gt;      &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;f&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;11:8-11:8
;&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;;&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;11:9-11:9
}&lt;span class="w"&gt;       &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;}&lt;span class="w"&gt;          &lt;/span&gt;|&lt;span class="w"&gt; &lt;/span&gt;12:1-12:1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Believe it or not 3500 words later, we have only scratched the surface on this
topic. Testing, custom token representations, automata construction, and more
will have to wait for another post. While still in an early state I hope you
find &lt;a href="https://github.com/timtadh/lexmachine"&gt;lexmachine&lt;/a&gt; useful and this article
helpful for constructing lexers whatever language you are using.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Golang中的面向对象继承</title><link href="https://hackthology.com/golangzhong-de-mian-xiang-dui-xiang-ji-cheng.html" rel="alternate"/><published>2016-05-20T00:00:00-04:00</published><updated>2016-05-20T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2016-05-20:/golangzhong-de-mian-xiang-dui-xiang-ji-cheng.html</id><summary type="html">&lt;p&gt;Golang的面向对象机制与Smalltalk或者Java等传统面向对象的编程语言不同。传统面向对象编程语言的一个重要特性是继承机制。因为继承机制支持在关联对象间进行代码复用和数据共享。继承 …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Golang的面向对象机制与Smalltalk或者Java等传统面向对象的编程语言不同。传统面向对象编程语言的一个重要特性是继承机制。因为继承机制支持在关联对象间进行代码复用和数据共享。继承机制曾在代码复用和数据共享的设计模式占据主导地位，但是目前组合这一古老的技术重新焕发了活力。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;本篇文章转自Tim Henderson的 "Object Oriented Inheritance in Go"， 原文地址是 &lt;a href="http://hackthology.com/object-oriented-inheritance-in-go.html"&gt;http://hackthology.com/object-oriented-inheritance-in-go.html&lt;/a&gt; 。非常感谢李浩和骏奇对于这篇文章的翻译。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;在我们探讨如何在Go中实现继承机制之前（Golong中的继承机制和其他语言(Java)的继承机制有区别），我们先看一下Java中如何实现继承机制。&lt;/p&gt;
&lt;h3&gt;继承与组合&lt;/h3&gt;
&lt;p&gt;让我们先看一下我最喜欢的话题之一：编译器！编译器由管道转换构成，该管道读取text文本并将其转化为机器代码、汇编语言、字节码或者其他的编程语言。管道首先会使用语法分析器对目标变成语言进行语法分析。一般情况下文本会被分解为不同的组成部分，例如：关键词、标识符、标点和数字等等。每个组成部分都会被相应的数据类型标记。例如下面这个Java数据类型：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这些组成部分（可以称作标记）如下所示：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;public keyword&amp;gt;, &amp;quot;public&amp;quot;
&amp;lt;class keyword&amp;gt;, &amp;quot;class&amp;quot;
&amp;lt;idenitifier&amp;gt;, &amp;quot;Main&amp;quot;
&amp;lt;left-bracket&amp;gt;, &amp;quot;{&amp;quot;
&amp;lt;right-bracket&amp;gt;, &amp;quot;}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这些标记可以划分为两个部分：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;标记类型&lt;/li&gt;
&lt;li&gt;语义部分&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这会导致我们进行如下的Java设计方式：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LBRACKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RBRACKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TokenToken&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;Here&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;I&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;think&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TokenToken&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;should&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;be&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;TokenType&amp;quot;&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexeme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;对于一些标记类型来说，例如数值常量，标记类型最好能够将包含这些属性信息。就数值常量来说，在他的标记类型里应该包括常量值这一属性。实现这一设计的传统方式是使用继承机制产生Token子类。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;另外一种完成该设计的方式是利用组合方式产生IntegerConstant，IntegerConstant包含token的引用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在这个例子中，继承机制是一个比较恰当的选择。理由是语法分析器需要返回一个通用类型。考虑一下语法分析器的接口设计：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputStream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在继承机制中，IntegerConstant 属于Token类型，所以它可以在Lexer中调用。这不是唯一可用或者最好的设计，但是这种设计方式是有效的。让我们看一下Go是如何完成这一目的的。&lt;/p&gt;
&lt;h3&gt;Inheritance and Composition in Go&lt;/h3&gt;
&lt;p&gt;Go中实现组合是一件十分容易的事情。简单组合两个结构体就能够构造一个新的数据类型。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;KEYWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;iota&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIER&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;LBRACKET&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;RBRACKET&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这就是Go中实现代码和数据共享的常用方式。然而如果你想实现继承机制，我们该如何去做？&lt;/p&gt;
&lt;h4&gt;Why would you want to use inheritance in go&lt;/h4&gt;
&lt;p&gt;一个可选的方案是将Token设计成接口类型。这种方案在Java和Go都适用：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;toktype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;lexeme&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toktype&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lexeme&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这样分析器就可以返回满足&lt;em&gt;Match 和 &lt;/em&gt;IntegerConstant类型的Token接口。&lt;/p&gt;
&lt;h4&gt;继承机制的简化版&lt;/h4&gt;
&lt;p&gt;上面的实现方案的一个问题是*IntegerConstant的方法调用中，出现了重复造轮子的问题。但是我们可以使用Go内建的嵌入机制来避免此类情况的出现。嵌入机制(匿名嵌入)允许类型之前共享代码和数据。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;IntegerConstant中匿名嵌入了Token类型，使得IntegerConstant"继承"了Token的字段和方法。很酷的方法！我们可以这样写代码：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wizard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(可以在这里试一下 ：&lt;a href="https://play.golang.org/p/PJW7VShpE0"&gt;https://play.golang.org/p/PJW7VShpE0&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;我们没有编写Type()和Value()方法的代码，但是*IntegerConstant也实现了Token接口，非常棒。&lt;/p&gt;
&lt;h4&gt;结构体的"继承"机制&lt;/h4&gt;
&lt;p&gt;Go中有三种方式完成”继承“机制，您已经看到了第一种实现方式：在结构体的第一个字段匿名嵌入接口类型。你还可以利用结构体实现其他两种”继承“机制：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;匿名嵌入结构体实例&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;2.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;匿名嵌入结构体实例指针&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;在所有的例子中，与正常嵌入类型不同的是我们使用匿名嵌入。然而，这个字段还是有字段名称的，名称是嵌入类型名称。在IntegerConstant 的Match字段中，字段名称是Match，无论嵌入类型是实例还是指针。&lt;/p&gt;
&lt;p&gt;在以上的方案中，你不能嵌入与嵌入类型相同的方法名。例如结构体Bar匿名嵌入结构体Foo后，就不能拥有名称为Foo的方法，同样也不能实现type Fooer interface { Foo() }接口类型。&lt;/p&gt;
&lt;h3&gt;共享代码、共享数据或者两者兼得&lt;/h3&gt;
&lt;p&gt;相比于Java，Go在继承和聚合之间的界限是很模糊的。Go中没有extends关键词。在语法的层次上，继承看上去与聚合没有什么区别。Go中聚合跟继承唯一的不同在于，继承自其他结构体的struct类型可以直接访问父类结构体的字段和方法。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(可以试一下  &lt;a href="https://play.golang.org/p/Pmkd27Nqqy"&gt;https://play.golang.org/p/Pmkd27Nqqy&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;嵌入式继承机制的的局限&lt;/h3&gt;
&lt;p&gt;相比于Java， Go的继承机制的作用是非常有限的。有很多的设计方案可以在Java轻松实现，但是Go却不可能完成同样的工作。让我们看一下：&lt;/p&gt;
&lt;h4&gt;Overriding Methods&lt;/h4&gt;
&lt;p&gt;上面的Pet例子中，Dog类型重载了Speak()方法。然而如果Pet有另外一个方法Play()被调用，但是Dog没有实现Play()的时候，Dog类型的Speak()方法则不会被调用。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(试一下  &lt;a href="https://play.golang.org/p/id-aDKW8L6"&gt;https://play.golang.org/p/id-aDKW8L6&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;但是Java中就会像我们预想的那样工作：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %s and I am a %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;javac&lt;span class="w"&gt; &lt;/span&gt;Main.java&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java&lt;span class="w"&gt; &lt;/span&gt;Main
spot
my&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;spot&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;pointer
my&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;spot&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;这个明显的区别是因为Go从根本上阻止了抽象方法的使用。让我们看看下面这个例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(试一下 &lt;a href="https://play.golang.org/p/9iIb2px7jH"&gt;https://play.golang.org/p/9iIb2px7jH&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;现在跟我们预想的一样了，但是跟Java相比略显冗长和晦涩。你必须手工重载方法签名。而且，代码在结构体未正确初始化的情况下会崩溃，例如当调用Speak()时，speaker()却没有完成初始化工作的时候。&lt;/p&gt;
&lt;h4&gt;Subtyping&lt;/h4&gt;
&lt;p&gt;在Java中，Dog继承自Pet，那么Dog类型就是Pet子类。这意味着在任何需要调用Pet类型的场景都可以使用Dog类型替换。这种关系称作多态性，但Go的结构体类型不存在这种机制。&lt;/p&gt;
&lt;p&gt;让我们看下面的例子：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(试一下  &lt;a href="https://play.golang.org/p/e1Ujx0VhwK"&gt;https://play.golang.org/p/e1Ujx0VhwK&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;go&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cannot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;然而，接口类型中存在子类化的多态机制！&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(试一下  &lt;a href="https://play.golang.org/p/WMH-cr4AJf"&gt;https://play.golang.org/p/WMH-cr4AJf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;输出：&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;所以接口类型可以用来实现子类化的机制。但是如果你想正确的实现方法重载，需要了解以上的技巧。&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;事实上，虽然这不是Go的主打特性，但是Go语言在结构体嵌入结构体或者接口方面的能力确实为实际工作增加了很大的灵活性。Go的这些特性为我们解决实际问题提供了新的解决方案。但是相较于Java等语言，由于Go缺少子类化和方法重载支持还有存在一些局限性。Go含有一项Java没有的特性--接口嵌入。关于接口嵌入的细节请参考Golang的官方文档的Embedding部分。&lt;/p&gt;
&lt;p&gt;非常感谢echlebek, Alexander Staubo, spriggan3和breerly对这篇文章提供的支持！&lt;/p&gt;</content><category term="Mandarin"/></entry><entry><title>Object Oriented Inheritance in Go</title><link href="https://hackthology.com/object-oriented-inheritance-in-go.html" rel="alternate"/><published>2016-05-20T00:00:00-04:00</published><updated>2016-05-20T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2016-05-20:/object-oriented-inheritance-in-go.html</id><summary type="html">&lt;p&gt;The Go (golang) programming language is not a traditional object oriented
language like Smalltalk or Java. A key feature supporting traditional object
oriented design is inheritance.  Inheritance supports sharing of code and data
between related objects. It used to be that inheritance was the dominant design
for sharing code and …&lt;/p&gt;</summary><content type="html">&lt;p&gt;The Go (golang) programming language is not a traditional object oriented
language like Smalltalk or Java. A key feature supporting traditional object
oriented design is inheritance.  Inheritance supports sharing of code and data
between related objects. It used to be that inheritance was the dominant design
for sharing code and data but today another (older) technique called composition
has seen a resurgence.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Thank you 李浩 (Hao Li) for translating this article into Mandarin:
&lt;a href="/golangzhong-de-mian-xiang-dui-xiang-ji-cheng.html" title="Golang中的面向对象继承"&gt;Golang中的面向对象继承&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before we jump into how to use inheritance in Go (which has some interesting
edge cases) let's see how it is used in Java.&lt;/p&gt;
&lt;h3&gt;Inheritance vs. Composition in Java&lt;/h3&gt;
&lt;p&gt;Let's look at an example from one of my favorite topics: compilers! A compiler
is made up of a pipeline of transformations that take "plain text" and transform
it either to machine code, assembly language, bytecode, or another programming
language. The first stage of the pipeline the &lt;em&gt;lexer&lt;/em&gt; performs what is called
&lt;em&gt;lexical analysis&lt;/em&gt; of the programming language. It traditionally splits the text
up into the different components as: keywords, identifiers, punctuation,
numbers, etc... Each component is tagged with the class of component it is. So
for this fragment of Java:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The "components" (called &lt;em&gt;tokens&lt;/em&gt;) would be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt;public keyword&amp;gt;, &amp;quot;public&amp;quot;
&amp;lt;class keyword&amp;gt;, &amp;quot;class&amp;quot;
&amp;lt;idenitifier&amp;gt;, &amp;quot;Main&amp;quot;
&amp;lt;left-bracket&amp;gt;, &amp;quot;{&amp;quot;
&amp;lt;right-bracket&amp;gt;, &amp;quot;}&amp;quot;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The tokens have two parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The &lt;em&gt;token type&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The &lt;em&gt;lexeme&lt;/em&gt;, or the string the token was extracted from&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This leads to the following Java design&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;IDENTIFIER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;LBRACKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;RBRACKET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;TokenToken&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lexeme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For some tokens, such as numeric constants, it is convenient to specialize the
&lt;code&gt;Token&lt;/code&gt; object to contain some extra information. In the case of numeric
constants the numerical value of the lexeme is convenient to store directly in
the &lt;code&gt;Token&lt;/code&gt;. The traditional way to accomplish this is to have the numeric
tokens &lt;em&gt;inherit&lt;/em&gt; from the &lt;code&gt;Token&lt;/code&gt; class.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Another way this can be achieved is to use composition where the &lt;code&gt;IntegerConstant&lt;/code&gt;
instead of extending the &lt;code&gt;Token&lt;/code&gt; class contains a reference to the token.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It turns out, in this particular case, inheritance is the better choice. The
reason is the &lt;code&gt;Lexer&lt;/code&gt; which produces the tokens needs to return a common type.
Consider the interface of the Lexer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Lexer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Lexer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InputStream&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;in&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;EOF&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;peek&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Since in the first design (which uses inheritance) a &lt;code&gt;IntegerConstant&lt;/code&gt; &lt;em&gt;is a&lt;/em&gt;
&lt;code&gt;Token&lt;/code&gt; it can be used in the Lexer. Now, this isn't the only design that can be
used and maybe isn't even the best design but it is valid. Let's take a look at
how it translates to into Go.&lt;/p&gt;
&lt;h3&gt;Inheritance and Composition in Go&lt;/h3&gt;
&lt;p&gt;Composition is very natural in Go (as it is in most languages). To compose two
structures simply provide a pointer or embedding to the collaborating structure.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint16&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;KEYWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;iota&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;IDENTIFIER&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;LBRACKET&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;RBRACKET&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;INT&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This would be the usual way to share code and data in Go. However, if you feel
the need for inheritance then how can we use it?&lt;/p&gt;
&lt;h4&gt;Why would you want to use inheritance in go?&lt;/h4&gt;
&lt;p&gt;One of the obvious alternative designs for the &lt;code&gt;Token&lt;/code&gt; is to make it an
interface. This works equally well in both Java and Go:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;toktype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;lexeme&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toktype&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lexeme&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TokenType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The Lexer can then easily return the &lt;code&gt;Token&lt;/code&gt; interface which both &lt;code&gt;*Match&lt;/code&gt; and
&lt;code&gt;*IntegerConstant&lt;/code&gt; satisfy.&lt;/p&gt;
&lt;h4&gt;Simplifying with inheritance&lt;/h4&gt;
&lt;p&gt;One of the problems with the previous design is the manual work in
&lt;code&gt;*IntegerConstant&lt;/code&gt; calling &lt;code&gt;i.token.Type()&lt;/code&gt; and &lt;code&gt;i.token.Lexeme()&lt;/code&gt;. It turns out
we can use Go's built in support for
&lt;a href="https://twitter.com/hackthology"&gt;&lt;em&gt;embedding&lt;/em&gt;&lt;/a&gt; to avoid this work. Embedding is
a limited form of inheritance which allows types to share data and code.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By not giving the &lt;code&gt;Token&lt;/code&gt; field a name in &lt;code&gt;IntegerConstant&lt;/code&gt;, it "inherits" the
methods (and fields if &lt;code&gt;Token&lt;/code&gt; was a &lt;code&gt;struct&lt;/code&gt;) from &lt;code&gt;Token&lt;/code&gt;. This pretty cool!
We can write code like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;KEYWORD&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wizard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Value&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Type&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Lexeme&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it in the playground &lt;a href="https://play.golang.org/p/PJW7VShpE0"&gt;https://play.golang.org/p/PJW7VShpE0&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;So wow! Not only did we not have implement &lt;code&gt;Type()&lt;/code&gt; and &lt;code&gt;Value()&lt;/code&gt; but
&lt;code&gt;*IntegerConstant&lt;/code&gt; also implements the &lt;code&gt;Token&lt;/code&gt; interface. Pretty nice.&lt;/p&gt;
&lt;h4&gt;"Inheriting" from &lt;code&gt;structs&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;There are three ways to do "inheritance" in Go. You have already seen one,
"inheriting" from an &lt;code&gt;interface&lt;/code&gt; by putting it as the first member without a field
name. It turns out your can do the same thing with &lt;code&gt;struct&lt;/code&gt;s and you have two
choices&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Inherit by embedding the &lt;code&gt;struct&lt;/code&gt; by value&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inherit by embedding a pointer to a &lt;code&gt;struct&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntegerConstant&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Match&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint64&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In all cases, the difference from a regular field is the lack of an explicit
name. However, the field still has a name. It is the name of the embedded type.
In the case of &lt;code&gt;IntegerConstant&lt;/code&gt; the &lt;code&gt;Match&lt;/code&gt; field is named &lt;code&gt;Match&lt;/code&gt;. This is
true whether one embeds a pointer to a struct or a struct by value.&lt;/p&gt;
&lt;p&gt;On gotcha of all of these options, you can't have a Field and a method with the
same name. A &lt;code&gt;struct&lt;/code&gt; &lt;code&gt;Bar&lt;/code&gt; is embedding a &lt;code&gt;struct&lt;/code&gt; &lt;code&gt;Foo&lt;/code&gt; precludes &lt;code&gt;Bar&lt;/code&gt; from
having a method called &lt;code&gt;Foo&lt;/code&gt;. It also prevents &lt;code&gt;Bar&lt;/code&gt; from implementing &lt;code&gt;type
Fooer interface { Foo() }&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Sharing Data, Code or Both&lt;/h3&gt;
&lt;p&gt;In Go the line between inheritance and composition is pretty blurry in
comparison with Java. There is no &lt;code&gt;extends&lt;/code&gt; keyword. Syntactically, inheritance
looks almost identical to composition. The only difference between composition
and inheritance in Go, is a &lt;code&gt;struct&lt;/code&gt; which inherits from another &lt;code&gt;struct&lt;/code&gt; can
directly access the methods and fields of the parent &lt;code&gt;struct&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try in the playground &lt;a href="https://play.golang.org/p/Pmkd27Nqqy"&gt;https://play.golang.org/p/Pmkd27Nqqy&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Limitations of Embedding as Inheritance&lt;/h3&gt;
&lt;p&gt;In comparison to a language like Java, Go's form of inheritance is quite
limited. There are multiple designs which can be easily accomplished in Java
which are not possible in Go. Let's look at some of them.&lt;/p&gt;
&lt;h4&gt;Overriding Methods&lt;/h4&gt;
&lt;p&gt;In the pet example above, &lt;code&gt;Dog&lt;/code&gt; "overrides" the &lt;code&gt;Speak()&lt;/code&gt; method. However, if
&lt;code&gt;Pet&lt;/code&gt; had another method &lt;code&gt;Play()&lt;/code&gt; which invokes &lt;code&gt;Speak()&lt;/code&gt; that &lt;code&gt;Dog&lt;/code&gt; does not
override the &lt;code&gt;Dog&lt;/code&gt;'s implementation of &lt;code&gt;Speak()&lt;/code&gt; would not be used:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it on the playground: &lt;a href="https://play.golang.org/p/id-aDKW8L6"&gt;https://play.golang.org/p/id-aDKW8L6&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Contrast this to Java, in Java it would work as expected!&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;extends&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %s and I am a %s&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;javac&lt;span class="w"&gt; &lt;/span&gt;Main.java&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;java&lt;span class="w"&gt; &lt;/span&gt;Main
spot
my&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;spot&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;pointer
my&lt;span class="w"&gt; &lt;/span&gt;name&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;spot&lt;span class="w"&gt; &lt;/span&gt;and&lt;span class="w"&gt; &lt;/span&gt;I&lt;span class="w"&gt; &lt;/span&gt;am&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is a pretty big difference as it essentially precludes the use of abstract
methods as you might want to define them. However, there is a work around:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it on the playground &lt;a href="https://play.golang.org/p/9iIb2px7jH"&gt;https://play.golang.org/p/9iIb2px7jH&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, it works "as expected" but it is much more verbose and difficult than in
Java. You manually have to override the method yourself. Furthermore, it is
rather fragile because if the struct is initialized incorrectly it will crash
when &lt;code&gt;Speak()&lt;/code&gt; is called because &lt;code&gt;speaker()&lt;/code&gt; will not have been correctly
initialized.&lt;/p&gt;
&lt;h4&gt;Subtyping&lt;/h4&gt;
&lt;p&gt;In Java, when the class &lt;code&gt;Dog&lt;/code&gt; extends &lt;code&gt;Pet&lt;/code&gt; it &lt;em&gt;is&lt;/em&gt; a &lt;code&gt;Pet&lt;/code&gt;. That means in every
place you need an object of type &lt;code&gt;Pet&lt;/code&gt; you can use a &lt;code&gt;Dog&lt;/code&gt; object. &lt;code&gt;Dog&lt;/code&gt; is
said to &lt;em&gt;substitute&lt;/em&gt; for &lt;code&gt;Pet&lt;/code&gt;. This relationship is known as &lt;em&gt;subtyping&lt;/em&gt; (&lt;code&gt;Dog&lt;/code&gt;
is a &lt;em&gt;subtype&lt;/em&gt; of &lt;code&gt;Pet&lt;/code&gt;). This relationship is also called subtype polymorphism
and it does not exist in the Go programming language for &lt;code&gt;struct&lt;/code&gt; types.&lt;/p&gt;
&lt;p&gt;Let's look at an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it out on the playground &lt;a href="https://play.golang.org/p/e1Ujx0VhwK"&gt;https://play.golang.org/p/e1Ujx0VhwK&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;prog&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;go&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;62&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;cannot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;argument&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, not all is lost because subtyping does exist for &lt;code&gt;interface&lt;/code&gt; types!
Let's try it out:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Breed&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewPet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;my name is %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speaker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;dog&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;%v and I am a %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;speak&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;breed&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Pet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;NewDog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;spot&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;pointer&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Speak&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Play&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;d&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it on the playground &lt;a href="https://play.golang.org/p/WMH-cr4AJf"&gt;https://play.golang.org/p/WMH-cr4AJf&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;spot
my name is spot and I am a pointer
my name is spot and I am a pointer
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Thus, &lt;code&gt;interface&lt;/code&gt;s can be used to acheive a form of subtyping. However, if they
do not change the equation on method overriding. If you want a method overridden
correctly you still have to use the "trick" I presented above.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;So it turns out, while it isn't a headline feature of Go, its ability for
&lt;code&gt;struct&lt;/code&gt;s to embed &lt;code&gt;struct&lt;/code&gt; pointers, &lt;code&gt;struct&lt;/code&gt;s, and &lt;code&gt;interface&lt;/code&gt;s is powerful
and flexible. It allows innovative designs that can solve real problems.
However, in comparison to Java it is limited because of a lack of direct support
for subtyping and method overriding. It does contain one feature that Java does
not, the ability to embed an &lt;code&gt;interface&lt;/code&gt;. For more details on embedding checkout
the &lt;a href="https://golang.org/doc/effective_go.html#embedding"&gt;Embedding&lt;/a&gt; section of
&lt;a href="https://golang.org/doc/effective_go.html"&gt;Effective Go&lt;/a&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Thank you to echlebek, Alexander Staubo, spriggan3, and breerly for reading and
providing thoughtful feedback on this post.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Exceptions for Go as a Library</title><link href="https://hackthology.com/exceptions-for-go-as-a-library.html" rel="alternate"/><published>2016-05-19T00:00:00-04:00</published><updated>2016-05-19T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2016-05-19:/exceptions-for-go-as-a-library.html</id><summary type="html">&lt;p&gt;Go (golang) lacks support for exceptions found in many other languages. There
are good reasons for Go to not include exceptions. For instance, by making
error handling explicit the programmer is forced to think concretely about
the correct action to take. Fined grained control over the handling of errors
using …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Go (golang) lacks support for exceptions found in many other languages. There
are good reasons for Go to not include exceptions. For instance, by making
error handling explicit the programmer is forced to think concretely about
the correct action to take. Fined grained control over the handling of errors
using multiple return parameters is one of Go's strengths.&lt;/p&gt;
&lt;p&gt;However, there are cases where Go programs do not universally benefit from
the explicit handling of errors. For instance, consider the following code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If Go had exceptions such code could be easily simplified:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;throws&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Adding Exceptions with a Library&lt;/h3&gt;
&lt;p&gt;I created a &lt;a href="https://github.com/timtadh/data-structures/exc"&gt;library&lt;/a&gt; which adds
support for exceptions to the go programming language.  This library allow you
to write go with exceptions and try-catch-finally blocks. It is not appropriate
for all situations but can simplify some application code. Libraries and
external APIs should continue to conform to the Go standard of returning error
values.&lt;/p&gt;
&lt;p&gt;Here is an example of the &lt;code&gt;DoStuff&lt;/code&gt; function where foo, bar and baz all throw
exceptions instead of returning errors. (We will look at the case where they
return errors that you want to turn into exceptions next). We want DoStuff to
be an public API function and return an error:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Catch Blocks&lt;/h4&gt;
&lt;p&gt;Now let's consider the case where we want to catch the exception log and
reraise it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Rethrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rethrow after logging&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Rethrow will chain the Throwable &lt;code&gt;t&lt;/code&gt; with the new &lt;code&gt;*Error&lt;/code&gt; created such that
if/when the exception reaches the top level you know exactly how it was
created and where it was re-thrown.&lt;/p&gt;
&lt;h4&gt;Throwing Errors&lt;/h4&gt;
&lt;p&gt;Ok, what about interacting with regular Go APIs which return errors? How can
we turn those errors into exceptions? The easy was is to use the
&lt;code&gt;ThrowOnError&lt;/code&gt; function which is a sugar for:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ThrowErr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;ErrorFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So converting out original &lt;code&gt;DoStuff&lt;/code&gt; function we get&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// Throws&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This package also supports: catching user defined exceptions, catching
multiple exception types, &lt;code&gt;Close&lt;/code&gt; which works like the "try with resources"
construct in Java 7+, (multiple) finally blocks, and a choice between
propagating exceptions with &lt;code&gt;Unwind&lt;/code&gt; or retrieving the error/exception with
&lt;code&gt;Error&lt;/code&gt; and &lt;code&gt;Exception&lt;/code&gt; functions.&lt;/p&gt;
&lt;p&gt;One Gotcha! The &lt;code&gt;Try()&lt;/code&gt; function creates a &lt;code&gt;*Block&lt;/code&gt; struct. To execute the
block you must either call: &lt;code&gt;Unwind&lt;/code&gt;, &lt;code&gt;Error&lt;/code&gt;, or &lt;code&gt;Exception&lt;/code&gt;. &lt;code&gt;Unwind&lt;/code&gt;
executes the block, if there is an exception coming out of the block it
continues to cause the program stack unwind. &lt;code&gt;Error&lt;/code&gt; and &lt;code&gt;Exception&lt;/code&gt; execute
the block, but return the exception as a value to deal with in the usual Go
way.&lt;/p&gt;
&lt;h4&gt;Finally Blocks&lt;/h4&gt;
&lt;p&gt;Finally blocks are a great feature of exceptions. They allow you to have a block
of code run unconditionally after a try and catch block even if there was an
un-handled exception or re-raised exception. In this example I use a finally
block to log the timing information of the DoStuff function.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;DoStuff&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;baz&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;y&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Rethrow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;rethrow after logging&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Finally&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;time&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Do stuff took: %v&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;end&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;start&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Automatically Closing Resources&lt;/h4&gt;
&lt;p&gt;One common situation is to open a resource (like a file) and want it to close no
matter what. In Go this is often accomplished with a &lt;code&gt;defer&lt;/code&gt; function. However,
we can accomplish the same thing with finer granularity using the &lt;code&gt;Close&lt;/code&gt;
function which acts like a &lt;code&gt;Try&lt;/code&gt; but automatically closes a created resource
when the block exits:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Closer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;/tmp/wizard&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Closer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;f&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WriteString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;wizardry&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ThrowOnError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Unwind&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In the above code, the file created in the first function will always be closed
at the end of the *Block even if WriteString had an error. This get more
interesting if you imagine passing the resource to other functions which could
throw exceptions.&lt;/p&gt;
&lt;h4&gt;User Defined Exception Types&lt;/h4&gt;
&lt;p&gt;To create a user defined exception simply create a struct which inherits from
the &lt;code&gt;exc.Exception&lt;/code&gt; struct by embedding it as the first member.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;MyException&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can catch &lt;em&gt;MyException with &lt;/em&gt;Exception. eg:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;MyException&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;My Exception&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;()})&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Exception&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;caught!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;Unwind&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This should work with heirarchies of exceptions allowing your code to declare
specific exceptions for specific errors.&lt;/p&gt;
&lt;h3&gt;How does it work?&lt;/h3&gt;
&lt;p&gt;Go provides &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;recover&lt;/code&gt; as &lt;a href="https://golang.org/ref/spec#Handling_panics"&gt;built-in
functions&lt;/a&gt;. &lt;code&gt;panic(.)&lt;/code&gt; allows you
to cause the program to halt and the stack to "unwind". This means stack frame
by stack frame the each function is halted and any deferred functions are run.
Let's look at an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c panic&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="n"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;
&lt;span class="n"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="nl"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;panic&lt;/span&gt;

&lt;span class="n"&gt;goroutine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;running&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;
&lt;span class="n"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mh"&gt;0x128360&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mh"&gt;0x1040a140&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;local&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;runtime&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;481&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x700&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox797297488&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;28&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x180&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox797297488&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x140&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox797297488&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x140&lt;/span&gt;
&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;tmp&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sandbox797297488&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;main&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mh"&gt;0x20&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it on the playground &lt;a href="https://play.golang.org/p/0Vp4jq0978"&gt;https://play.golang.org/p/0Vp4jq0978&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;So panic by default kills your program but gives you a nice stack trace. It also
runs your &lt;code&gt;defer&lt;/code&gt;ed functions which allows some cleanup to happen. Recognizing
this was rather limited and their are times even in Go when it is nice to
recover from what is usually a fatal error (like in webservers) Go also provides
&lt;code&gt;recover&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;recover&lt;/code&gt; function can be thought of as a limited panic catching function.
It can only meaingfully be used inside of defer functions. When a &lt;code&gt;recover&lt;/code&gt; is
found it will stop the panic (that is stop unwinding the stack) and allow the
function the &lt;code&gt;defer&lt;/code&gt;ed &lt;code&gt;recover&lt;/code&gt; is in to exit normally. Let's look at another
example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c panic&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;start&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;start&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Try it on the playground: &lt;a href="https://play.golang.org/p/WTzKywhey2"&gt;https://play.golang.org/p/WTzKywhey2&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This time, instead of the program crashing it exited normally. Functions, &lt;code&gt;a&lt;/code&gt;
and &lt;code&gt;main&lt;/code&gt;, who invocations occurred before &lt;code&gt;b&lt;/code&gt; which invoked &lt;code&gt;recover&lt;/code&gt; exited
normally. However, using recover like this will stop all errors and not explain
what the problem is. Luckily, recover reports whether or not a panic was
recovered and what the argument to the panic was. Here is an example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;recovered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end defer of a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;recovered&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end defer of b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;defer c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c panic&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;start&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;end&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;start&lt;/span&gt;
&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="nv"&gt;recovered&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;panic&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;b&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;a&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(Try it on the playground: &lt;a href="https://play.golang.org/p/agxBcqgCb8"&gt;https://play.golang.org/p/agxBcqgCb8&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This time the value passed into panic was returned by the call to &lt;code&gt;recover&lt;/code&gt; in
&lt;code&gt;b&lt;/code&gt;. In &lt;code&gt;a&lt;/code&gt; which contains the same code as &lt;code&gt;b&lt;/code&gt; to recover the panic nothing is
returned by &lt;code&gt;recover&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Implementation&lt;/h4&gt;
&lt;p&gt;To implement exceptions, &lt;code&gt;panic&lt;/code&gt; is used to throw the &lt;code&gt;Throwable&lt;/code&gt; objects. Then
a special function &lt;code&gt;exec&lt;/code&gt; is created to execute the &lt;code&gt;try&lt;/code&gt; functions:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;defer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;recover&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;exc&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;try&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This function simply calls the function passed into &lt;code&gt;Try()&lt;/code&gt;. However, &lt;code&gt;exec&lt;/code&gt; also
registers a &lt;code&gt;defer&lt;/code&gt; which changes the returned value of &lt;code&gt;exec&lt;/code&gt; if a &lt;code&gt;Throwable&lt;/code&gt;
is discovered. Thus, we can throw exceptions with &lt;code&gt;panic&lt;/code&gt; (no changes
necessary!) and catch them with &lt;code&gt;recover&lt;/code&gt;. The final piece is implementing the
semantics of try, catch, finally. This is accomplished by a function called
&lt;code&gt;run&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Throwable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;reflect&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TypeOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catches&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;isa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exception&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Try&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)}).&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;finally&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;finallies&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;run&lt;/code&gt; function first executes the &lt;code&gt;try&lt;/code&gt; and gets the error if any. If there
is an error it tries to find a catch function to handle it (using the &lt;code&gt;isa&lt;/code&gt;
helper function to identify the catcher). Then whether or not a catch function
was found, all &lt;code&gt;finally&lt;/code&gt; functions are run in order of declaration. The final
trick is the &lt;code&gt;catch&lt;/code&gt; functions are run inside of a &lt;code&gt;Try&lt;/code&gt; block and &lt;code&gt;exec&lt;/code&gt;
directly in case they re-throw exceptions. That is it! Check out the &lt;a href="https://github.com/timtadh/data-structures/tree/master/exc"&gt;source
code&lt;/a&gt; for more
details.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;There are good reasons why Go does not include exceptions at the language level.
However, at times their absence can become annoying. So I created this little
library that adds them to Go. You probably shouldn't make public APIs based on
it, but it may help you write certain internal code more clearly. One clear use
case is during a refactor adding &lt;code&gt;Throw&lt;/code&gt; call in a deep internal function which
should have always returned an error. Then at the entry points to the API simply
wrap up in a &lt;code&gt;Try().Catch().Error()&lt;/code&gt; which would accomplish the same thing as
adding a returned error throughout the library.&lt;/p&gt;
&lt;p&gt;I hope you enjoy this little experiment of mine and don't send me too much hate
mail! I know that exceptions are controversal in the Go community. This library
tries to demonstrate how close &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;recover&lt;/code&gt; are to exceptions and how
to emulate exceptions using &lt;code&gt;panic&lt;/code&gt; and &lt;code&gt;recover&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/timtadh/data-structures/tree/master/exc"&gt;Check it out!&lt;/a&gt;.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>First Rust Macro</title><link href="https://hackthology.com/first-rust-macro.html" rel="alternate"/><published>2014-09-20T00:00:00-04:00</published><updated>2014-09-20T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-09-20:/first-rust-macro.html</id><summary type="html">&lt;p&gt;I started learning &lt;a href="http://www.rust-lang.org/"&gt;Rust&lt;/a&gt; yesterday. Today as I was
writing input handling code I wanted to print to the standard err. The way to do
that seems to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;writeln!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;write to stderr failed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That seems a bit verbose to me versus printing to the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I started learning &lt;a href="http://www.rust-lang.org/"&gt;Rust&lt;/a&gt; yesterday. Today as I was
writing input handling code I wanted to print to the standard err. The way to do
that seems to be:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;writeln!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;write to stderr failed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;That seems a bit verbose to me versus printing to the standard out, which is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So I decided to fix that with the following macro:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="fm"&gt;macro_rules!&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="cp"&gt;$fmt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="cp"&gt;$(,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;expr&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="fm"&gt;writeln!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;stderr&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$fmt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$(,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="cp"&gt;$msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;log failed&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which you can use like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;{}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;expected {} got {}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expected&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;actual&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Scala Notes</title><link href="https://hackthology.com/scala-notes.html" rel="alternate"/><published>2014-08-18T00:00:00-04:00</published><updated>2014-08-18T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-08-18:/scala-notes.html</id><summary type="html">&lt;p&gt;My notes as I relearn Scala. I am reading through &lt;a href="http://www.worldcat.org/title/programming-in-scala/oclc/731510960"&gt;Programming in Scala (2nd
ed.)&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Quibble with the Functional List&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;gt; &lt;em&gt;from page 43&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Why not append to lists?&lt;/h3&gt;
&lt;p&gt;Class &lt;code&gt;List&lt;/code&gt; does offer an append operation -- it's written &lt;code&gt;:+&lt;/code&gt; and is
explained in Chapter 24 -- but this operation is rarely used, because …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;My notes as I relearn Scala. I am reading through &lt;a href="http://www.worldcat.org/title/programming-in-scala/oclc/731510960"&gt;Programming in Scala (2nd
ed.)&lt;/a&gt;&lt;/p&gt;
&lt;h1&gt;Quibble with the Functional List&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;gt; &lt;em&gt;from page 43&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Why not append to lists?&lt;/h3&gt;
&lt;p&gt;Class &lt;code&gt;List&lt;/code&gt; does offer an append operation -- it's written &lt;code&gt;:+&lt;/code&gt; and is
explained in Chapter 24 -- but this operation is rarely used, because the time
it takes to append to a list grows linearly with the size of the list, whereas
prepending with &lt;code&gt;::&lt;/code&gt; take constant time. Your options if you want to build a
list efficiently by append elements is to prepend them, then when you're done
call &lt;code&gt;reverse&lt;/code&gt;; or use a &lt;code&gt;ListBuffer&lt;/code&gt; a mutable list that does offer an
&lt;code&gt;append&lt;/code&gt; operation, and when you're done call &lt;code&gt;toList&lt;/code&gt;. &lt;code&gt;ListBuffer&lt;/code&gt; will be
described in Section 22.2.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I have always found the functional linked list to be a bit of an anachronism
when appearing as core concept in a modern language. It is a limited data
structure in terms of functionality, especially when compared to it
non-functional mutable counter part (the doubly linked list with pointers to the
head and the tail). The mutable doubly linked list can prepend, append, and swap
elements in constant time. This makes it a highly useful data structure for a
variety of tasks, including the wonderful Least Recently Used (LRU) cache
replacement algorithm. In comparison, the traditional functional list of &lt;code&gt;cons&lt;/code&gt;
cells really only supports constant time prepend.&lt;/p&gt;
&lt;p&gt;Scala should provide a immutable list implementation with all of the features
one can expect of an ArrayList, such as the one found in Python or Ruby. Like
the Python or Ruby list Scala can simply refer to the list as &lt;code&gt;list&lt;/code&gt; and
provide details about the algorithms used to achieve the functionality as
documentation. In fact a quick Google reveals Scala has such a structure and it
calls it a &lt;code&gt;Vector&lt;/code&gt;. Why not simply call the &lt;code&gt;Vector&lt;/code&gt; a &lt;code&gt;list&lt;/code&gt;? Or at least
introduce &lt;code&gt;Vector&lt;/code&gt;s as the primary list like structure to use.&lt;/p&gt;
&lt;p&gt;Using the &lt;code&gt;List&lt;/code&gt; class as the example general purpose container type is just
asking for trouble. Beginners would be better served by being introduced to
&lt;code&gt;Vector&lt;/code&gt; or a similar structure right away.&lt;/p&gt;
&lt;p&gt;Other than this quibble about the book, I think the Scala &lt;a href="https://github.com/scala/scala/tree/v2.11.2/src/library/scala/collection/"&gt;collections
library&lt;/a&gt;
is great. A wide variety of data-structures with solid implementations.&lt;/p&gt;
&lt;h1&gt;Values vs. Variables&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;gt; &lt;em&gt;from page 62&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;sup&gt;1&lt;/sup&gt; The reason parameters are &lt;code&gt;vals&lt;/code&gt; is that &lt;code&gt;vals&lt;/code&gt; are easier to
reason about. You needn't look further to determine if a &lt;code&gt;val&lt;/code&gt; is reassigned,
as you must do with a &lt;code&gt;var&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Perfectly true, but why should I care? The compiler will have no trouble
determining whether or not a &lt;code&gt;var&lt;/code&gt; is re-assigned. In fact if this was an
imperative language the first step of the optimizer would likely be to convert
the code into Single Static Assignment (SSA) form. Once in (SSA) form every
variable has exactly one definition and code re-arrangement optimizations can
proceed without difficulty.&lt;/p&gt;
&lt;p&gt;So using &lt;code&gt;vals&lt;/code&gt; instead of &lt;code&gt;vars&lt;/code&gt; must be for &lt;em&gt;(in)&lt;/em&gt;convenience of the
programmer. Scala does recommend using &lt;code&gt;val&lt;/code&gt; over &lt;code&gt;var&lt;/code&gt; when possible. So the
choice is consistent with the philosophy of the language.&lt;/p&gt;
&lt;p&gt;My question is why prioritize the immutable against the mutable? The benefits of
this choice are not clearly explained. It is true that it is easier to write
certain proofs if you don't have to deal with changing data on the heap however
today we have the (mathematical) tools to deal with that situation.  There are
real benefits of mutable data-structures and algorithms, state mutation can be
very efficient. For instance, the &lt;a href="http://en.wikipedia.org/wiki/Disjoint-set_data_structure"&gt;Union-Find
algorithm&lt;/a&gt; has a
straight forward and optimal imperative implementation. It is significantly
harder to achieve an optimal immutable version as demonstrated by &lt;a href="https://www.lri.fr/~filliatr/ftp/publis/puf-wml07.pdf"&gt;this paper
from 2007&lt;/a&gt;.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Always Go To Editable Command Mode in Vim</title><link href="https://hackthology.com/always-go-to-editable-command-mode-in-vim.html" rel="alternate"/><published>2014-06-06T00:00:00-04:00</published><updated>2014-06-06T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-06-06:/always-go-to-editable-command-mode-in-vim.html</id><summary type="html">&lt;p&gt;A useful trick in vim is an editable command mode with previous commands in the
buffer. To get to this mode go to normal mode (ie. hit ESC) and then type &lt;code&gt;q:&lt;/code&gt;
this places you in editable command mode. If you always want to go to that mode
you can …&lt;/p&gt;</summary><content type="html">&lt;p&gt;A useful trick in vim is an editable command mode with previous commands in the
buffer. To get to this mode go to normal mode (ie. hit ESC) and then type &lt;code&gt;q:&lt;/code&gt;
this places you in editable command mode. If you always want to go to that mode
you can remap &lt;code&gt;:&lt;/code&gt; with the following command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;quot; Always go to history mode&lt;/span&gt;
&lt;span class="nb"&gt;nnoremap&lt;/span&gt; : &lt;span class="k"&gt;q&lt;/span&gt;:&lt;span class="k"&gt;i&lt;/span&gt;
&lt;span class="nb"&gt;nnoremap&lt;/span&gt; &lt;span class="sr"&gt;/ q/&lt;/span&gt;&lt;span class="k"&gt;i&lt;/span&gt;
&lt;span class="nb"&gt;nnoremap&lt;/span&gt; ? &lt;span class="k"&gt;q&lt;/span&gt;?&lt;span class="k"&gt;i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Happy Hacking!&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Private Methods and Functions Should be Tested</title><link href="https://hackthology.com/private-methods-and-functions-should-be-tested.html" rel="alternate"/><published>2014-03-20T00:00:00-04:00</published><updated>2014-03-20T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-03-20:/private-methods-and-functions-should-be-tested.html</id><summary type="html">&lt;p&gt;Recently I became engaged in a debate around whether or not private methods
should usually have unit tests. Rather than writing up a quick off hand reply to
the question I decided to write up a detailed stance on the matter.&lt;/p&gt;
&lt;h1&gt;Testing Theory&lt;/h1&gt;
&lt;p&gt;Why is software tested? It is tested …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Recently I became engaged in a debate around whether or not private methods
should usually have unit tests. Rather than writing up a quick off hand reply to
the question I decided to write up a detailed stance on the matter.&lt;/p&gt;
&lt;h1&gt;Testing Theory&lt;/h1&gt;
&lt;p&gt;Why is software tested? It is tested for two reasons:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To reveal defects and deviations from a &lt;strong&gt;specification&lt;/strong&gt;. Does the software
   function properly? This is called Software &lt;strong&gt;Verification&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;To ensure the software meets the needs of the end user. Are we meeting the
   needs of our users? This is called Software &lt;strong&gt;Validation&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To validate software, engineers employ a variety of techniques such as user
testing, case studies on user needs, surveys, runtime observations, alpha/beta
testing, and acceptance testing. These techniques not only look for bugs and
defects in the software but also try and understand whether it effectively
solves problems for the user. This process informs the iterative development of
the software and can lead to changes in functional requirements.&lt;/p&gt;
&lt;p&gt;In order to verify the correct functioning of software, engineers check the
software to ensure it satisfies the specification. A specification states how
the software should function. Unfortunately, a complete and accurate
specification never exists. Engineers carefully determine what to check and based
on their estimations on the accuracy and completeness of a specification.&lt;/p&gt;
&lt;p&gt;The modern engineer has many techniques that can be used to verify software.
Broadly they fit into two categories: testing and program analysis. Program
analysis uses various techniques to prove specific properties about a program.
For exampled, in statically type checked languages (such as Java or Haskell) the
type checker proves the absence of type errors. I will not discuss these
techniques in this essay as there availability varies by language and
environment.&lt;/p&gt;
&lt;p&gt;Testing runs a program with specified inputs and checks that the result is
correct. It is the primary way software is verified. While the advanced program
analysis techniques are neat almost all software should be rigorously tested.
Well what does "rigorously" mean. If software is rigorously tested does that then
mean: the software will be dependable (and/or correct)?&lt;/p&gt;
&lt;p&gt;Unfortunately, no matter what techniques are used to test software, tests can
never ensure software is correct. However, it can give the development team
confidence (with the right techniques) in the dependability of the software.&lt;/p&gt;
&lt;h2&gt;Rigorous Testing&lt;/h2&gt;
&lt;p&gt;What are some suitable criteria that can be used to determine if a test suite is
adequate for verifying the software? Designing a adequate testing criteria has
many pitfalls. Consider the following requirement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A test suite must cover (execute) every statement in the program.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This requirement only looks useful. For instance, it doesn't say that the
individual tests should check each component functioned properly. Rather, it
only says that the component was executed.&lt;/p&gt;
&lt;p&gt;The abstract requirements I often use for tests at the unit (function or method
level) is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;A method should checked that it behaves properly in both nominal and
   exceptional cases.&lt;/li&gt;
&lt;li&gt;If a model of how the method should function is available it should be
   checked against that model.&lt;/li&gt;
&lt;li&gt;Path coverage, how many control flow paths through a method are taken, can be
   used a heuristic to guide the tester towards methods which may require
   further testing.&lt;/li&gt;
&lt;li&gt;When required methods should be checked for security and language level
   faults such as: buffer overflows, SQL injection errors, cross site scripting
   errors, etc...&lt;/li&gt;
&lt;li&gt;Public methods should be checked against all elements of their specified API
   contract.&lt;/li&gt;
&lt;li&gt;Unit tests should assume the methods used by the method under test behave
   correctly if each of those methods has good tests.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These requirements will not ensure that a program has no bugs. However, it gives
confidence that all methods in the program work properly because it forces the
programmer to think about how each method should work. Not only think about it,
but think how to test it, how to to check every control flow path, how to check
all parts of the specified API. By engaging the programmer in this way bugs can
be caught not only in the method but in the specification for the method.&lt;/p&gt;
&lt;h1&gt;Should Private Methods be Tested?&lt;/h1&gt;
&lt;p&gt;According to my theory on testing methods at the unit level &lt;em&gt;private methods
should be tested&lt;/em&gt;. My theory has the inductive hypothesis that methods used by a
method under test can only be assumed to work if each of those methods has good
tests.  If that hypothesis is not met, one loses confidence in the test suite.
Furthermore, the programmer is no longer forced to think critically about the
function of every method.&lt;/p&gt;
&lt;p&gt;I have received some important counter points to this point of view. I am going
to address those individually.&lt;/p&gt;
&lt;h3&gt;If private methods are tested then how can we locate dead code?&lt;/h3&gt;
&lt;p&gt;One can solve this problem in several ways. My recommendation is to mark tests
for private methods in such a way that they can be excluded from test suite
runs.&lt;/p&gt;
&lt;h3&gt;Tests on private methods make the test suite brittle&lt;/h3&gt;
&lt;p&gt;Here the tester needs to use their best judgement on whether the specification
on some area is in too much flux to formalize a test. They should also use their
judgement on what to check. If the output format is likely to change rather than
checking the output exactly matches some expected output one should check that
the output has certain properties.&lt;/p&gt;
&lt;h4&gt;negative example&lt;/h4&gt;
&lt;p&gt;This test is very brittle. Slight changes to the code can easily break by
re-ordering fields or adding and removing them.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;edge {\&amp;quot;src\&amp;quot;:0,\&amp;quot;targ\&amp;quot;:1,\&amp;quot;label\&amp;quot;:\&amp;quot;cfg\&amp;quot;,\&amp;quot;src_label\&amp;quot;:\&amp;quot;a\&amp;quot;,\&amp;quot;targ_label\&amp;quot;:\&amp;quot;b\&amp;quot;}&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Graph&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cfg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;positive example&lt;/h4&gt;
&lt;p&gt;This test is better because it looks for just the properties of the
serialization which are important (the source, target, and edge label are set
correctly).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Graph&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Graph&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;a&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;b&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addNode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;x.y&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;c&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;m&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;t&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;Edge&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Edge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;cfg&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;Serialize&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\&amp;quot;src\&amp;quot;:0&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\&amp;quot;targ\&amp;quot;:1&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;assertThat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;E&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="na"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;\&amp;quot;label\&amp;quot;:\&amp;quot;cfg\&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Testing private methods pulls away from BDD&lt;/h3&gt;
&lt;p&gt;BDD (Behavior Driven Development), tries to help projects stay on target by
keeping them aligned to user needs.  In this sense it is a validation technique
which integrates validation into the development process. However, high level
behavioural tests rely on the software underneath the high level functionality
functioning properly. Verification of that functionality is needed regardless of
its relationship to customer requirements.&lt;/p&gt;
&lt;p&gt;For instance a customer would never specify that items from a sorted array
should be retrieved with a binary search. But, if a programmer needs to retrieve
an item from a sorted array and uses a binary search that search must work in
order to meet whatever functional requirement the programmer is implementing.
Furthermore, security requirements are typically not functional or behavioural
but none the less they must be checked.&lt;/p&gt;
&lt;p&gt;Testing private methods and methods which implement basic functionality does not
conflict with BDD it enables it.&lt;/p&gt;
&lt;h3&gt;Testing private methods is time consuming&lt;/h3&gt;
&lt;p&gt;It is often difficult to know when the proper time is to write a test for a
method. TDD (Test Driven Development) advocates for writing tests before a
method is written. The TDD method can be useful in some circumstances but I
would not advocate for universal application of it. I will give the advice that
it is easier to write a test for a method at the time of development rather than
later on. If the method needs to be modified in some way later on (especially in
a way that does not break existing functionality) then the tests serve as a
"safety belt" when extending it. If the change to the method changes existing
functionality then the old tests can be safely deleted (but new tests should
likely be created).&lt;/p&gt;
&lt;p&gt;I don't think testing private methods is in particular time consuming. Rather,
program verification and validation is in general time consuming. However,
performing these activities is what separates high quality software from low
quality software.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>How to Re-Use a Sub-Project's Buildfile in Apache Buildr</title><link href="https://hackthology.com/how-to-re-use-a-sub-projects-buildfile-in-apache-buildr.html" rel="alternate"/><published>2014-03-14T00:00:00-04:00</published><updated>2014-03-14T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-03-14:/how-to-re-use-a-sub-projects-buildfile-in-apache-buildr.html</id><summary type="html">&lt;p&gt;&lt;a href="http://buildr.apache.org"&gt;Apache Buildr&lt;/a&gt; is a nice build system for Java and
other JVM langauges. It is based on Ruby's Rake system and makes it easy to
setup a multi-project build. However, by default, there is no support for
re-using a &lt;code&gt;Buildfile&lt;/code&gt; from another project.  The intreprepid hacker can fix that
problem …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://buildr.apache.org"&gt;Apache Buildr&lt;/a&gt; is a nice build system for Java and
other JVM langauges. It is based on Ruby's Rake system and makes it easy to
setup a multi-project build. However, by default, there is no support for
re-using a &lt;code&gt;Buildfile&lt;/code&gt; from another project.  The intreprepid hacker can fix that
problem by loading the sub-project's &lt;code&gt;Buildfile&lt;/code&gt; like this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;exists?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sub-project/Buildfile&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sub-project&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;load&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;./Buildfile&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;project&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sub-project&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_dir&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;## HACK: pins the project to the&lt;/span&gt;
&lt;span class="w"&gt;                                        &lt;/span&gt;&lt;span class="c1"&gt;## proper directory!&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="no"&gt;Dir&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;pwd&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you don't access &lt;code&gt;base_dir&lt;/code&gt; before you reset the current working directory
then it will eventually get set to the wrong directory causing build failures.&lt;/p&gt;
&lt;p&gt;After you have loaded the &lt;code&gt;Buildfile&lt;/code&gt; you can run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;
/path/to/project
$&lt;span class="w"&gt; &lt;/span&gt;buildr&lt;span class="w"&gt; &lt;/span&gt;help:projects
&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/path/to/project,&lt;span class="w"&gt; &lt;/span&gt;development&lt;span class="o"&gt;)&lt;/span&gt;
/path/to/project/sub-project
&lt;span class="w"&gt;  &lt;/span&gt;main-project
&lt;span class="w"&gt;  &lt;/span&gt;sub-project
&lt;span class="w"&gt;  &lt;/span&gt;other-project
&lt;span class="w"&gt;  &lt;/span&gt;another-project
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;All of the tasks from you sub-project should now work as expected from the
parent project. Happy Buildring!&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Vi Mode in Python Shell, IRB, and Elsewhere!</title><link href="https://hackthology.com/vi-mode-in-python-shell-irb-and-elsewhere.html" rel="alternate"/><published>2014-02-04T00:00:00-05:00</published><updated>2014-02-04T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2014-02-04:/vi-mode-in-python-shell-irb-and-elsewhere.html</id><content type="html">&lt;p&gt;Enable vi mode in irb, python shell, and other readline based systems:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cat&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;gt;~/&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;inputrc&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;vi&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;set&lt;/span&gt; &lt;span class="n"&gt;editing&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mode&lt;/span&gt; &lt;span class="n"&gt;vi&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kr"&gt;END&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now everything has vi key bindings! You are welcome.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Functional Iteration in Go</title><link href="https://hackthology.com/functional-iteration-in-go.html" rel="alternate"/><published>2013-12-13T00:00:00-05:00</published><updated>2013-12-13T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-12-13:/functional-iteration-in-go.html</id><summary type="html">&lt;p&gt;Go provides a built in way to iterate easily over built-in collection types:
&lt;code&gt;maps&lt;/code&gt;, &lt;code&gt;slices&lt;/code&gt; and &lt;code&gt;chans&lt;/code&gt;. Iterating with these types is much like iterating
using for-each type loops in languages like Python, Ruby and Java.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// key, value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// index, item …&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</summary><content type="html">&lt;p&gt;Go provides a built in way to iterate easily over built-in collection types:
&lt;code&gt;maps&lt;/code&gt;, &lt;code&gt;slices&lt;/code&gt; and &lt;code&gt;chans&lt;/code&gt;. Iterating with these types is much like iterating
using for-each type loops in languages like Python, Ruby and Java.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;map&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// key, value&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;slice&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// index, item&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;channel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// item&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Unfortunately, Go does not provide a way to iterate over user defined
collections using range. I have been experimenting with how to solve this
problem since the initial public release of Go and I have finally settled on a
solution I like. This new solution uses a functional programming style.&lt;/p&gt;
&lt;h2&gt;Functional Iterators&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This iterator is a function. Calling the function yields the next item in the
collection and a continuation function pointer. When the continuation function
pointer becomes nil, there are no more items left in the collection. Here's an
example of how to use a functional iterator from a test case in my
&lt;a href="https://github.com/timtadh/data-structures/blob/ab3c41d91c7b569caa0e989c7787de16cca7d10b/tree/avltree_test.go#L206"&gt;data-structures repository&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;9&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;13&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;18&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;19&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tree&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Iterate&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;types&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="p"&gt;]))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wrong key&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;.(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Wrong value&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;j&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The functional approach allows the user to have a nice "linked-list" style
interface while avoiding the problems with using channels to implement
iteration. Using channels make iterators quite easy to write, consider this
post-order traversal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;%v %v&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PostOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;go&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yield&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;chan&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;yield&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;iter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;yield&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}(&lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;ch&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}}}}}}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PostOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it on the playground &lt;a href="http://play.golang.org/p/kUGDQvWhkb"&gt;http://play.golang.org/p/kUGDQvWhkb&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;However, what happens if the consumer of the iterator needs to bail out early?
Like so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PostOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In this case the go-routine &lt;code&gt;PostOrder&lt;/code&gt; is running in will leak. Since, it will
be blocked on sending to the consumer who will never consume the item. The fix
for this is to make the API more complicated by adding two way communication
such that the consuming thread can indicate to the producing thread it no longer
wants any more items. This can be a significant complication as it would be in
the cute little post-order traversal presented above.&lt;/p&gt;
&lt;h2&gt;Functional Iteration to the Rescue (almost)&lt;/h2&gt;
&lt;p&gt;Functional iteration solves several of the problems with iterating using
channels while maintaining an easy to use interface. Because all the code runs
on the same go-routine no go-routines can leak. If a consumer stops using an
iterator the garbage collector can clean it up. In the &lt;code&gt;PostOrder&lt;/code&gt; traversal
above the channel can leak because the producing go-routine maintains a
reference. However, functional iterators are a bit tricky to write. Let's look
at a few from the &lt;a href="https://github.com/timtadh/data-structures"&gt;data-structures
repository&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Hash Table Iteration.&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iterate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KVIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kv_iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KVIterator&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;kv_iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Equatable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KVIterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kv_iterator&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kv_iterator&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;How does the function work? The first thing to notice is the &lt;code&gt;Iterate&lt;/code&gt; function
returns a function &lt;code&gt;kv_iterator&lt;/code&gt; which closes over some state: &lt;code&gt;table&lt;/code&gt;, &lt;code&gt;i&lt;/code&gt; and
&lt;code&gt;e&lt;/code&gt;. The &lt;code&gt;table&lt;/code&gt; variable is the array backing the hash table. The &lt;code&gt;i&lt;/code&gt; variable
refers to which bucket is currently being examined. Finally, the &lt;code&gt;e&lt;/code&gt; variable
refers to which entry in the bucket is next to be returned to the consumer.&lt;/p&gt;
&lt;p&gt;When the consumer calls the &lt;code&gt;kv_iterator&lt;/code&gt; function for the first time &lt;code&gt;e&lt;/code&gt; will
be &lt;code&gt;nil&lt;/code&gt; and the top loop will run until and entry is found or it has run
through the entire table. When and entry is found, the key and value are stored
and &lt;code&gt;e&lt;/code&gt; is set to &lt;code&gt;e.next&lt;/code&gt;. This assignment modifies the closed state of
&lt;code&gt;kv_iterator&lt;/code&gt; and will be preserved on the next call to &lt;code&gt;kv_iterator&lt;/code&gt;. Finally,
&lt;code&gt;key&lt;/code&gt;, &lt;code&gt;val&lt;/code&gt; and &lt;code&gt;kv_iterator&lt;/code&gt; are returned to the consumer.&lt;/p&gt;
&lt;p&gt;The main thing to understand about the &lt;code&gt;kv_iterator&lt;/code&gt; function and all iterators
of this style is they implement a tail-recursive approach to iteration. Thus,
just like writing a tail-recursive function in Scheme or Lisp one must write the
iterator such that no actions need to be taken after the data is returned to the
user. This sometimes gets tricky, for instance in post-order iteration.&lt;/p&gt;
&lt;h3&gt;Post Order Iteration&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;fmt&amp;quot;&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntIterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;String&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Sprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;lt;%v %v&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;PostOrder&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntIterator&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;IntIterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;kid&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;kid&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;tn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iterator&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Node&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;}}}}}}}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;root&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;PostOrder&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;(try it out yourself on the playground &lt;a href="http://play.golang.org/p/M4ivyGL7GM"&gt;http://play.golang.org/p/M4ivyGL7GM&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This time, the iterator must keep a stack of items in order to function. The
top entry contains the next item to process and location in its child list next
to process. The function pops a node, &lt;code&gt;tn&lt;/code&gt;, and child index, &lt;code&gt;i&lt;/code&gt;, off of the
stack. If the node, &lt;code&gt;tn&lt;/code&gt;, has unprocessed children it gets the next child, and
pushes &lt;code&gt;tn&lt;/code&gt; back onto the stack (and increments &lt;code&gt;i&lt;/code&gt;). The child then becomes
&lt;code&gt;tn&lt;/code&gt;. It continues traversing down the left most side of the tree until it gets
to a leaf node. At that point, the function exits the loop and returns the final
value for &lt;code&gt;tn&lt;/code&gt; and the &lt;code&gt;tn_iterator&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The next time the function is called, it will pop the stack and find the parent
of the last node it returned to the consumer. If there are more children of
parent left to processed it will repeat the process described above. Otherwise,
the parent gets returned to the consumer and the stack shrinks.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Functional iterators represent a flexible way to implement generic iterators in
Go. They are easy to use and do not leak resources. There only draw back in
comparison to other approaches is greater difficulty in constructing the
iterators. In order solve this libraries of data-structures and iterator
generators should be constructed.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>How to Compile MySQL's "ON DUPLICATE KEY UPDATE" in SQL Alchemy</title><link href="https://hackthology.com/how-to-compile-mysqls-on-duplicate-key-update-in-sql-alchemy.html" rel="alternate"/><published>2013-12-05T00:00:00-05:00</published><updated>2013-12-05T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-12-05:/how-to-compile-mysqls-on-duplicate-key-update-in-sql-alchemy.html</id><summary type="html">&lt;p&gt;This snippet contains a well tested way to compile an "Upsert" statement for
MySQL in SQL Alchemy. I have found it useful for several project and I am making
it available via this gist for others to enjoy and improve. Unlike some other
examples out there this one supports doing …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This snippet contains a well tested way to compile an "Upsert" statement for
MySQL in SQL Alchemy. I have found it useful for several project and I am making
it available via this gist for others to enjoy and improve. Unlike some other
examples out there this one supports doing a bulk insert.&lt;/p&gt;
&lt;script src="https://gist.github.com/timtadh/7811458.js"&gt;&lt;/script&gt;</content><category term="Blog"/></entry><entry><title>Innovation isn't always the answer.</title><link href="https://hackthology.com/innovation-isnt-always-the-answer.html" rel="alternate"/><published>2013-11-25T00:00:00-05:00</published><updated>2013-11-25T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-25:/innovation-isnt-always-the-answer.html</id><summary type="html">&lt;p&gt;From, &lt;a href="http://www.wired.com/wiredscience/2013/11/vaclav-smil-wired/"&gt;http://www.wired.com/wiredscience/2013/11/vaclav-smil-wired/&lt;/a&gt;, at the
bottom.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;So the answers are not technological but political: better economic
policies, better education, better trade policies.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Right. Today, as you know, everything is "innovation." We have problems, and
people are looking for fairy-tale solutions—innovation like manna from …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;From, &lt;a href="http://www.wired.com/wiredscience/2013/11/vaclav-smil-wired/"&gt;http://www.wired.com/wiredscience/2013/11/vaclav-smil-wired/&lt;/a&gt;, at the
bottom.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;So the answers are not technological but political: better economic
policies, better education, better trade policies.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Right. Today, as you know, everything is "innovation." We have problems, and
people are looking for fairy-tale solutions—innovation like manna from heaven
falling on the Israelites and saving them from the desert. It’s like, "Let's
not reform the education system, the tax system. Let's not improve our
dysfunctional government. Just wait for this innovation manna from a little
group of people in Silicon Valley, preferably of Indian origin."&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You people at WIRED - you're the guilty ones&lt;/em&gt;! You support these people, you
write about them, you elevate them onto the cover! You really messed it up. I
tell you, you pushed this on the American public, right? And people believe it
now.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Dr. Smil is right about education. We cannot "innovate" our way out of poor
educational policy - which is intimately tied up with many of our other
policies. The Massive Online Open Course (MOOC) is the new textbook not the new
classroom. The motivated student could always visit the library. These courses
make material more accessible but the classroom is where the student is not
where the material is. Not every person who needs help will be able to seek it.
To help them you first have to find them, they will not find you.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>The Ruby For Loop</title><link href="https://hackthology.com/the-ruby-for-loop.html" rel="alternate"/><published>2013-11-21T00:00:00-05:00</published><updated>2013-11-21T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-21:/the-ruby-for-loop.html</id><summary type="html">&lt;p&gt;I am taking some time to learn Ruby this fall from &lt;a href="http://www.worldcat.org/title/eloquent-ruby/oclc/676726142"&gt;Eloquent
Ruby&lt;/a&gt;. The second chapter
on choosing the right control structures has this paragraph (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since the two versions of the “print my fonts” code are essentially
equivalent,[1] why prefer one over the other? Mainly it is …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;I am taking some time to learn Ruby this fall from &lt;a href="http://www.worldcat.org/title/eloquent-ruby/oclc/676726142"&gt;Eloquent
Ruby&lt;/a&gt;. The second chapter
on choosing the right control structures has this paragraph (emphasis mine):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Since the two versions of the “print my fonts” code are essentially
equivalent,[1] why prefer one over the other? Mainly it is a question of
eliminating one level of indirection. Ruby actually defines the for loop in
terms of the each method: When you say for font in fonts, Ruby will actually
conjure up a call to fonts.each. Given that the for statement is really a call
to each in disguise, &lt;strong&gt;why not just pull the mask off and write what you
mean?&lt;/strong&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[1] Almost. The code block in the each version actually introduces a new
scope. Any variables introduced into a code block are local to that block
and go away at the end of the block. The more traditional for version of the
loop does not introduce a new scope, so that variables introduced inside a
for are also visible outside the loop.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Why not just pull the mask off?&lt;/h2&gt;
&lt;p&gt;We should not avoid constructs that potentially clarify the meaning of our code
because under the hood they become something else. By that argument one would
always write x86 machine code, memnonic assemblers are not for &lt;em&gt;real&lt;/em&gt;
programmers! Real programmers assemble the code in their heads!&lt;/p&gt;
&lt;p&gt;I think that a for-each loop of the style of Ruby or Python or &lt;code&gt;____&lt;/code&gt; are a very
clear idiom. It reads nicely, every programmer who has a background in a C
family language will know instantly what you mean. I don't see any benefit in
avoiding the for loop in Ruby any more than I can see benefit in avoiding in C
when I could be using a goto and an if statement. Which reads better to you?
(Say the words out loud!)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;fonts&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;each&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;do&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="c1"&gt;# fonts each do font :-(&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fonts&lt;/span&gt;
&lt;span class="c1"&gt;# for font in fonts :-)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The for loop gets my vote.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>An in Memory Go Implementation of Linear Hashing</title><link href="https://hackthology.com/an-in-memory-go-implementation-of-linear-hashing.html" rel="alternate"/><published>2013-11-15T00:00:00-05:00</published><updated>2013-11-15T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-15:/an-in-memory-go-implementation-of-linear-hashing.html</id><summary type="html">&lt;p&gt;In the &lt;a href="https://hackthology.com/linear-hashing.html"&gt;last post&lt;/a&gt; I described how linear hashing
works. If you haven't read it yet, you should go read it first. I can wait, this
post presents a new implementation which is a lot simpler than the disk based
version referenced in the last post.&lt;/p&gt;
&lt;p&gt;In the demonstration version …&lt;/p&gt;</summary><content type="html">&lt;p&gt;In the &lt;a href="https://hackthology.com/linear-hashing.html"&gt;last post&lt;/a&gt; I described how linear hashing
works. If you haven't read it yet, you should go read it first. I can wait, this
post presents a new implementation which is a lot simpler than the disk based
version referenced in the last post.&lt;/p&gt;
&lt;p&gt;In the demonstration version (that would be this one) I represent the buckets as
binary search trees. Find the exact code for this article in my &lt;a href="https://github.com/timtadh/goplay/blob/master/hashtable/linhash.go"&gt;goplay
repository&lt;/a&gt;. An updated
and slightly improved version is available in my &lt;a href="http://github.com/timtadh/data-structures"&gt;data-structures
repository&lt;/a&gt; along with several other
interesting algorithms.&lt;/p&gt;
&lt;h2&gt;Profiling Results&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;              iterations, ns per operation
BenchmarkGoMap    100000,      26292 ns/op -- native map
BenchmarkHash      20000,      79526 ns/op -- classical separate chaining
BenchmarkMLHash    20000,      80820 ns/op -- in memory LH
BenchmarkLHash       500,    5733882 ns/op -- disk based LH, LRU cached in memory
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Structs&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Bucket&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Has, Put, Get and Remove&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;UTILIZATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;float64&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;RECORDS_PER_BLOCK&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Split&lt;/h2&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;linearhash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;old_bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;old_bkt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Iterate&lt;/span&gt;&lt;span class="p"&gt;()();&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;bkt_a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;v&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_a&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Buckets&lt;/h2&gt;
&lt;p&gt;One cool thing about my BST implementation is it has a functional iterator. As
you may know you can't make a generic generator function in Go without using a
separate goroutine, which isn't really appropriate here. The &lt;code&gt;Iterate&lt;/code&gt; function
makes a &lt;code&gt;BSTIterator&lt;/code&gt; which is a function which yields the current key, value
pair and a function which provides the next item. You iterate by calling &lt;code&gt;next&lt;/code&gt;
over and over again until the function pointer is nil. I hadn't written an
iterator like this before but I like the way it works so I will probably re-use
this pattern for future Go iterators.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Iterate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;procnode&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;make_iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;make_iterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BSTIterator&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;pop&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;procnode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;node&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;make_iterator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;make_iterator&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Standard Has, Get, Put, Remove, Size&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Has&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not-found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;updated&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not-found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;lmd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lmd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;lmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;rmd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rmd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="nx"&gt;rmd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Less&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;left&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;The _md, lmr, rmd&lt;/h3&gt;
&lt;p&gt;These implement "left most descendent" and "right most descendent". Used by
remove to hook up the nodes correctly.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;_md&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_md&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;lmd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_md&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rmd&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;_md&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bst&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;node&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;right&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Linear Hashing</title><link href="https://hackthology.com/linear-hashing.html" rel="alternate"/><published>2013-11-13T00:00:00-05:00</published><updated>2013-11-13T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-13:/linear-hashing.html</id><summary type="html">&lt;p&gt;Linear Hashing&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;,&lt;/sup&gt;&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; is a hash table algorithm suitable for
secondary storage. It is often used to implement hash indices in databases and
file systems. Linear Hashing was invented by Witold Litwin in 1980 and has been
in widespread use since that time. I implemented this file-structure earlier
this …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Linear Hashing&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;,&lt;/sup&gt;&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; is a hash table algorithm suitable for
secondary storage. It is often used to implement hash indices in databases and
file systems. Linear Hashing was invented by Witold Litwin in 1980 and has been
in widespread use since that time. I implemented this file-structure earlier
this year. You can find &lt;a href="https://github.com/timtadh/file-structures/blob/master/linhash"&gt;my implementation on
github&lt;/a&gt;. This
article is based off a talk&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; I gave at &lt;a href="http://hacsoc.org"&gt;CWRU Hacker
Society&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also implemented an in memory version of this algorithm. I give a detailed
break down of each element of the implementation in the follow up
&lt;a href="https://hackthology.com/an-in-memory-go-implementation-of-linear-hashing.html"&gt;post&lt;/a&gt;. You should read that article after you
have finished this one.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Linear Hash" src="images/lin-hash.png"&gt;&lt;/p&gt;
&lt;h1&gt;Hashing, A Refresher&lt;/h1&gt;
&lt;p&gt;In order to understand Linear Hashing one should take a moment to review
Classical Hashing.&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt; Briefly, a hash table is a "symbol table" which maps keys
to values. By "maps" I mean if you give it a key it will give the associated
value if one exists. Keys must be hashable, which means there must be some way
to turn them into integers. For a discussion on constructing such hash functions
I recommend the Hashing Tutorial.&lt;sup id="fnref2:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h3&gt;Abstract Data Type&lt;/h3&gt;
&lt;p&gt;If the above description was confusing perhaps this ADT will clarify what I
mean:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;HashTable
  size():int -- how many entries?
  has(key:Hashable):boolean -- is the key in the table?
  get(key:Hashable):Object throws KeyNotFound -- get the associated value.
  put(key:Hashable, value:Object) -- associate a key and value.


  remove(key:Hashable) throws KeyNotFound -- remove the key from the table.

Hashable
  hash():int
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You may have used hash tables by another name in you programming language. For
instance in Python they are called dictionaries, in Ruby hashs, and in Java they
are called HashMaps.&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;p&gt;Let's walk through a simple hash table implementation using separate chaining
(also called open hashing). We will do this in the Go programming language. &lt;/p&gt;
&lt;h3&gt;Structs&lt;/h3&gt;
&lt;p&gt;Here is how we are going to represent a hash table:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;b&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A &lt;code&gt;hash&lt;/code&gt; is a struct with to elements. An array of pointers to &lt;code&gt;entry&lt;/code&gt;. The
entries hold our key value pairs. The way the table works is we convert the key
into a number which we then clamp to the size of our table. That number will be
the index of some entry in our table from which we can add, lookup, or remove
the key.&lt;/p&gt;
&lt;p&gt;The entry struct represents the key value pair and represents a linked list.
Since covering linked list operations is a bit beyond the scope of this paper,
let me just present operations on the &lt;code&gt;*entry&lt;/code&gt; but with no explanation. The
function should be obvious even if the implementation is obscure.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;



&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;list-not-found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Equals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Operations on the Hash Table&lt;/h2&gt;
&lt;p&gt;Now for how to implement the different operations. As a reminder we are going to
convert our key to an index into the table as our first step. Let's make a
function for that and call it &lt;code&gt;bucket&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Insertion&lt;/h4&gt;
&lt;p&gt;Putting an object into a hash table is very simple. We grab the bucket and use
the associate &lt;code&gt;Put&lt;/code&gt; method to place our key value pair into the list. If it was
actually appended onto the list (rather than updating and existing entry) we
increment the &lt;code&gt;size&lt;/code&gt; field.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;


&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now there is one more wrinkle I will return to in a moment which is resizing the
table when it gets too full.&lt;/p&gt;
&lt;h4&gt;Retrieval&lt;/h4&gt;
&lt;p&gt;Retrieval is just as easy. We grab the bucket and look in the linked list to see
if it is there or not. If it is, return it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not-found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Removal&lt;/h4&gt;
&lt;p&gt;Removal is almost the same as insertion except we call &lt;code&gt;Remove&lt;/code&gt; on the linked
list instead of &lt;code&gt;Put&lt;/code&gt; and update the head as before. We check to make sure it
is in the linked list first as this slightly simplifies the removal algorithm
above.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;has&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Errors&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;not-found&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Remove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Expansion&lt;/h4&gt;
&lt;p&gt;The performance of a hash table degrades as it gets too full. Therefore, we have
to periodically expand the size of the hash table. As long we double the size
each time all of our operations are asymptotically linear (on average). To
double the size of the table, we allocate a new table and copy all of the
entries from the old table to the new. We must be careful when we do this and
rehash each element. If we don't, we will be unable to find the elements in the
new table since the &lt;code&gt;bucket&lt;/code&gt; function depends on the table size.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;range&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;E&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Insert Revisited&lt;/h4&gt;
&lt;p&gt;So when should we expand the hash table? We should expand on insert when the
number of elements is over a certain threshold. The threshold is often set at
60% but this setting varies.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;interface&lt;/span&gt;&lt;span class="p"&gt;{})&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kd"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;appended&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expand&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Adapting Hash Tables for Secondary Storage&lt;/h1&gt;
&lt;p&gt;&lt;a href="images/cpu-arch.png"&gt;&lt;img alt="CPU and Storage" src="images/cpu-arch.png"&gt;&lt;/a&gt;
Figure 1. &lt;strong&gt;CPU and Storage&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, the algorithm presented above does work well when using secondary
storage mediums like hard disks and solid state drives. There are several
reasons for this:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Secondary Storage is slower than RAM&lt;/li&gt;
&lt;li&gt;The bus is slower&lt;/li&gt;
&lt;li&gt;Many peripherals hang off of the South Bridge&lt;/li&gt;
&lt;li&gt;Disks may be daisy chained causing bus contention&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To deal with these factors and others when using disks:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Read and write pages which are blocks of size 4096 bytes.&lt;/li&gt;
&lt;li&gt;Try and read contiguous runs and if writing more than one page write
   contiguous runs as well.&lt;/li&gt;
&lt;li&gt;Batch writes.&lt;/li&gt;
&lt;li&gt;Don't read one byte at a time, read several blocks and get the byte that you
   need.&lt;/li&gt;
&lt;li&gt;Employ caching at every layer.&lt;/li&gt;
&lt;li&gt;Measure performance in terms of number of disk accesses (eg. Block read and
   writes).&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Back to Hashing&lt;/h2&gt;
&lt;p&gt;The first adjustment to make is to hash into blocks instead of hashing into
individual array buckets. Each block is then a sorted array of entries.&lt;/p&gt;
&lt;p&gt;&lt;a href="images/block-file.png"&gt;&lt;img alt="Block File" src="images/block-file.png"&gt;&lt;/a&gt;
Figure 2. &lt;strong&gt;Block File&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We could make a fairly straight forward adaption of our separate chained hash
table above to this restriction. However, there is a problem: what do we do when
the table needs to be expanded? If the table is static then there is not
problem, we simply allocate the correct number of blocks right away. But, if we
have to expand the table every entry will need to be rehashed. This will cause
us to read from every block from our old table (N reads) and write to every
block in our new table (2*N writes) -- ouch.&lt;/p&gt;
&lt;p&gt;The solution is of course Linear Hashing.&lt;/p&gt;
&lt;h2&gt;Linear Hashing&lt;/h2&gt;
&lt;p&gt;How does Linear Hashing compare?&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Small mean disk accesses&lt;ol&gt;
&lt;li&gt;Successful Search&lt;ol&gt;
&lt;li&gt;.75 utilization ~ 1.05 disk accesses&lt;/li&gt;
&lt;li&gt;.9 utilization ~ 1.35 disk accesses&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Unsuccessful Search&lt;ol&gt;
&lt;li&gt;.75 utilization ~ 1.27 disk accesses&lt;/li&gt;
&lt;li&gt;.9 utilization ~ 2.37 disk accesses&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;Insert&lt;ol&gt;
&lt;li&gt;.75 utilization ~ 2.62 disk accesses&lt;/li&gt;
&lt;li&gt;.9 utilization ~ 3.73 disk accesses&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In comparison a B+Tree of reasonable size might need at least 4 disk access
   for a search. (Of course a B+Tree will can perform range queries but that
   isn't the point here)&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;File grows at a linear rate.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Little dynamic re-arrangement&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Does not necessarily need address translation.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Simple Algorithm esp. in comparison to B+Trees.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Explanation of the Algorithm&lt;/h3&gt;
&lt;p&gt;The &lt;strong&gt;key&lt;/strong&gt; insight is to not use all the bits of the hash function "H(.)" all
the time. When the table is small we only use as much of the hash function as
we need. As the table grows we use more bits. As the table shrinks we use less.&lt;/p&gt;
&lt;p&gt;&lt;a href="images/lin-hash-ex-1.png"&gt;&lt;img alt="Linear Hash" src="images/lin-hash-ex-1.png"&gt;&lt;/a&gt;
Figure 3. &lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In the figure, &lt;code&gt;n&lt;/code&gt; is the number of blocks, &lt;code&gt;i&lt;/code&gt; is the number of bits of the
hash functions and &lt;code&gt;r&lt;/code&gt; is the number of records.&lt;/p&gt;
&lt;p&gt;So to find which bucket a key goes to:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;bkt_idx&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kr"&gt;let&lt;/span&gt;
  &lt;span class="n"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="n"&gt;a_1&lt;/span&gt; &lt;span class="n"&gt;a_2&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="n"&gt;a_i&lt;/span&gt; &lt;span class="cm"&gt;(* base 2 expansion of the hash of the key *)&lt;/span&gt;
  &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a_1&lt;/span&gt; &lt;span class="n"&gt;a_2&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="n"&gt;a_i&lt;/span&gt; &lt;span class="cm"&gt;(* just the first i bits *)&lt;/span&gt;
&lt;span class="kr"&gt;in&lt;/span&gt;
  &lt;span class="kr"&gt;if&lt;/span&gt; &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kr"&gt;then&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;
  &lt;span class="kr"&gt;else&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="n"&gt;^&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="cm"&gt;(* == 0 a_2 a_3 ... a_i *)&lt;/span&gt;
&lt;span class="kr"&gt;end&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In go&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;uint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// last i bits of hash as&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="c1"&gt;// bucket number m&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;m&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;^&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// unset the top bit&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Insertion&lt;/h4&gt;
&lt;p&gt;Insertion is quite simple now that we know how to get the bucket (assuming we
have implemented the appropriate operations on our buckets). First we get the
bucket and we put the item into the bucket. If the bucket takes care of chaining
on an extra block if it full then the only thing that is left is checking
whether or not an expansion (called a split) is needed.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LinearHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Insert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Hashable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Hash&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;bkt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;UTILIZATION&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;records_per_block&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As I mentioned above, if a bucket is full it should chain out an extra block for
itself. This can be handled transparently.&lt;/p&gt;
&lt;p&gt;&lt;a href="images/lin-hash-ex-2.png"&gt;&lt;img alt="Linear Hash" src="images/lin-hash-ex-2.png"&gt;&lt;/a&gt;
Figure 4. &lt;strong&gt;Chaining Example&lt;/strong&gt;&lt;/p&gt;
&lt;h4&gt;Splitting&lt;/h4&gt;
&lt;p&gt;The split mechanism is clever bit of the linear hash algorithm. When the table
is too full another block is added to the table:&lt;/p&gt;
&lt;p&gt;&lt;a href="images/lin-hash-ex-3.png"&gt;&lt;img alt="Linear Hash" src="images/lin-hash-ex-3.png"&gt;&lt;/a&gt;
Figure 5. &lt;strong&gt;Split Example Part 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Note that the bucket we added in the example was &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There are some keys in the old bucket &lt;code&gt;0&lt;/code&gt; which is now called &lt;code&gt;00&lt;/code&gt; which
actually belong to bucket &lt;code&gt;10&lt;/code&gt;. So in order to make the addition of the new
bucket correct we need to split bucket &lt;code&gt;00&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="images/lin-hash-ex-4.png"&gt;&lt;img alt="Linear Hash" src="images/lin-hash-ex-4.png"&gt;&lt;/a&gt;
Figure 5. &lt;strong&gt;Split Example Part 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In general if we add&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We split&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="mf"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;...&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;a_i&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In code&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kd"&gt;func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;LinearHash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;split&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;get_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bkt_idx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;:=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;allocate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;nil&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;blk_a&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split_into&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;bkt_b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// The split into function is left as&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;// an exercise for the reader!&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Hopefully if you are still with me you have a grasp on what is going on in the
Linear Hashing algorithm. The key take aways are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can slowly extend how much of the hash function you use.&lt;/li&gt;
&lt;li&gt;You don't have to rehash the whole file to add a bucket, just the bucket that
   collides with the new bucket.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;If you want to implement the algorithm I suggest reading the description in the
Garcia-Molina book and taking a look at the original paper. You can also take a
look at &lt;a href="https://github.com/timtadh/file-structures/blob/master/linhash"&gt;my implementation&lt;/a&gt; or my other
implementation, an &lt;a href="https://hackthology.com/an-in-memory-go-implementation-of-linear-hashing.html"&gt;in memory version&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Henderson, T. A. D. (2013)
&lt;a href="https://hackthology.com/pdfs/2013-11-13-linear-hashing-lecture.pdf"&gt;Linear Virtual Hashing&lt;/a&gt;.
CWRU Hacker Society. Lecture Notes. November, 2013.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Litwin, W. (1980).
&lt;a href="https://hackthology.com/pdfs/Litwin-1980-Linear_Hashing.pdf"&gt;Linear hashing: a new tool for file and table addressing&lt;/a&gt;. In Proceedings of the sixth
international conference on Very Large Data Bases - Volume 6 (pp.  212–223).
VLDB Endowment. Retrieved from
&lt;a href="http://dl.acm.org/citation.cfm?id=1286887.1286911"&gt;http://dl.acm.org/citation.cfm?id=1286887.1286911&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;Garcia-Molina, H., Ullman J. D., and Widom J. (2002)
&lt;a href="http://www.worldcat.org/title/database-systems-the-complete-book/oclc/47915796"&gt;Database Systems: The Complete Book&lt;/a&gt;.
Prentice Hall. Upper Saddle River, New Jersey. ISBN 0-13-031995-3. Section
13.4.7 "Linear Hash Tables"&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;Shaffer, C. A. (2007)
&lt;a href="http://research.cs.vt.edu/AVresearch/hashing/"&gt;Hashing Tutorial&lt;/a&gt;
Virginia Tech Algorithm Research Group.&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;Ok, I am not that mean here is how to do the split_into in this file:
&lt;a href="https://github.com/timtadh/file-structures/blob/master/linhash/bucket/bucket.go"&gt;https://github.com/timtadh/file-structures/blob/master/linhash/bucket/bucket.go&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;Henderson, T. A. D. (2013) &lt;a href="https://github.com/timtadh/file-structures/blob/master/linhash"&gt;Linear Hash
Implementation&lt;/a&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Cryptography and Complexity</title><link href="https://hackthology.com/cryptography-and-complexity.html" rel="alternate"/><published>2013-11-11T00:00:00-05:00</published><updated>2013-11-11T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-11:/cryptography-and-complexity.html</id><summary type="html">&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct or the bibliography you should read the
&lt;a href="https://hackthology.com/pdfs/crypto-complexity.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cite as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Henderson, Tim A. D. &lt;strong&gt;Cryptography and Complexity&lt;/strong&gt;. Unpublished. Case Western Reserve University. MATH 408.  Spring 2012.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr/&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;Modern cryptographic systems are built on problems …&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a conversion from a latex paper I wrote. If you want all formatting
correct or the bibliography you should read the
&lt;a href="https://hackthology.com/pdfs/crypto-complexity.pdf"&gt;pdf version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cite as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Henderson, Tim A. D. &lt;strong&gt;Cryptography and Complexity&lt;/strong&gt;. Unpublished. Case Western Reserve University. MATH 408.  Spring 2012.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr/&gt;
&lt;script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.4/latest.js?config=TeX-AMS-MML_HTMLorMML" type="text/javascript"&gt;&lt;/script&gt;

&lt;p&gt;Modern cryptographic systems are built on problems which are assumed to be computationally infeasible. Computational infeasibility means a computation which although computable would take far too many resources to actually compute. Ideally in cryptography one would like to ensure an infeasible computation&amp;#8217;s cost is greater than the reward obtained by computing it. At first glance this seems to be an odd notion to base a cryptographic system on. Don&amp;#8217;t we want our cryptographic systems to be totally secure? They should be unbreakable! &amp;#8220;It may take a long time to break it,&amp;#8221; seems like a poor guarantee of security.&lt;/p&gt;
&lt;p&gt;However, it is the best guarantee which can exist in either an ideal world (from a mathematical perspective) or the physical world. As we shall see later in the survey, if several widely held assumptions turn out to be false we can not even make the guarantee of computational infeasibility.&lt;/p&gt;
&lt;h2&gt;Classical Security&lt;/h2&gt;
&lt;p&gt;In classical cryptographic systems, those known to the academic community prior to the publication of Diffie and Hellman&amp;#8217;s paper &lt;span class="citation"&gt;&lt;/span&gt;, security assumptions were based on the results of information theory. This approach is sometimes referred to as &lt;em&gt;information-theoretic&lt;/em&gt; and is concerned with whether there exists information in the &lt;em&gt;ciphertext&lt;/em&gt; which originated in the &lt;em&gt;plaintext&lt;/em&gt; or in the &lt;em&gt;key&lt;/em&gt;. We say a system has &lt;em&gt;perfect-secrecy&lt;/em&gt; if:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
  \forall_{m \in \mathcal{M}} \forall_{c \in \mathcal{C}} \text{ : } 
  Pr[\mathcal{M} = m | \mathcal{C} = c] = Pr[\mathcal{M} = m]
  \label{perfect-secrecy}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Intuitively this formula says an attacker gains no information about the contents of a message from the ciphertext of the message. Does this mean the attacker knows nothing about the message? Of course not! However, he doesn&amp;#8217;t &lt;em&gt;learn&lt;/em&gt; anything new about the message by closely examining the ciphertext. Therefore, the ciphertext of the message is essentially useless to an attacker. &lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn1" class="footnoteRef" id="fnref1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;However, any system with &lt;em&gt;perfect-secrecy&lt;/em&gt; requires the length of the key to be at least as large as the sum of the lengths of all messages encrypted with it. Since the key has to be at least as long as the messages sent such a system is of little value in practical modern situations.&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn2" class="footnoteRef" id="fnref2"&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;There are two practical problems with a system with &lt;em&gt;perfect-secrecy&lt;/em&gt; the first is &amp;#8220;Key Distribution.&amp;#8221; Since the sender and receiver must use the same key they must some how &lt;em&gt;secretly&lt;/em&gt; agree on a key beforehand. Therefore, there must exist some &amp;#8220;second channel&amp;#8221; by which the sender and receiver can communicate. The second problem has to do with the length of the key. Since it is as long as the message there seems to be only small utility in the system as the sender and receiver could conceivably securely exchange messages using their secure &amp;#8220;second channel&amp;#8221; they use for key distribution.&lt;/p&gt;
&lt;p&gt;These to problems make the system an unrealistic system for securing (for instance) internet communications. Internet communications do not require the parties to know each other before hand and allow for no secondary secure communications channel to exist. Therefore, some other encryption methodology must be used if one wants to secure communication in this setting.&lt;/p&gt;
&lt;h2&gt;Modern Security&lt;/h2&gt;
&lt;p&gt;In modern system we no longer discuss security in terms of whether a system provides &lt;em&gt;perfect-secrecy&lt;/em&gt;. Instead, we say if a ciphertext contains information leaked from the plaintext it should be computationally infeasible to extract that information. We can provide this property even in cases where the key is shorter than the message. This property can also be provided in cases where the attacker has access to the &lt;em&gt;encryption&lt;/em&gt; key (but not of course to the &lt;em&gt;decryption&lt;/em&gt; key).&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn3" class="footnoteRef" id="fnref3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;In following section [secure-encryption] we shall unpack and rigorously define (using &lt;span class="citation"&gt;&lt;/span&gt;&amp;#8217;s definitions) the definition above. In particular we will look at the definition in the context of symmetric key systems. The difficulties of public key systems will also be briefly presented but without detailed exposition. However, before we get to the fun stuff we will first present complexity theory and one way functions.&lt;/p&gt;
&lt;h1&gt;A Tour of Computational Complexity Theory&lt;/h1&gt;
&lt;p&gt;In many ways Computability Theory, and its daughter field Complexity Theory, began with proof of the incompleteness of axiomatic systems in 1931.&lt;span class="citation"&gt;&lt;/span&gt; The proof is a tremendously important result in meta-mathematics stating: no recursively axiomatized mathematical system can be both complete and consistent. Thus, we cannot prove in a particular theory that the same particular theory is consistent. Indeed, if we did construct such a proof it would prove exactly the opposite. Thus, there are some mathematical sentences which are true for which no algorithm can decided on their truth value.&lt;/p&gt;
&lt;p&gt;In a similar result, Alan Turing in 1937 proved that for general programs one could not decide whether the programs would halt for all inputs.&lt;span class="citation"&gt;&lt;/span&gt; During the previous year Alonzo Church proved the exact same thing for evaluations of &lt;span class="math"&gt;\(\lambda\)&lt;/span&gt;-Calculus expressions.&lt;span class="citation"&gt;&lt;/span&gt; Church and Turing later conjectured that the machine Turing defined (eg. Turing Machines) and Church&amp;#8217;s lambda calculus were equivalent. All though this is an unprovable conjecture it is largely accepted today.&lt;/p&gt;
&lt;p&gt;Once actual computational machines were produced (as opposed to the abstract machines of Turing and Church), programmers became interested in the notion of the &lt;em&gt;complexity&lt;/em&gt; of an algorithm. The complexity of an algorithm is an expression of how much time or space or other resources the algorithm will use. The representation of time and space is abstract and placed in terms of the size of the parameters to the algorithm. Today, we use asymptotic notation to express complexity assertions. The notation was standardized by Don Knuth in 1976 but in wide (although inconsistent) use before then. It was invented by Bachmann in 1894 for use in a different context.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The interest in the complexity of algorithms and work on linguistics (particularly formal language hierarchies) lead to work on classifying the &amp;#8220;hardness&amp;#8221; computational problems. For instance all of the language classes in the Chomsky hierarchy have hardness results. Type-0 Languages (all recursively enumerable languages) are recognizable but only non-deterministically. While, Type-3 languages (referred to as regular languages) can be recognized in linear time.&lt;sup&gt;&lt;a href="#fn4" class="footnoteRef" id="fnref4"&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This leads to defining complexity classes for problems (as opposed to algorithms). A complexity class typically refers to a bound on the amount time or space needed to solve the problem in the worst case. Thus, complexity classes describe how difficult a problem is to solve in general. The first general results in the theory were obtained in 1965 by Hartmanis and Stearns who defined the meaning computation complexity.&lt;/p&gt;
&lt;p&gt;In particular Hartmanis and Stearns modeled their definition using the computational model of an N-Tape Turing Machine. Any computational model could have been used, and today others are used. In particular the authors prove facts about the computability of particular binary strings, &lt;span class="math"&gt;\(\alpha\)&lt;/span&gt; in the paper. They say &lt;span class="math"&gt;\(\alpha\)&lt;/span&gt; is in a complexity class &lt;span class="math"&gt;\(S_T\)&lt;/span&gt; if &lt;span class="math"&gt;\(T: \mathbb{N} \rightarrow \mathbb{N}\)&lt;/span&gt; is a monotone increasing function and there exists a Turing machine &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; such that &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; computes the &lt;span class="math"&gt;\(n\)&lt;/span&gt;th term in &lt;span class="math"&gt;\(T(n)\)&lt;/span&gt; steps.&lt;/p&gt;
&lt;p&gt;What does this definition mean intuitively? Think of &lt;span class="math"&gt;\(T\)&lt;/span&gt; as a time function, where time is a function of the number bits generated. A string can belongs to those complexity classes which can compute the string according to the complexity class&amp;#8217;s specified time function. Thus, by specifying some general time functions such as (&lt;span class="math"&gt;\(1\)&lt;/span&gt;, &lt;span class="math"&gt;\(n\)&lt;/span&gt;, &lt;span class="math"&gt;\(n^2\)&lt;/span&gt; &amp;#8230;, &lt;span class="math"&gt;\(2^n\)&lt;/span&gt;) one can begin classifying bit-strings. The bit-strings correspond to problem solutions. For a simple example consider the bit-string which corresponds to all prime numbers. To compute it, one would need to actually compute exactly those numbers which are prime.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The type of problem Hartmanis and Stearns classified belongs to the class of problems known as Decision Problems. Informally, decision problems are problems to which there is a &amp;#8220;yes/no&amp;#8221; answer. For instance, deciding whether the first &lt;span class="math"&gt;\(n\)&lt;/span&gt; bits of a string is in a language, &lt;span class="math"&gt;\(\mathcal{L} \subseteq \{0,1\}^*\)&lt;/span&gt;, is a decision problem. Complexity classes are more general than just decision problems however, one can construct complexity classes for any type of computational problem, optimizations problems for instance.&lt;/p&gt;
&lt;h2&gt;The Class NP&lt;/h2&gt;
&lt;p&gt;Of particular importance to mathematics, computer science and this paper in particular is the complexity class NP (Non-Deterministic Polynomial Time). The class of NP is defined (intuitively) as those problems which have easily verifiable solutions. What does it mean for a solution to be &amp;#8220;easily verifiable.&amp;#8221; It means given the problem instance and the solution one can check the validity of the solution in &lt;span class="math"&gt;\(O(n^k)\)&lt;/span&gt; where &lt;span class="math"&gt;\(n\)&lt;/span&gt; is parameterized by the problem and &lt;span class="math"&gt;\(k\)&lt;/span&gt; is a constant.&lt;/p&gt;
&lt;p&gt;More formally, the class NP is defined in terms of formal languages. Let &lt;span class="math"&gt;\(\Sigma\)&lt;/span&gt; be an alphabet and &lt;span class="math"&gt;\(\Sigma_{0}\)&lt;/span&gt; be &lt;span class="math"&gt;\(\Sigma - \{*\}\)&lt;/span&gt; where &lt;span class="math"&gt;\(*\)&lt;/span&gt; is the empty symbol. Let &lt;span class="math"&gt;\(\Sigma_{0}^{*}\)&lt;/span&gt; be the closure of all finite strings made up of symbols in &lt;span class="math"&gt;\(\Sigma_{0}\)&lt;/span&gt;. We define a language, &lt;span class="math"&gt;\(\mathcal{L}\)&lt;/span&gt;, as &lt;span class="math"&gt;\(\mathcal{L} \subseteq \Sigma_{0}^{*}\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The Class NP&lt;sup&gt;&lt;a href="#fn5" class="footnoteRef" id="fnref5"&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A language, &lt;span class="math"&gt;\(\mathcal{L}\)&lt;/span&gt;, belongs to NP if there exists a Deterministic Turing Machine, &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt;, a polynomial, &lt;span class="math"&gt;\(p(n)\)&lt;/span&gt; &amp;#8211; such that &lt;span class="math"&gt;\(p(n)\)&lt;/span&gt; defines the complexity class of &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn6" class="footnoteRef" id="fnref6"&gt;6&lt;/a&gt;&lt;/sup&gt; &amp;#8211; and on any input &lt;span class="math"&gt;\(x
    \in \Sigma_{0}^{*}\)&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;if &lt;span class="math"&gt;\(x \in \mathcal{L}\)&lt;/span&gt; then there exists a &lt;em&gt;certificate&lt;/em&gt;, &lt;span class="math"&gt;\(y
            \in \Sigma_{0}^{*} \text{ st. } |y| \leq p(|x|)\)&lt;/span&gt;, and &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; accepts the input string &lt;span class="math"&gt;\(xy\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;if &lt;span class="math"&gt;\(x \notin \mathcal{L}\)&lt;/span&gt; then for any string, &lt;span class="math"&gt;\(y \in
            \Sigma_{0}^{*}\)&lt;/span&gt;, &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; rejects the input string &lt;span class="math"&gt;\(xy\)&lt;/span&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;
&lt;p&gt;The given definition does not discuss Non-Determinism. To see the role of Non-Determinism consider constructing solutions (certificates) to problem instances (the string x in the definition). If certificates can be chosen and examined non-deterministically then it will take only polynomial time to find a solution. However, if we are testing every possible certificate deterministically it will take &lt;span class="math"&gt;\(\vert \Sigma_0\vert ^{p(\vert x\vert )}\)&lt;/span&gt; examinations, a combinatorial explosion. Thus, problems in NP have solutions which are easy to verify but not necessarily easy to construct.&lt;/p&gt;
&lt;h2&gt;The Class P&lt;/h2&gt;
&lt;p&gt;The complexity class P (Polynomial Time) is exactly those problems solvable in deterministic polynomial time. More formally,&lt;/p&gt;
&lt;p&gt;The Class P&lt;sup&gt;&lt;a href="#fn7" class="footnoteRef" id="fnref7"&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math"&gt;\(\Pi\)&lt;/span&gt; be a decision problem. Let &lt;span class="math"&gt;\(L_{\Pi} = \{ x \in \Sigma_0^* |
    \text{x is an encoding of an instance of } \Pi \}\)&lt;/span&gt;, that is, &lt;span class="math"&gt;\(L_{\Pi}\)&lt;/span&gt; is the language of &lt;span class="math"&gt;\(\Pi\)&lt;/span&gt;. We can then define the class P as:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      P = \{ L \subseteq \Sigma_0^* |&amp;amp; \text{ there is a Deterministic Turing} 
        \text{ Machine, } \mathcal{M} \text{, and a polynomial, } \\
        &amp;amp;p(n) \text{, } \text{such that } T_{\mathcal{M}} \leq p(n) 
        \text{ for all } n \geq 1 \}
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;A language is in P if one can construct a Turing Machine which accepts it (and rejects all non-members) in time less than some polynomial (with respect to the size of the input).&lt;/p&gt;
&lt;p&gt;All those problems which belong to P are considered easily solvable, or tractable. While, they are &amp;#8220;easy&amp;#8221; one should not make the mistake of assuming they are simple. Given a polynomial time algorithm which solves a problem one can easily solve it. However, even if you know a polynomial time algorithm exists for a problem constructing the algorithm may be difficult.&lt;/p&gt;
&lt;h2&gt;P vs.&amp;#160;NP&lt;/h2&gt;
&lt;p&gt;What is the relationship between P and NP? It is known P is contained in NP (ie. &lt;span class="math"&gt;\(P \subseteq NP\)&lt;/span&gt;). However, whether &lt;span class="math"&gt;\(NP \subseteq P\)&lt;/span&gt; is true is one of the greatest open questions in applied mathematics. The class P containment inside of NP is obvious: if we can find a solution in polynomial time it is certainly verifiable in polynomial time. To show NP is contained within P one would need to show every problem in NP can be solved with a polynomial time algorithm.&lt;/p&gt;
&lt;p&gt;The methodology for solving P vs NP with the greatest impact relies on the idea of &lt;em&gt;reduction&lt;/em&gt;. We say problem, &lt;span class="math"&gt;\(\Pi_1\)&lt;/span&gt; is &lt;em&gt;reducible&lt;/em&gt; to another problem, &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt;, if one can find a mapping from every instance of &lt;span class="math"&gt;\(\Pi_1\)&lt;/span&gt; to equivalent instances of &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt; such that the solutions to the constructed instances of &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt; correspond to solutions of &lt;span class="math"&gt;\(\Pi_1\)&lt;/span&gt;. A reduction is a &lt;em&gt;polynomial reduction&lt;/em&gt; if the mapping can be done in polynomial time. A problem, &lt;span class="math"&gt;\(\Pi_1\)&lt;/span&gt;, is as &amp;#8220;hard&amp;#8221; as another problem, &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt;, if &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt; can be &lt;em&gt;reduced&lt;/em&gt; to &lt;span class="math"&gt;\(\Pi_2\)&lt;/span&gt;. Thus, hardness is a relational notion. Problems are not intrinsically hard, they are hard with respect to other problems.&lt;/p&gt;
&lt;p&gt;To prove P contains NP one could prove the hardest problem in NP is also in P. By the definition of hardness above, if a problem, &lt;span class="math"&gt;\(\Pi_h\)&lt;/span&gt;, is the hardest problem in NP than every other problem in NP is reducible to &lt;span class="math"&gt;\(\Pi_h\)&lt;/span&gt;. Problems which are at least as hard as every problem in NP are know as NP-Hard problems. A problem does not need to be in NP to be NP-Hard. However, if a problem is NP-Hard and it is in NP then it is called an NP-Complete problem.&lt;/p&gt;
&lt;p&gt;NP-Complete problems exist and their existence is one of the greatest results in complexity theory. It was proved by Stephen Cook in 1971 who found the first NP-Complete problem. The problem he found is known as SAT (for satisfiability of boolean formulas). He proved any problem solvable in polynomial time by a Nondeterministic Turing Machine can be reduced to finding whether or not a boolean formula is satisfiable.&lt;span class="citation"&gt;&lt;/span&gt; Cook&amp;#8217;s result launched a wave of research. The very next year Richard Karp proved 21 other problems were also NP-Complete.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;While there have many hundreds of problems proven to be NP-Complete since Cook proved SAT, there have been only fruitless attempts to prove P does or does not contain NP. The leading consensus in the complexity community is P does not contain NP. Furthermore, since it appears work on proving P contains NP is permanently stalled one can safely assume NP-Hard problems are in some platonic sense actually difficult to solve.&lt;/p&gt;
&lt;h2&gt;Infeasibility&lt;/h2&gt;
&lt;p&gt;A sharper definition of computational infeasibility can now be given with definitions of Complexity Classes, P, and NP in hand. Recall the opening statement on infeasibility, where we defined an infeasible computation to be one requiring too many resources to actually compute. If one has encrypted a message one would ideally like the ciphertext to be unreadable. If the message is a solution to an NP-Complete problem then the ciphertext could be the problem instance and therefore can only be decrypted by solving the NP-Complete problem. However, assuming NP is not contained in P, the NP-Complete problem will take time proportional to &lt;span class="math"&gt;\(\vert \Sigma_0^*\vert ^{\vert x\vert }\)&lt;/span&gt; (where x is the ciphertext) to solve.&lt;/p&gt;
&lt;p&gt;Therefore, a new working definition of an infeasible computation is a &amp;#8220;hard&amp;#8221; instance of an NP-Hard problem of sufficient size. What is sufficient size? Any size which leads to &lt;span class="math"&gt;\(\vert \Sigma_0^*\vert ^{\vert x\vert }\)&lt;/span&gt; to be so large as to be uncomputable. An example of such as size might be &lt;span class="math"&gt;\(160\)&lt;/span&gt; since trying &lt;span class="math"&gt;\(2^{160}\)&lt;/span&gt; possible solutions is not expected to ever be computable with classical computers in time less than the age of the universe. What is a &amp;#8220;hard&amp;#8221; instance? A hard instance is one in which there exists no better way to find a solution than trying all possible solutions. Not every instance of a hard problem is hard to solve. Specifying an infeasible computation requires a hard instance is a necessary restriction.&lt;/p&gt;
&lt;h2&gt;Probabilistic Infeasibility&lt;/h2&gt;
&lt;p&gt;In the previous section it was assumed all computations were exact. No computation &lt;em&gt;sometimes&lt;/em&gt; gave the right answer and sometimes did not. However, with an algorithm which mostly gives right answers could be very useful to the cryptanalyst. Therefore, we briefly turn our attention to probabilistic computations.&lt;/p&gt;
&lt;h3&gt;Probabilistic Turing Machines&lt;/h3&gt;
&lt;p&gt;A Probabilistic Turing Machine (PTM) is a Deterministic Turing Machine (DTM) with an extra input tape. The tape is called the &amp;#8220;coin flipping tape.&amp;#8221; The PTM can read one bit of information at a time from the coin flipping tape. Each bit is assured to be a random bit.&lt;sup&gt;&lt;a href="#fn8" class="footnoteRef" id="fnref8"&gt;8&lt;/a&gt;&lt;/sup&gt; Computation on the machine proceeds as before except at any time a random choice can be made. This allows us to construct algorithms which will &amp;#8220;probably&amp;#8221; but not necessarily produce the desired answer.&lt;/p&gt;
&lt;p&gt;Analyzing the running time of a PTM is a bit different than a DTM. While a DTM&amp;#8217;s running time only depends on its program and the initial configuration of the input tape, a PTM also depends on the random bits it reads during the computation. Therefore, the running time of a PTM is a random variable (we denote it as &lt;span class="math"&gt;\(t_{\mathcal{M}}(x)\)&lt;/span&gt;). Furthermore, whether a PTM halts or not on a fixed input is also a random variable. A &lt;em&gt;halting&lt;/em&gt; PTM is one which halts after a finite number of steps for all inputs and all configurations of the coin tossing tape.&lt;/p&gt;
&lt;p&gt;With the definition a &lt;em&gt;halting&lt;/em&gt; PTM in hand we are now prepared to reason about its running time. Worst case running time of a PTM, &lt;span class="math"&gt;\(T_{\mathcal{M}}(n)\)&lt;/span&gt;, is:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
  T_{\mathcal{M}}(n) = \text{max} \{ t \text{ } | \text{ there exists a } 
                       x \in \Sigma^{n}_{0} \text{ such that } 
                       \text{Pr}[t_{\mathcal{M}}(x) = t] &amp;gt; 0 \}\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Informally, this definition states: the worst case running time of a PTM is the maximum running time, &lt;span class="math"&gt;\(t_{\mathcal{M}}(x)\)&lt;/span&gt;, for which the machine will run with some probability greater than zero. A polynomial PTM is one in which there exists some positive polynomial, &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, such that &lt;span class="math"&gt;\(T_{\mathcal{M}}(n) \le p(n)\)&lt;/span&gt; holds.&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn9" class="footnoteRef" id="fnref9"&gt;9&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;BPP, Bounded Probability Polynomial Time&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A language &lt;span class="math"&gt;\(\mathcal{L}\)&lt;/span&gt; is recognized by a polynomial PTM, &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt;, if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;for every &lt;span class="math"&gt;\(x \in \mathcal{L}\)&lt;/span&gt; it holds that&lt;/em&gt; Pr&lt;span class="math"&gt;\([\mathcal{M} \text{ accepts } x] \ge \frac{2}{3}\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;em&gt;for every &lt;span class="math"&gt;\(x \notin \mathcal{L}\)&lt;/span&gt; it holds that&lt;/em&gt; Pr&lt;span class="math"&gt;\([\mathcal{M} \text{ does not accept } x] \ge \frac{2}{3}\)&lt;/span&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;BPP is the class of languages recognized by a polynomial PTM.&lt;sup&gt;&lt;a href="#fn10" class="footnoteRef" id="fnref10"&gt;10&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;&lt;a href="#fn11" class="footnoteRef" id="fnref11"&gt;11&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The class Bounded Probability Polynomial Time, sometimes called Bounded-&lt;em&gt;Error&lt;/em&gt; Probabilistic Polynomial Time, is somewhat analogous to the class P. Computations in BPP are considered feasible computations. The class P is contained within BPP, &lt;span class="math"&gt;\(P \subseteq BPP\)&lt;/span&gt;. However, the relationship between NP and BPP has not been established. In practice cryptographers assume &lt;span class="math"&gt;\(NP \nsubseteq BPP\)&lt;/span&gt; which implies &lt;span class="math"&gt;\(NP \neq P\)&lt;/span&gt;. All problems unsolvable by a polynomial PTM are considered infeasible, of which NP-Hard problems are a special case. As before, some instances of hard problems may in fact be easy to solve.&lt;/p&gt;
&lt;p&gt;Infeasible computations as defined above are nice formalisms but do not seem too useful. To utilize the previous definition one has to answer the following question: Given and instance of a problem is it a &lt;em&gt;hard&lt;/em&gt; instance? Unfortunately, we don&amp;#8217;t know how to answer this question.&lt;sup&gt;&lt;a href="#fn12" class="footnoteRef" id="fnref12"&gt;12&lt;/a&gt;&lt;/sup&gt; As we will see later, if we could easily find hard instances we could construct a simple and secure crypto-system by sampling hard instances. Therefore, cryptographers need better assurances than &lt;em&gt;worst-case&lt;/em&gt; assurances; a cryptographer needs to know a typical instance of a problem is hard.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;One Way Functions&lt;/h1&gt;
&lt;p&gt;With a firm grounding in Complexity Theory, we turn our attention to cryptography. First, by capturing the notion of exploitable computational difficulty as epitomized in the one way function. A one way function is a function which is &lt;em&gt;easy&lt;/em&gt; to compute but &lt;em&gt;hard&lt;/em&gt; to invert. More specifically:&lt;/p&gt;
&lt;p&gt;One Way Function [owf]&lt;/p&gt;
&lt;blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="math"&gt;\(\forall_x\)&lt;/span&gt; computing &lt;span class="math"&gt;\(f(x) = y\)&lt;/span&gt; is &lt;em&gt;easy&lt;/em&gt; to compute.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;span class="math"&gt;\(\forall_y\)&lt;/span&gt; computing &lt;span class="math"&gt;\(f^{-1}(y)\)&lt;/span&gt; such that &lt;span class="math"&gt;\(f(x) \in f^{-1}(y)\)&lt;/span&gt; is &lt;em&gt;hard&lt;/em&gt; to compute.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;p&gt;The one way function in definition [owf] is more of a theoretical construct than an actual mathematical construct. Therefore, it uses the notion of &lt;em&gt;easy&lt;/em&gt; and &lt;em&gt;hard&lt;/em&gt; computations without grounding itself with exact definitions. One can think of this first definition as an abstract, or ideal, definition.&lt;/p&gt;
&lt;p&gt;Ignoring for the moment the definitional problems, what use is a one way function to the cryptographer? It turns out one can define secure cryptosystems with one way functions. Such a cryptosystem will be discussed in detail in section [secure-encryption]. For now consider this simple example of the power of the idea:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;One day while toiling away, Ian had a flash of insight which would put his mechanical workings to right. A machine danced in his mind, one which would make widgets faster and better than before. So clever his insight he knew no one else would easily come up with the same idea. Thus, he decided not to patent it. Instead, he wrote down his idea and ran it through a one way function producing &lt;span class="math"&gt;\(y\)&lt;/span&gt; his certificate of his idea. He then published &lt;span class="math"&gt;\(y\)&lt;/span&gt; widely, placing it in all the libraries around the country.&lt;/p&gt;
&lt;p&gt;Many years passed and Mallory stole Ian&amp;#8217;s idea. Mallory being very clever sought to undue Ian and patented the idea. Then, he sued Ian for patent infringement. But, since Ian had a certificate of his invention, &lt;span class="math"&gt;\(y\)&lt;/span&gt;, he could prove to the court he had invented and known about the idea long before Mallory had filed for the patent. The court agreed with Ian and invalidated Mallory&amp;#8217;s patent.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The challenge in section [secure-encryption] will be transforming the one way function into a workable encryption device. For while a powerful concept, as demonstrated by the story above, it is non-obvious how a crypto-system can be constructed from it. But before crypto-systems, the definition must be tightened. Furthermore, one must be convinced one way functions can be reasonably expected to exist.&lt;/p&gt;
&lt;h2&gt;Strong One Way Functions&lt;/h2&gt;
&lt;p&gt;There are two vague terms used in definition [owf], &lt;em&gt;easy&lt;/em&gt; and &lt;em&gt;hard&lt;/em&gt; computations. Fortunately, we have already defined what an &lt;em&gt;easy&lt;/em&gt; computation is: an easy computation is on which can be done in (probabilistic) polynomial time. But what about inversion? What does it mean for a function to be hard to invert? A function, &lt;span class="math"&gt;\(f\)&lt;/span&gt;, is hard to invert if every probabilistic polynomial time algorithms will only invert &lt;span class="math"&gt;\(f\)&lt;/span&gt; with &lt;em&gt;negligible&lt;/em&gt; probability.&lt;/p&gt;
&lt;p&gt;Negligible&lt;sup&gt;&lt;a href="#fn13" class="footnoteRef" id="fnref13"&gt;13&lt;/a&gt;&lt;/sup&gt; [neg]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A function, &lt;span class="math"&gt;\(\mu : \mathbb{N} \rightarrow \mathbb{R}\)&lt;/span&gt;, is negligible if for every positive polynomial, &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, there exists an &lt;span class="math"&gt;\(N\)&lt;/span&gt; such that for all &lt;span class="math"&gt;\(n &amp;gt; N\)&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      \mu(n) &amp;lt; \frac{1}{p(n)}
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The definition of negligible is reminiscent of Asymptotic Notation used in the analysis of algorithms. It concerns itself with the behavior of the function, &lt;span class="math"&gt;\(\mu(n)\)&lt;/span&gt;, when &lt;span class="math"&gt;\(n\)&lt;/span&gt; grows large. An additional, and useful, feature of the definition is any negligible function remain negligible after multiplication with any polynomial &lt;span class="math"&gt;\(q(\cdot)\)&lt;/span&gt;. Therefore, any event which occurs with negligible probability will continue to occur with negligible probability even after polynomial repetitions. Thus, if &lt;span class="math"&gt;\(f\)&lt;/span&gt; is only invertible with polynomial time algorithm, &lt;span class="math"&gt;\(A\)&lt;/span&gt;, with negligible probability than no polynomial repetition of &lt;span class="math"&gt;\(A\)&lt;/span&gt; will be likely to invert &lt;span class="math"&gt;\(f\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Strong One Way Functions&lt;sup&gt;&lt;a href="#fn14" class="footnoteRef" id="fnref14"&gt;14&lt;/a&gt;&lt;/sup&gt; [strong-owf]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A function, &lt;span class="math"&gt;\(f : \{0,1\}^* \rightarrow \{0,1\}^*\)&lt;/span&gt;, is &lt;strong&gt;strongly&lt;/strong&gt; one way if it is:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Easy to compute&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;There exists a (deterministic) polynomial time algorithm A such that on input x algorithm A outputs &lt;span class="math"&gt;\(f(x)\)&lt;/span&gt; (ie. &lt;span class="math"&gt;\(A(x) =
      f(x)\)&lt;/span&gt;).&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Hard to invert&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;For &lt;em&gt;every&lt;/em&gt; probabilistic polynomial time algorithm &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt;, every positive polynomial &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, and all sufficiently large &lt;span class="math"&gt;\(n\)&lt;/span&gt; the probability &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt; inverts &lt;span class="math"&gt;\(f\)&lt;/span&gt; is negligible. That is:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
        \text{Pr}[A&amp;#39;(f(x)) \in f^{-1}(f(x))] &amp;lt; \frac{1}{p(n)}
      \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the above definition &amp;#8220;input x&amp;#8221; should be considered as a random variable drawn from a uniform distribution over &lt;span class="math"&gt;\(\{0,1\}^n\)&lt;/span&gt;. Thus, the second condition reads: for any random input of size &lt;span class="math"&gt;\(n\)&lt;/span&gt; the probability an arbitrary polynomial time algorithm will find a pre-image is negligible. If such a function could be found or constructed it would offer a strong assurance of computational difficulty.&lt;/p&gt;
&lt;h2&gt;Weak One Way Functions&lt;/h2&gt;
&lt;p&gt;While strong one way functions ensure any efficient inversion algorithm has only a negligible likelihood of succeeding; weak one way functions require efficient inversion algorithms will fail with a non-negligible probability.&lt;/p&gt;
&lt;p&gt;Weak One Way Functions&lt;sup&gt;&lt;a href="#fn15" class="footnoteRef" id="fnref15"&gt;15&lt;/a&gt;&lt;/sup&gt; [weak-owf]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A function, &lt;span class="math"&gt;\(f : \{0,1\}^* \rightarrow \{0,1\}^*\)&lt;/span&gt;, is &lt;strong&gt;weakly&lt;/strong&gt; one way if it is:&lt;/p&gt;
&lt;dl&gt;
&lt;dt&gt;Easy to compute&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;There exists a (deterministic) polynomial time algorithm A such that on input x algorithm A outputs &lt;span class="math"&gt;\(f(x)\)&lt;/span&gt; (ie. &lt;span class="math"&gt;\(A(x) =
      f(x)\)&lt;/span&gt;).&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Slightly hard to invert&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;There exists a polynomial &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt; such that for every probabilistic polynomial time algorithm, &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt;, and a sufficiently large &lt;span class="math"&gt;\(n\)&lt;/span&gt;&amp;#8217;s,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
        \text{Pr}[A&amp;#39;(f(x)) \notin f^{-1}(f(x))] &amp;gt; \frac{1}{p(n)}
      \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;In definition [strong-owf] the probability that &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt; could invert &lt;span class="math"&gt;\(f\)&lt;/span&gt; has an upper bound of &lt;span class="math"&gt;\(p(\cdot)^{-1}\)&lt;/span&gt; for &lt;em&gt;every&lt;/em&gt; positive polynomial. In definition [weak-owf], there is a &lt;em&gt;single&lt;/em&gt; positive polynomial, &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, such that &lt;span class="math"&gt;\(p(\cdot)^{-1}\)&lt;/span&gt; is a lower bound on the failure of any efficient inversion algorithm. Unlike strong one way functions, weak one way functions are not hard for typical instances. However, they are hard for some percentage of instances.&lt;/p&gt;
&lt;h3&gt;Amplification of Weak One Way Functions&lt;/h3&gt;
&lt;p&gt;Since weak functions are hard for a non-negligible percentage of inputs they can be used to construct strong functions. The proof for this bold assertion is given by Goldreich.&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn16" class="footnoteRef" id="fnref16"&gt;16&lt;/a&gt;&lt;/sup&gt; Since one can convert a weak one way function into a strong one it suffices to find weak ones. While a strongly one way function may yield a more efficient cryptosystem a weak one will still allow a secure system (as discussed in section [secure-encryption]).&lt;/p&gt;
&lt;h2&gt;Hard Core Predicates&lt;/h2&gt;
&lt;p&gt;If Alice has a strong one way function &lt;span class="math"&gt;\(f\)&lt;/span&gt;, computes &lt;span class="math"&gt;\(y = f(x)\)&lt;/span&gt;, and sends &lt;span class="math"&gt;\(y\)&lt;/span&gt; to Bob while Eve eavesdrops what can Eve learn about &lt;span class="math"&gt;\(x\)&lt;/span&gt;? Depending on the function &lt;span class="math"&gt;\(f\)&lt;/span&gt; Eve may be able to learn a surprising amount. Since &lt;span class="math"&gt;\(f\)&lt;/span&gt; is hard to invert Eve cannot learn everything about &lt;span class="math"&gt;\(x\)&lt;/span&gt; but she may not need too. Is there some way to quantify which bits of &lt;span class="math"&gt;\(x\)&lt;/span&gt; Eve can learn about and which bits she can&amp;#8217;t?&lt;/p&gt;
&lt;p&gt;There is! The bits which are hard for a polynomial attacker (like Eve) to learn about are called the &amp;#8220;Hard Core&amp;#8221; of a one way function. A predicate is a yes/no question, for example: Does &lt;span class="math"&gt;\(x\)&lt;/span&gt; end with a 0? If a yes/no question is hard for Eve to answer it is called a Hard Core Predicate. Since a yes/no question only has 2 possible answers Eve can always guess the answer. Therefore, a predicate is only hard for her to answer if she can&amp;#8217;t do better than get it right about half the time. To be precise:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
  \text{Pr}[\text{EveGuess\_P}(y) = P(x)] \le \frac{1}{2} + neg(|x|)\end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;where &lt;span class="math"&gt;\(neg(\vert x\vert )\)&lt;/span&gt; is a negligible function (as defined in definition [neg]). This description of Eve trying to guess something about &lt;span class="math"&gt;\(x\)&lt;/span&gt;, like whether it starts with 0, leads nicely into a formal definition:&lt;/p&gt;
&lt;p&gt;Hard-Core Predicates&lt;sup&gt;&lt;a href="#fn17" class="footnoteRef" id="fnref17"&gt;17&lt;/a&gt;&lt;/sup&gt; [hardcore]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A polynomial time computable predicate, &lt;span class="math"&gt;\(b : \{0,1\}^* \rightarrow
    \{0,1\}\)&lt;/span&gt;, is called a &lt;strong&gt;hard-core&lt;/strong&gt; of a function, &lt;span class="math"&gt;\(f\)&lt;/span&gt;, if for every probabilistic polynomial time algorithm &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt;, every positive polynomial &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, and all sufficiently large &lt;span class="math"&gt;\(|x|\)&lt;/span&gt;&amp;#8217;s,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      \text{Pr}[A&amp;#39;(f(x)) = b(x)] &amp;lt; \frac{1}{2} + \frac{1}{p(|x|)}
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Given a hard to invert function, &lt;span class="math"&gt;\(f\)&lt;/span&gt;, one knows some of the bits in its input must be hard to predict from the output. How does one know which bits are the hard bits? In general deciding what bits are hard for a function is difficult but one can always construct a Hard-Core Predicate for any strong one way function. Since one can always construct a strong one way function from a weak function this poses no limitation to the framework.&lt;/p&gt;
&lt;h3&gt;Constructing Hard-Core Predicates&lt;/h3&gt;
&lt;p&gt;The following result was first proved in 1982 by Yao but we present a simplification due to Goldreich and Levin as presented by Talbot and Welsh.&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn18" class="footnoteRef" id="fnref18"&gt;18&lt;/a&gt;&lt;/sup&gt; A detailed proof is available as usual in the Goldreich book.&lt;span class="citation"&gt;&lt;/span&gt;&lt;sup&gt;&lt;a href="#fn19" class="footnoteRef" id="fnref19"&gt;19&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Hard-Core Predicates from Strong One Way Functions [con-hard]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math"&gt;\(f\)&lt;/span&gt; be an arbitrary strong one way function. Let &lt;span class="math"&gt;\(g\)&lt;/span&gt; be defined as &lt;span class="math"&gt;\(g(x, r) = (f(x), r)\)&lt;/span&gt;, where &lt;span class="math"&gt;\(|x| = |r|\)&lt;/span&gt;. Let &lt;span class="math"&gt;\(r\)&lt;/span&gt; be a random bit string. Then define &lt;span class="math"&gt;\(B(x, r)\)&lt;/span&gt; to be a Hard-Core Predicate of &lt;span class="math"&gt;\(g\)&lt;/span&gt; by:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      B(x,r) &amp;amp;= \sum\limits^{|x|}_{i=1} x_i r_i \imod{2} \\
             &amp;amp;= \bar{x} \cdot \bar{r} \imod{2} 
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The theorem states, if &lt;span class="math"&gt;\(f\)&lt;/span&gt; is strongly one way then it will be hard to guess the result of taking an exclusive-or of a random subset of &lt;span class="math"&gt;\(x\)&lt;/span&gt; given &lt;span class="math"&gt;\(f(x)\)&lt;/span&gt; and the subset &lt;span class="math"&gt;\(r\)&lt;/span&gt;. If &lt;span class="math"&gt;\(B(x,r)\)&lt;/span&gt; is not a hard-core of &lt;span class="math"&gt;\(g\)&lt;/span&gt; then &lt;span class="math"&gt;\(f\)&lt;/span&gt; is easily invertible. The proof involves constructing an algorithm from the predictor for &lt;span class="math"&gt;\(B\)&lt;/span&gt;. For details on the construction once again see Goldreich.&lt;/p&gt;
&lt;p&gt;With the result of theorem [con-hard] and the ability to construct strong one way functions from weak one way functions one will always be able to construct a function where at least one predicate on &lt;span class="math"&gt;\(x\)&lt;/span&gt; is hard to compute. If one bit is not enough it turns out &lt;em&gt;hard-core functions&lt;/em&gt; are also constructable. However, their specific details are well out of the scope of this paper.&lt;/p&gt;
&lt;h2&gt;Constructing One Way Functions&lt;/h2&gt;
&lt;p&gt;It one is going to build a crypto-system based on hard computational problems (specifically strong one way functions) one should have some way of identifying such problems. From a practical perspective there are three number theoretic based problems which are assumed to be one way functions. The first is the discrete log problem: &lt;span class="math"&gt;\(g^x \equiv y \imod{p}\)&lt;/span&gt;, second finding square roots mod &lt;span class="math"&gt;\(N = pq\)&lt;/span&gt;, and third the &amp;#8220;RSA&amp;#8221; problem &lt;span class="math"&gt;\(c \equiv x^e \imod{N}\)&lt;/span&gt;. While these problems are likely to be used in practice none of them are suspected to be in the class NP-Hard. While, instances of problems in NP-Hard may be efficiently solvable there is good evidence they are not. In contrast these problems are potentially vulnerable to good approximation algorithms.&lt;/p&gt;
&lt;p&gt;Thus, an open problem for the aspiring cryptographer to tackle is to suggest a novel one way function. However, serious care needs to be exercised when suggesting such a function. It is not good enough for the function to be difficult in the &lt;em&gt;worst-case&lt;/em&gt; it must be difficult in the typical case. Average case complexity analysis relies heavily on the input distribution. Thus, the input distribution must be carefully characterized and uniform sampling techniques must be developed. Without exercising such care the aspiring cryptographer may fall into the trap of defining something which appears secure from a cursory theoretical glance but on close inspection is quite vulnerable.&lt;/p&gt;
&lt;h1&gt;Secure Encryption&lt;/h1&gt;
&lt;p&gt;[secure-encryption]&lt;/p&gt;
&lt;p&gt;Secure encryption schemes are naturally built on top of strong one way functions with hard-core predicates. However, before the encryption schemes can be defined a formal definition of security must be stated. Until now, our definition has been colloquial: information in the ciphertext should be computationally infeasible to extract. The informal definition is too vague for use in defining an encryption system because the security definition is more important than the cryptographic system itself. A proper definition ensures systems conforming to the definition will be more difficult to attack.&lt;/p&gt;
&lt;h2&gt;Security Definitions&lt;/h2&gt;
&lt;p&gt;[sec-def]&lt;/p&gt;
&lt;p&gt;Before rigorously defining a modern definition of security let us turn once again to classical security and &lt;em&gt;perfect-secrecy&lt;/em&gt;. Recall perfect secrecy says an attackers &lt;em&gt;uncertainty&lt;/em&gt; about a message should not be reduced when in possession of a corresponding ciphertext. As noted in the introduction, the obvious criticism of &lt;em&gt;perfect-secrecy&lt;/em&gt; is the implied key length. In such a system, the length of the key must be at least as long as the message. Making the definition impractical for most modern uses of cryptography. Therefore, a new definition is indeed necessary.&lt;/p&gt;
&lt;h3&gt;Polynomial Indistinguishability&lt;/h3&gt;
&lt;p&gt;The first definition we will consider is &lt;em&gt;polynomial-indistinguishability&lt;/em&gt;. Informally, if Alice has two messages, &lt;span class="math"&gt;\(M_1\)&lt;/span&gt; and &lt;span class="math"&gt;\(M_2\)&lt;/span&gt; and she sends Bob a ciphertext, &lt;span class="math"&gt;\(C\)&lt;/span&gt;, Eve who has been given both messages and the ciphertext will have no easy way to determine which message it corresponds to. Something is easy for Eve if she can do it in probabilistic polynomial time. Indeed, it is assumed none of our characters can do any computations except easy ones. Formally,&lt;/p&gt;
&lt;p&gt;Polynomial Indistinguishability of Encryptions&lt;sup&gt;&lt;a href="#fn20" class="footnoteRef" id="fnref20"&gt;20&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An encryption scheme, &lt;span class="math"&gt;\((G, E, D)\)&lt;/span&gt;, where &lt;span class="math"&gt;\(G\)&lt;/span&gt; generates keys, &lt;span class="math"&gt;\(E\)&lt;/span&gt; encrypts messages, and &lt;span class="math"&gt;\(D\)&lt;/span&gt; decrypts messages has &lt;em&gt;indistinguishable encryptions&lt;/em&gt; if for every probabilistic polynomial time algorithm, &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt;, every polynomial &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, all sufficiently large &lt;span class="math"&gt;\(n\)&lt;/span&gt;, and every &lt;span class="math"&gt;\(x,y \in
    \{0,1\}^{\text{poly}(n)}\)&lt;/span&gt; with &lt;span class="math"&gt;\(|x| = |y|\)&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      | \text{Pr}[A&amp;#39;(E_{G(1^n)}(x)) = 1] - 
        \text{Pr}[A&amp;#39;(E_{G(1^n)}(y)) = 1] |  &amp;lt;  \frac{1}{p(n)}
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The above definition was written with a symmetric encryption and decryption keys. However, the public key version only has minor and unimportant complications. The importance of the definition is in the intuition. Eve, the attacker, knows both messages and she has a ciphertext. The only thing she does not know is the key used to create the ciphertext. If the system is polynomially indistinguishable then Eve can only guess which message the ciphertext corresponds to. Since there are two messages she will only get it right half the time. If she can get it right better than half the time then the system is &lt;em&gt;not&lt;/em&gt; polynomially indistinguishable.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;security&lt;/em&gt; of the definition is perhaps non-obvious but consider the case were Eve can distinguish which message the ciphertext corresponds too. If the system was supposed to have &lt;em&gt;perfect-secrecy&lt;/em&gt; then clearly the secrecy would have been violated. Some bit of information would be leaking from the message to the ciphertext. Therefore, what the definition is saying is no information is leaking from the message to the ciphertext which can be extracted in polynomial time.&lt;/p&gt;
&lt;h3&gt;Semantic Security&lt;/h3&gt;
&lt;p&gt;The intuitive explanation of polynomial indistinguishability is captured in an alternative definition: &lt;em&gt;semantic-security&lt;/em&gt;. A crypto-system is semantically secure if any piece of information Eve can compute given a ciphertext she could just as easily compute without the ciphertext. That is, the ciphertext provides Eve with no advantage for computing any piece of information of interest to her. Formally,&lt;/p&gt;
&lt;p&gt;Semantic Security&lt;sup&gt;&lt;a href="#fn21" class="footnoteRef" id="fnref21"&gt;21&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An encryption scheme, &lt;span class="math"&gt;\((G, E, D)\)&lt;/span&gt;, where &lt;span class="math"&gt;\(G\)&lt;/span&gt; generates keys, &lt;span class="math"&gt;\(E\)&lt;/span&gt; encrypts messages, and &lt;span class="math"&gt;\(D\)&lt;/span&gt; decrypts messages is &lt;em&gt;semantically secure&lt;/em&gt; if for every probabilistic polynomial time algorithm, &lt;span class="math"&gt;\(A\)&lt;/span&gt;, there exists another probabilistic polynomial time algorithm, &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt;, such that for every message &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; of length &lt;span class="math"&gt;\(n\)&lt;/span&gt;, every pair of functions with polynomially bounded output &lt;span class="math"&gt;\(f,h : \{0,1\}^* \rightarrow \{0,1\}^*\)&lt;/span&gt;, every polynomial &lt;span class="math"&gt;\(p(\cdot)\)&lt;/span&gt;, and all sufficiently large &lt;span class="math"&gt;\(n\)&lt;/span&gt;,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      \text{Pr}[A(1^n, E_{G_1(1^n)}(\mathcal{M}), h(1^n, \mathcal{M})] =
                                                        f(1^n,\mathcal{M})] \\
                                  &amp;lt;
      \text{Pr}[A&amp;#39;(1^n, h(1^n, \mathcal{M})] = f(1^n,\mathcal{M})] +
                                                        \frac{1}{p(n)}
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the above definition, &lt;span class="math"&gt;\(f\)&lt;/span&gt; represents the information Eve would like to compute. The information Eve wants, &lt;span class="math"&gt;\(f\)&lt;/span&gt;, is a function of the message and the length of the message (encoded for technical reasons in unary). The output of &lt;span class="math"&gt;\(f\)&lt;/span&gt; is polynomial however it is not necessary for &lt;span class="math"&gt;\(f\)&lt;/span&gt; to be a &lt;em&gt;computable&lt;/em&gt; function. The algorithm &lt;span class="math"&gt;\(A\)&lt;/span&gt; guesses &lt;span class="math"&gt;\(f\)&lt;/span&gt; using the ciphertext, the length of the message, and &lt;span class="math"&gt;\(h\)&lt;/span&gt;. The algorithm &lt;span class="math"&gt;\(A&amp;#39;\)&lt;/span&gt; guesses &lt;span class="math"&gt;\(f\)&lt;/span&gt; using only the length of the message and &lt;span class="math"&gt;\(h\)&lt;/span&gt;. The function &lt;span class="math"&gt;\(h\)&lt;/span&gt; represents a polynomial amount of &lt;em&gt;a-priori&lt;/em&gt; knowledge about the output of &lt;span class="math"&gt;\(f\)&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The definition of semantic security intuitive says the probability Eve can guess &lt;span class="math"&gt;\(f\)&lt;/span&gt; utilizing the ciphertext is at most negligibly greater than guessing &lt;span class="math"&gt;\(f\)&lt;/span&gt; without the ciphertext. The definition places no restrictions on what Eve might be guessing (other than an upper bound on its size). Eve could be guessing whether the message is an order to move troops, or the message is a bank account number; it makes no difference to the definition.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Semantic-security&lt;/em&gt; is therefore the complexity theory analog of &lt;em&gt;perfect-secrecy&lt;/em&gt;. It provides assurance to the cryptographer that a polynomially bound cryptanalyst will be able to gain no information from the ciphertext. In practice, one only cares about polynomially bound adversaries since exponential adversaries do not exist.&lt;/p&gt;
&lt;h3&gt;Equivalence of Definitions&lt;/h3&gt;
&lt;p&gt;In a potentially surprising result it turns out it doesn&amp;#8217;t matter which security definition one uses, they imply each other:&lt;/p&gt;
&lt;p&gt;Equivalence of Definitions&lt;sup&gt;&lt;a href="#fn22" class="footnoteRef" id="fnref22"&gt;22&lt;/a&gt;&lt;/sup&gt; [equiv-thm]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;An encryption scheme is semantically secure if and only if it has indistinguishable encryptions.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, it is usually far easier to prove a scheme has indistinguishable ciphertexts. However, from a security perspective the property one actually wants is &lt;em&gt;semantic-security&lt;/em&gt;. Thus, theorem [equiv-thm] provides the cryptographer with an incredibly useful result.&lt;/p&gt;
&lt;h2&gt;A Secure Symmetric Key Encryption Scheme&lt;/h2&gt;
&lt;p&gt;To construct a perfectly secret symmetric key encryption scheme from an information theory perspective one first obtains a large amount of random information. One then takes a random bit for each bit of message and exclusive-ors them together. One now has the perfect cryptographic system. The construction of a semantically secure system is quite similar (in the case of stream ciphers). One takes a bit of random information, referred alternately as the seed of the key, stretches it to create a pseudo-random sequence the same length as the message. The message and the pseudo-random sequence are then xored together. This encryption scheme will clearly be semantically secure if no adversary can distinguish between the pseudo-random sequence and a truly random sequence.&lt;/p&gt;
&lt;h3&gt;Pseudo-Random Sequence Generators&lt;/h3&gt;
&lt;p&gt;A pseudo-random bit generator, &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; is defined as a deterministic polynomial time algorithm taking a bit-string, &lt;span class="math"&gt;\(x \in \{0,1\}^k\)&lt;/span&gt;, and outputting a longer string &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt;. In other words, the generator stretches the input. For the generator to be pseudo-random in nature, the output must be unpredictable if the input is random. Luckily, we already know how to produce bits which are essentially unguessable by a polynomial adversary. Hard-core predicates by construction cannot be guessed correctly better than half the time.&lt;/p&gt;
&lt;p&gt;A Pseudo-Random Generator can be Constructed from any One Way Permutation.&lt;sup&gt;&lt;a href="#fn23" class="footnoteRef" id="fnref23"&gt;23&lt;/a&gt;&lt;/sup&gt;&lt;sup&gt;&lt;a href="#fn24" class="footnoteRef" id="fnref24"&gt;24&lt;/a&gt;&lt;/sup&gt; [onebitgen]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math"&gt;\(f : \{0,1\}^* \rightarrow \{0,1\}^*\)&lt;/span&gt; be a one-way function length preserving permutation with a hard core predicate &lt;span class="math"&gt;\(B : \{0,1\}^*
    \rightarrow \{0,1\}\)&lt;/span&gt; then,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      &amp;amp;G : \{0,1\}^k \rightarrow \{0,1\}^{k+1} \\
      &amp;amp;G(x) = (f(x), B(x))
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;is a pseudo-random generator.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If &lt;span class="math"&gt;\(x\)&lt;/span&gt; is a random string, and therefore drawn from a uniform distribution over &lt;span class="math"&gt;\(\{0,1\}^k\)&lt;/span&gt;, then &lt;span class="math"&gt;\(f(x)\)&lt;/span&gt; is also a random string. Therefore, if there is some test, &lt;span class="math"&gt;\(T\)&lt;/span&gt;, which can distinguish &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; from a random string of length &lt;span class="math"&gt;\(k+1\)&lt;/span&gt; it must be distinguishing the last bit, &lt;span class="math"&gt;\(B(x)\)&lt;/span&gt;. Since, it can distinguish &lt;span class="math"&gt;\(B(x)\)&lt;/span&gt; from a random bit then one must be able to guess it significantly better than half the time. However, this contradicts &lt;span class="math"&gt;\(B(x)\)&lt;/span&gt; being a hard-core predicate of &lt;span class="math"&gt;\(f(x)\)&lt;/span&gt;. Therefore, &lt;span class="math"&gt;\(f\)&lt;/span&gt; is either not a one-way function or &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; is a pseudo-random generator.&lt;/p&gt;
&lt;p&gt;While, theorem [onebitgen] certainly constructs a pseudo-random number generator it is hardly a useful one. Recall, the issue with perfect secrecy was the key size. If one constructed a stream cipher from using theorem [onebitgen] one would only save 1 bit of key size over a one time pad. Luckily, the following extension also holds:&lt;/p&gt;
&lt;p&gt;An &lt;span class="math"&gt;\(l(k)\)&lt;/span&gt; Pseudo-Random Generator&lt;sup&gt;&lt;a href="#fn25" class="footnoteRef" id="fnref25"&gt;25&lt;/a&gt;&lt;/sup&gt; [gen]&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Let &lt;span class="math"&gt;\(f : \{0,1\}^* \rightarrow \{0,1\}^*\)&lt;/span&gt; be a one-way function length preserving permutation with a hard core predicate &lt;span class="math"&gt;\(B : \{0,1\}^*
    \rightarrow \{0,1\}\)&lt;/span&gt;. If &lt;span class="math"&gt;\(l(\cdot)\)&lt;/span&gt; is a positive polynomial then,&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
      &amp;amp;G : \{0,1\}^k \rightarrow \{0,1\}^{l(k)} \\
      &amp;amp;G(x) = (B(x), B(f(x)), B(f^2(x)), ..., B(f^{l(k)-1}(x)))
    \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;is a pseudo-random generator.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With the construction in theorem [gen] one can now generate a strong pseudo-random sequence. If &lt;span class="math"&gt;\(f\)&lt;/span&gt; is a strong one way function with a hard-core then no polynomial adversary can discern between the output of the generator above and a truly random string.&lt;/p&gt;
&lt;p&gt;A Symmetric Key Stream Cipher&lt;sup&gt;&lt;a href="#fn26" class="footnoteRef" id="fnref26"&gt;26&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;dl&gt;
&lt;dt&gt;Setup&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Alice chooses a short random key &lt;span class="math"&gt;\(x \in_{R} \{0,1\}^k\)&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Key Distribution&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Alice secretly shares &lt;span class="math"&gt;\(x\)&lt;/span&gt; with Bob.&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Encryption&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Alice encrypts an &lt;span class="math"&gt;\(m\)&lt;/span&gt;-bit message, &lt;span class="math"&gt;\(M\)&lt;/span&gt;, by generating a pseudo-random string:&lt;/p&gt;
&lt;p&gt;&lt;span class="math"&gt;\[\begin{aligned}
                          G(x) = (B(f(x)), B(f^2(x)), ..., B(f^m(x)))
                        \end{aligned}\]&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;and forming the cryptogram &lt;span class="math"&gt;\(C = G(x) \otimes M\)&lt;/span&gt;&lt;/p&gt;
&lt;/dd&gt;
&lt;dt&gt;Decryption&lt;/dt&gt;
&lt;dd&gt;&lt;p&gt;Bob creates the same string &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; an recovers the message via &lt;span class="math"&gt;\(M = G(x) \otimes C\)&lt;/span&gt;.&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/blockquote&gt;
&lt;p&gt;The strength of the cipher relies on the strength of &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; and the strength of &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; relies on the underlying properties of the one way function, &lt;span class="math"&gt;\(f\)&lt;/span&gt;. The above stream cipher is clearly semantically secure since the ciphertexts are indistinguishable by Eve. If Eve could distinguish the ciphertexts than she could predict &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt;. If Eve can predict &lt;span class="math"&gt;\(G(x)\)&lt;/span&gt; than &lt;span class="math"&gt;\(f\)&lt;/span&gt; must not be a one way function.&lt;/p&gt;
&lt;p&gt;While the above stream cipher is semantically secure, it is not necessarily the construction one would use in practice. Often, one would instead want to use a block cipher. Luckily, one can also construct block based ciphers from pseudo-random generators. For these an many other complications I refer you to Oded Goldreich&amp;#8217;s 2004 book.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Public Key Schemes&lt;/h2&gt;
&lt;p&gt;I will not discuss the public key schemes in detail. The definitions for security setup in section [sec-def] are implicitly for symmetric key systems. While, the modifications are fairly trivial they should be given proper treatment. In addition the public key systems deserve a thorough explanation. I will settle for some brief remarks.&lt;/p&gt;
&lt;p&gt;The RSA cryptographic system does not satisfy the property of polynomial indistinguishability. In particular, if Eve wants to tell whether &lt;span class="math"&gt;\(C\)&lt;/span&gt; corresponds to &lt;span class="math"&gt;\(M_1\)&lt;/span&gt; or to &lt;span class="math"&gt;\(M_2\)&lt;/span&gt; all she has to do is encrypt both messages can compare their ciphertexts. Eve and easily do this since the encryption algorithm in a public key system is public and therefore available to Eve.&lt;/p&gt;
&lt;p&gt;The encryption algorithm being publicly available seems to be an insurmountable obstacle at first, but it turns out to be possible to overcome it. In the case of the RSA algorithm one needs to introduce randomness (and thus uncertainty) into the encryption process. One such suggestion &lt;em&gt;Randomized RSA&lt;/em&gt; introduces random data into each encryption thus ensuring polynomial indistinguishability. However, Randomized RSA comes with a cost: one must believe a different strong assumption. One must assume RSA has a &amp;#8220;large&amp;#8221; hard-core of bits in the input. While, this may be a reasonable assumption it is a &lt;em&gt;different&lt;/em&gt; assumption and not implied by the usual RSA assumption. For details I once again commend you to Goldreich&amp;#8217;s 2004 book.&lt;span class="citation"&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h1&gt;Concluding Remarks&lt;/h1&gt;
&lt;p&gt;Basing cryptographic security on computation complexity is a sound practice. It yields systems with strong and extensible security guarantees. However, it also requires strong assumptions. In particular, we must believe in &amp;#8220;one way functions.&amp;#8221; While, there is good evidence they exist, and several candidate functions appear to work, we do not &lt;em&gt;know&lt;/em&gt; they exist. But, until a better formalism comes along complexity theory is secure in its position as the basis of modern cryptography.&lt;/p&gt;
&lt;div class="footnotes"&gt;
&lt;hr /&gt;
&lt;ol&gt;
&lt;li id="fn1"&gt;&lt;p&gt;See section 4.6.1&lt;a href="#fnref1"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn2"&gt;&lt;p&gt;See pages 2,3&lt;a href="#fnref2"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn3"&gt;&lt;p&gt;See page 3&lt;a href="#fnref3"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn4"&gt;&lt;p&gt;ie. time proportional to the size of the input&lt;a href="#fnref4"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn5"&gt;&lt;p&gt;See &lt;span class="citation"&gt;&lt;/span&gt; page 41 at the bottom.&lt;a href="#fnref5"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn6"&gt;&lt;p&gt;That is &lt;span class="math"&gt;\(\mathcal{M}\)&lt;/span&gt; computes in the &lt;span class="math"&gt;\(n\)&lt;/span&gt;th bit of output in &lt;span class="math"&gt;\(p(n)\)&lt;/span&gt; time.&lt;a href="#fnref6"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn7"&gt;&lt;p&gt;See &lt;span class="citation"&gt;&lt;/span&gt; page 23.&lt;a href="#fnref7"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn8"&gt;&lt;p&gt;Since a PTM is a theoretical construction rather than a physical construction we can do away with the nasty realities of life and assume these random bits are actually random! A nice change of pace.&lt;a href="#fnref8"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn9"&gt;&lt;p&gt;See section 4.2&lt;a href="#fnref9"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn10"&gt;&lt;p&gt;Note, any constant greater than &lt;span class="math"&gt;\(\frac{1}{2}\)&lt;/span&gt; can be used here.&lt;a href="#fnref10"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn11"&gt;&lt;p&gt;Definition is a combination of Definition 1.3.4 from &lt;span class="citation"&gt;&lt;/span&gt; and the definition given in Section 4.5 of &lt;span class="citation"&gt;&lt;/span&gt;.&lt;a href="#fnref11"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn12"&gt;&lt;p&gt;From personal discussion with Prof. Harold Connamacher (harold.connamacher@cwru.edu)&lt;a href="#fnref12"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn13"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 1.3.5&lt;a href="#fnref13"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn14"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 2.2.1. Note, I simplified the definition slightly for clarity.&lt;a href="#fnref14"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn15"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 2.2.2&lt;a href="#fnref15"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn16"&gt;&lt;p&gt;See Theorem 2.3.2 for an impractical but demonstrative conversion and Section 2.6 for an efficient conversion in the case of one-way permutations.&lt;a href="#fnref16"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn17"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 2.5.1&lt;a href="#fnref17"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn18"&gt;&lt;p&gt;Theorem 10.8&lt;a href="#fnref18"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn19"&gt;&lt;p&gt;Section 2.5.2&lt;a href="#fnref19"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn20"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 5.2.3, simplified.&lt;a href="#fnref20"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn21"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see Def. 5.2.1, simplified.&lt;a href="#fnref21"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn22"&gt;&lt;p&gt;Theorem (and proof) due to &lt;span class="citation"&gt;&lt;/span&gt; Theorem 5.2.5.&lt;a href="#fnref22"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn23"&gt;&lt;p&gt;Theorem and proof due to &lt;span class="citation"&gt;&lt;/span&gt; see theorem 10.9. My proof is a summary of Talbot and Welsh&amp;#8217;s main argument&lt;a href="#fnref23"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn24"&gt;&lt;p&gt;A one way permutation is simply a one way function which is a bijection from the domain to the range. The existence of one way functions implies the existence of one way permutations.&lt;a href="#fnref24"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn25"&gt;&lt;p&gt;Theorem due to &lt;span class="citation"&gt;&lt;/span&gt; see Theorem 10.10&lt;a href="#fnref25"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li id="fn26"&gt;&lt;p&gt;Definition due to &lt;span class="citation"&gt;&lt;/span&gt; see page 216.&lt;a href="#fnref26"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Programming Never Gets Easier</title><link href="https://hackthology.com/programming-never-gets-easier.html" rel="alternate"/><published>2013-11-10T00:00:00-05:00</published><updated>2013-11-10T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-10:/programming-never-gets-easier.html</id><summary type="html">&lt;p&gt;Another comment on
&lt;a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html"&gt;E.W.Dijkstra Archive: The Humble Programmer (EWD 340)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dijkstra, in the essay, felt that at the current moment in time (1972) the
programmer was limited by the tools. That their thought processes were limited
by poor languages and poor environment. However, he expressed great hope that …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Another comment on
&lt;a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html"&gt;E.W.Dijkstra Archive: The Humble Programmer (EWD 340)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Dijkstra, in the essay, felt that at the current moment in time (1972) the
programmer was limited by the tools. That their thought processes were limited
by poor languages and poor environment. However, he expressed great hope that
this was transitory. Our tools would improve but he warns:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As an aside I would like to insert a warning to those who identify the
difficulty of the programming task with the struggle against the inadequacies
of our current tools, because they might conclude that, once our tools will be
much more adequate, programming will no longer be a problem. Programming will
remain very difficult, because once we have freed ourselves from the
circumstantial cumbersomeness, we will find ourselves free to tackle the
problems that are now well beyond our programming capacity.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;I believe he was right. Some might argue are tools have not improved and that is
why programming is not better. Indeed they may say it is worse than ever. But, I
think our tools have improved. They don't always improve linearly but they are
improving in fits and starts, with steps forwards and steps back. No matter how
much our tools may have improved the state of programming as a practice has
barely advanced at all! We still struggle against our own inadequacies, our own
failings. Even when the algorithms are clear, the problem well studied, the
programmer rarely gets it right the first time. Programming doesn't get easier
as the tools get better. Rather the scope of our ambition climbs. As it climbs
the problems get harder and the tried and true solution of yesteryear seems
quaint to the practicing programmer of today.&lt;/p&gt;
&lt;p&gt;So, we cannot rest on our laurels. We must strive on and construct new tools
which ease our current pains, even if inevitably new pains arise. For, in
learning, there is suffering.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>New Site</title><link href="https://hackthology.com/new-site.html" rel="alternate"/><published>2013-11-06T00:00:00-05:00</published><updated>2013-11-06T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-11-06:/new-site.html</id><summary type="html">&lt;p&gt;It has been 6 months maybe more since Posterous shut down and I have just now
gotten around to recreating my site. I chose to do this on github pages with
pelican. Hosting on github is easy and simple. If github ever stops doing these
pages I can easily self …&lt;/p&gt;</summary><content type="html">&lt;p&gt;It has been 6 months maybe more since Posterous shut down and I have just now
gotten around to recreating my site. I chose to do this on github pages with
pelican. Hosting on github is easy and simple. If github ever stops doing these
pages I can easily self host. I have now ported most of my old posts thanks to
&lt;code&gt;pandoc&lt;/code&gt;. The posts I left behind were mostly terrible so all in all I think the
new site is a big improvement. I might even write some more posts.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>The Limits of Type Systems</title><link href="https://hackthology.com/the-limits-of-type-systems.html" rel="alternate"/><published>2013-09-03T00:00:00-04:00</published><updated>2013-09-03T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-09-03:/the-limits-of-type-systems.html</id><summary type="html">&lt;p&gt;&lt;a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html"&gt;E.W.Dijkstra Archive: The Humble Programmer (EWD 340)&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Argument three is based on the constructive approach to the problem of program
correctness. Today a usual technique is to make a program and then to test it.
But: program testing can be a very effective way to show the presence …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://www.cs.utexas.edu/users/EWD/transcriptions/EWD03xx/EWD340.html"&gt;E.W.Dijkstra Archive: The Humble Programmer (EWD 340)&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Argument three is based on the constructive approach to the problem of program
correctness. Today a usual technique is to make a program and then to test it.
But: program testing can be a very effective way to show the presence of bugs,
but is hopelessly inadequate for showing their absence. The only effective way
to raise the confidence level of a program significantly is to give a
convincing proof of its correctness.  But one should not first make the
program and then prove its correctness, because then the requirement of
providing the proof would only increase the poor programmer’s burden. On the
contrary: the programmer should let correctness proof and program grow hand in
hand.  Argument three is essentially based on the following observation. If
one first asks oneself what the structure of a convincing proof would be and,
having found this, then constructs a program satisfying this proof’s
requirements, then these correctness concerns turn out to be a very effective
heuristic guidance. By definition this approach is only applicable when we
restrict ourselves to intellectually manageable programs, but it provides us
with effective means for finding a satisfactory one among these.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Essentially what Dijkstra is advocating here is what the approach the most
advanced type theories are striving for. They aim to allow the programmer to
specify in the type system (a proof system) important semantic invariants of the
application. The type system is constructed in such a way the program is only
well typed if the specified invariants hold. The hope of the type theorists is
that with a sufficiently powerful type (proof) system most if the not all
properties one cares to prove are in fact provable (for certain programs).&lt;/p&gt;
&lt;p&gt;The difficulty for the practicing programmer is most type systems are not nearly
powerful enough to specify properties which are actually interesting.  This
leaves the programmer doing essentially the proof equivalent of book keeping
with no benefit. I should distinguish here between dynamically checked types
(properties) and statically checked types.  Dynamically checked, that is at run
time, are always enormously helpful to the programmer because they provide
runtime safety. However, statically checked types can be overly burdensome if
they require lots of book keeping without sufficiently powerful proofs.&lt;/p&gt;
&lt;p&gt;Unfortunately, for a wide variety of statically checked programming languages
the available proofs are uninteresting and the burden is high.  This is the
challenge to the Dijkstra-ist.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>We can't automate the programmer.</title><link href="https://hackthology.com/we-cant-automate-the-programmer.html" rel="alternate"/><published>2013-09-03T00:00:00-04:00</published><updated>2013-09-03T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-09-03:/we-cant-automate-the-programmer.html</id><summary type="html">&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=6317778"&gt;HN Comment&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I find this comment thread on how programmers will "automate" our way out of
jobs to be especially pertinent as I work on my proposal. A contention I have,
as do many others, is the primary practical challenge standing between us and
robust systems is complexity. There are …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://news.ycombinator.com/item?id=6317778"&gt;HN Comment&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I find this comment thread on how programmers will "automate" our way out of
jobs to be especially pertinent as I work on my proposal. A contention I have,
as do many others, is the primary practical challenge standing between us and
robust systems is complexity. There are several on this thread who believe we
have essentially mastered complexity for a broad number important application
areas.&lt;/p&gt;
&lt;p&gt;I think I could be convinced of this argument as long as those application areas
are very narrow. As long as the creators of those applications are content with
relatively standardized solutions. The moment there are A) functional
requirements not covered by the standard case or B) differentiating requirements
(such as aesthetics etc...) the general tool stops working. This is what makes
complexity such a beast.  If you make a fully generic tool, you have created a
programming language. Perhaps a very high level (even graphical language like
LabView) but still a language. Such things require trained people to operate.&lt;/p&gt;
&lt;p&gt;We will never not need programmers.&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Always Pertinent - C a giant leap backwards.</title><link href="https://hackthology.com/always-pertinent-c-a-giant-leap-backwards.html" rel="alternate"/><published>2013-08-25T00:00:00-04:00</published><updated>2013-08-25T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2013-08-25:/always-pertinent-c-a-giant-leap-backwards.html</id><summary type="html">&lt;blockquote&gt;
&lt;p&gt;From the point of view of software engineering, the rapid spread of C
represented a great leap backward. It revealed that the community at large had
hardly grasped the true meaning of the term 'high-level language' which became
an ill-understood buzzword. What, if anything, was to be 'high-level'? As this …&lt;/p&gt;&lt;/blockquote&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;From the point of view of software engineering, the rapid spread of C
represented a great leap backward. It revealed that the community at large had
hardly grasped the true meaning of the term 'high-level language' which became
an ill-understood buzzword. What, if anything, was to be 'high-level'? As this
issue lies at the core of software engineering, we need to elaborate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;from : Wirth, N. (2008). &lt;em&gt;A Brief History of Software Engineering&lt;/em&gt;. IEEE Annals
of the History of Computing, 30(3), 32–39.  doi:10.1109/MAHC.2008.33&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Passmash - The Site Specific Password Munger</title><link href="https://hackthology.com/passmash-the-site-specific-password-munger.html" rel="alternate"/><published>2012-01-30T00:00:00-05:00</published><updated>2012-01-30T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2012-01-30:/passmash-the-site-specific-password-munger.html</id><summary type="html">&lt;p&gt;&lt;a href="https://github.com/timtadh/passmash"&gt;Passmash&lt;/a&gt; is a new commandline
password munger. It has been tested to work on Linux with X and on
MacOS. It should also work on Windows.&lt;/p&gt;
&lt;h2&gt;What is a Munger?&lt;/h2&gt;
&lt;p&gt;A munger takes a password and turns it into another password, "munging"
it. In particular &lt;code&gt;passmash&lt;/code&gt; takes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A password (supplied …&lt;/li&gt;&lt;/ul&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://github.com/timtadh/passmash"&gt;Passmash&lt;/a&gt; is a new commandline
password munger. It has been tested to work on Linux with X and on
MacOS. It should also work on Windows.&lt;/p&gt;
&lt;h2&gt;What is a Munger?&lt;/h2&gt;
&lt;p&gt;A munger takes a password and turns it into another password, "munging"
it. In particular &lt;code&gt;passmash&lt;/code&gt; takes&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A password (supplied interactively at the prompt)&lt;/li&gt;
&lt;li&gt;A URL (or other identifier) (supplied as a command line argument)&lt;/li&gt;
&lt;li&gt;A secret key (kept at \~/.ssh/passmash.key)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;and returns a password. It has the advantages of a password manager
without having to worry about syncing a password database. The key file
is static, so simply keep a (possibly encrypted) backup of it. If you
loose the key file, you will not be able to recover your passwords.&lt;/p&gt;
&lt;h2&gt;Example Usage&lt;/h2&gt;
&lt;p&gt;In most circumstances you will want to use the &lt;code&gt;pm&lt;/code&gt; command&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pm&lt;span class="w"&gt; &lt;/span&gt;myurlhere.com
Password:
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This command automatically generates and copies the password to you
clipboard. On Linux it uses &lt;code&gt;xclip -selection clipboard&lt;/code&gt;, on Mac OS X it
uses &lt;code&gt;pbcopy&lt;/code&gt; and on Windows it uses &lt;code&gt;clip&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If it is on another operating system (like OpenBSD) it will pretty print
the password for easy typing. eg.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pm&lt;span class="w"&gt; &lt;/span&gt;myurlhere.com
&lt;span class="c1"&gt;## We don&amp;#39;t yet support OpenBSD for autoclipboard copying&lt;/span&gt;
Password:

5KrUw4pBgC89LGxggXEIFtjM41aPc+/GxH+cumCuTo4
5KrUw&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;4pBgC&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;89LGx&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;ggXEI&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;FtjM4&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;1aPc+&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;/GxH+&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;cumCu&lt;span class="w"&gt; &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;To4
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Technical Details&lt;/h2&gt;
&lt;p&gt;Passmash uses a SHA256 based HMAC with &lt;a href="http://en.wikipedia.org/wiki/Key_stretching"&gt;key
strengthening&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;mash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;hmac&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;xrange&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;250000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;digest&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On my machine (a 2.0 Ghz Core2) it takes around 1 second to derive a
password using this function. A more secure version of the same utility
could make use of &lt;code&gt;bcrypt&lt;/code&gt; or &lt;code&gt;scrypt&lt;/code&gt;. However, either would add an
external dependency.&lt;/p&gt;
&lt;p&gt;This password derivation function should provide strong defense against
an attacker who has&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A password generated from the function (perhaps obtained from a
    hacked website).&lt;/li&gt;
&lt;li&gt;The algorithm. (eg. they know you use this program to generate your
    passwords).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And optionally:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The key file&lt;/li&gt;
&lt;li&gt;&lt;em&gt;or&lt;/em&gt; the "master" password (but not both)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your "master" password has sufficient
&lt;a href="http://en.wikipedia.org/wiki/Entropy_%28information_theory%29"&gt;entropy&lt;/a&gt;
then your other passwords generated with the same key should be
reasonably secure against a brute force attack.&lt;/p&gt;
&lt;h3&gt;&lt;a href="https://github.com/timtadh/passmash"&gt;Happy Munging!&lt;/a&gt;&lt;/h3&gt;</content><category term="Blog"/></entry><entry><title>Ternary Search Tries for Fast Flexible String Search : Part 1</title><link href="https://hackthology.com/ternary-search-tries-for-fast-flexible-string-search-part-1.html" rel="alternate"/><published>2011-06-02T00:00:00-04:00</published><updated>2011-06-02T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2011-06-02:/ternary-search-tries-for-fast-flexible-string-search-part-1.html</id><summary type="html">&lt;p&gt;Searching a large corpus of strings is a problem many applications have
to solve, whether the application features autocomplete boxes or
full-text search. Efficient methods for conducting such searches are not
always readily apparent to the algorithm designer. In this series of
articles I will present a data structure known …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Searching a large corpus of strings is a problem many applications have
to solve, whether the application features autocomplete boxes or
full-text search. Efficient methods for conducting such searches are not
always readily apparent to the algorithm designer. In this series of
articles I will present a data structure known as the Ternary Search
Trie (TST) which is designed to assist in solving this problem. For this
introductory article I will not discuss algorithms in detail but only
provide a high level overview of the structure and algorithmic running
time for various operations. In the next article I will detail the
process of maintaining the structure with insertions and deletions. The
final article will discuss different flexible search algorithms and
their implementations.&lt;/p&gt;
&lt;h2&gt;Symbol Tables: A Short Review&lt;/h2&gt;
&lt;p&gt;A symbol table is a mapping between a string key and a value which can
be any type of object from an integer to a complex nested structure.
There are two classic symbol table implementations most programmers are
immediately familiar with: Binary Search Trees (BSTs) and hash tables.
Both of these structures work by exactly matching the search key to the
keys stored in the structure. If there does not exist an exact match
then there is a miss. Thus, neither of these structures can serve as
useful index for an autocomplete algorithm where only part of the key is
known. They may be useful for a full text index, but they will not be as
efficient as some of the other structures we will later discuss.&lt;/p&gt;
&lt;p&gt;While these simple structures are limited, other symbol table
implementations have properties more suited for modification for
flexible string search. This series will focus on the Trie category of
structures. These structures are more suited for partial match as we
will see. But first, why are hash tables not suited for this job? They
have such excellent running time characteristics, O(1) lookups! However,
one cannot modify the hash table algorithm to effectively serve the
purpose of a partial match or a range query. Why? Because hash functions
transform strings into numbers (which correspond to buckets in an
array). Good hash functions have wide variance in hashing strings and
will not hash a similar string or a sub string to the same bucket.&lt;/p&gt;
&lt;h2&gt;Introducing the Trie&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Example Binary Search Trie" src="/images/Trie1.png"&gt;&lt;/p&gt;
&lt;p&gt;Figure 1. &lt;strong&gt;An Example Binary Search Trie&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In general a Trie is a special for of a tree. However, instead of
comparing entire key at each node during traversal, it only compares
parts of keys. The key/value pairs are kept in the leaves (like in a B+
Tree). We will first consider a Binary Search Trie. Like the Binary
Search Tree, each node in the Trie has two children, left and right. The
left child is defined as the 0'' child and the right as the 1'' child.
As a key is inserted, a node is created or visited for each bit in the
key. When visiting a node which already exists, the direction to descend
is based on the current bit. that is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;let there be a function bit(i, s) which returns the ith bit in the
    string s.&lt;/li&gt;
&lt;li&gt;let depth(r, n) return the depth of the node n in the tree rooted at
    r&lt;/li&gt;
&lt;li&gt;bit(depth(r, n), s) is the bit in the string used to make the
    decision on which of n's children to visit.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sedgewick gives the formal definition: "A [binary search] trie is a
binary tree that has keys associated with each of its leaves, defined
recursively as follows: The trie for an empty set of keys is a null
link; the trie for a single key is a leaf containing that key; and the
trie for a set of keys of cardinality greater than one is an internal
node with left link referring to the trie for the keys whose initial bit
is 0 and right link referring to the trie for the keys whose initial bit
is 1, with the leading bit considered to be removed for the purpose of
constructing the subtrees."&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;A search using this structure is directed by the strings in the
database. However, since only one bit is considered at a time in the
search for a k-bit string the search will take in the worst case k bit
comparisons. This makes for a very tall structure when using string
keys, since single characters will be at least 8 bits long in ASCII and
much longer in Unicode. Another unfortunate implementation detail is
that modern processors typically work more efficiently when accessing
bytes or words. Thus, a more efficient structure might consider multiple
bits at once.&lt;/p&gt;
&lt;h2&gt;Multi-way Tries&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Example R-Way Trie" src="/images/Trie2.png"&gt;&lt;/p&gt;
&lt;p&gt;Figure 2. &lt;strong&gt;An Example R-Way Trie&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If one considers multiple bits at once one has to increase the fanout
(number of children per node) of the tree. Consider figure 2, in which
each node has a fanout of 26.&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; While useful if every
node has 26 children, the space to store the pointers becomes wasteful
for real data. However, despite the wasted space in comparison to the
binary version, searches on the R-Way Trie will perform faster than on
the Binary Trie. It will be faster for the CPU to compare the bytes
under consideration and there will be fewer comparisons over all. In
general, a Binary Trie will require log~2~(N) comparisons to perform a
search, and an R-way Trie it will take log~R~(N) comparisons.&lt;/p&gt;
&lt;p&gt;However, to produce a usable structure for our purpose (a large
in-memory string index) we need to cut down on the space wasted by the
extra pointers in each node. The tricky bit is to do this while still
maintaining the hard-fought gains in search speed. Simply using a
dynamic structure like a hash table in each node to hold the array won't
work either because hash tables are slower than an array access and if
the hash table becomes overly full it may actually use more space than
the array. Thus, a different structure is needed.&lt;/p&gt;
&lt;h2&gt;Ternary Search Tries&lt;/h2&gt;
&lt;p&gt;&lt;img alt="Example Ternary Search Trie" src="/images/TST1.png"&gt;&lt;/p&gt;
&lt;p&gt;Figure 3. &lt;strong&gt;An Example Ternary Search Trie&lt;/strong&gt; with strings [abc, abs,
awe, and].&lt;/p&gt;
&lt;p&gt;The Ternary Search Trie helps avoid the unnecessary space needed by a
traditional multi-way trie while still maintaining many of its
advantages. In a Ternary Search Trie each node contains a character and
three pointers. The pointers correspond to the current character under
consideration being less than, greater than or equal to the character
held by the node. In a sense this structure is like taking the Multi-way
Trie and encoding it on to a Binary Search Tree with the keys as current
character and the values as another BST corresponding to the next
character.&lt;/p&gt;
&lt;p&gt;While a Multi-way Trie has about R*N/log~2~(R) pointers, a Ternary
Search Trie has R + c*N pointers where c is a small constant, perhaps
3. Consider the graph of their performance:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Multi-way Trie vs. Ternary Search Trie" src="/images/Multiway_vs_Trie.gif"&gt;&lt;/p&gt;
&lt;p&gt;Figure 4. &lt;strong&gt;Links in a Multi-way Trie vs. a Ternary Search Trie&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When R is small, 2, 3, 4 Multi-way Tries and Ternary Tries have similar
a similar number of pointers, but a low branching factor destroys the
advantage of the Multi-way Trie. When R grows to a larger, more
reasonable size such as 256, the number of pointers explodes in
comparison to the Ternary Trie. Thus, the Ternary formulation will be
far more space efficient in the worst case than the Multi-way
formulation.&lt;/p&gt;
&lt;p&gt;What is the cost for better space efficiency? In the Multi-way Trie we
must traverse at most the length of the search key links. In a TST we
may need to traverse up to 3 times that many links in the worst case.
However, this pathological case is rare. In the average case the
situation can be made much better through a few small improvements to
the basic structure.&lt;/p&gt;
&lt;p&gt;&lt;img alt="An Improved Ternary Search Trie" src="/images/TST2.png"&gt;&lt;/p&gt;
&lt;p&gt;Figure 5. &lt;strong&gt;An Improved Ternary Search Trie&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;The first improvement, illustrated below in Figure 5, involves
collapsing the leaf nodes. Instead of allowing long chains of nodes at
the leaves, we collapse them into a single node. This allows the final
check to be computed efficiently.&lt;/p&gt;
&lt;p&gt;The second improvement, also illustrated in Figure 5, combines the best
of the Multi-way Search Trie with the Ternary Search Trie. The root node
is an R-Way node like in the Multi-way Search Trie. The rest of the tree
is a Ternary Search Trie with the leaf nodes collapsed. In practice
these improvements result in an enormous speedup. The theory also
supports the practice; according to Sedgewick, these improvements cut
the number of comparisons needed in half.&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;There is one final improvement to consider not shown the above figure.
Similar to the first improvement, it involves collapsing nodes, but
instead of collapsing leaf nodes, internal nodes are collapsed. This
idea is similar to the Patricia Trie. When a group of strings shares the
same contiguous substring, instead of having a node for each character
shared, collapse the shared nodes into a single node.&lt;/p&gt;
&lt;h1&gt;Conclusion and Whats Next&lt;/h1&gt;
&lt;p&gt;In this post we discussed the theory behind Symbol Tables and the use of
Tries as a symbol table implementation. The Trie, and in particular the
TST, is an efficient way to implement a symbol table. A good
implementation of a TST has comparable performance to a Hash Table.&lt;/p&gt;
&lt;p&gt;You can puruse my Go (golang)
&lt;a href="https://github.com/timtadh/data-structures/tree/master/trie"&gt;implementation&lt;/a&gt;
in
my &lt;a href="http://hackthology.com/data-structures"&gt;data-structures&lt;/a&gt; repository. I also
wrote a &lt;a href="https://github.com/timtadh/tst"&gt;python implementation&lt;/a&gt;.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Sedgewick R. &lt;em&gt;Algorithms&lt;/em&gt;. Third Edition. Definition 15.1.  &lt;a href="http://www.amazon.com/dp/0201314525/"&gt;&lt;/a&gt;&lt;a href="http://www.amazon.com/dp/0201314525/"&gt;http://www.amazon.com/dp/0201314525/&lt;/a&gt; Hereafter: &lt;em&gt;Sedgewick&lt;/em&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;Note: Usually an R-Way or Multi-Way Trie has a fanout equal to the numbers of characters in the character set or the number of bits in a machine word, half word or byte. So in practice a node in an R-Way Trie might have 256 children or perhaps 2\^16 children. As the fanout (the number of children per node) increases the space efficiency of the Trie decreases. However, the search speed increases. A classic time/space trace off.&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;em&gt;Sedgewick&lt;/em&gt; Table 15.2 and related text.&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>How To: Write Self Updating Python Programs Using Pip and Git</title><link href="https://hackthology.com/how-to-write-self-updating-python-programs-using-pip-and-git.html" rel="alternate"/><published>2011-05-23T00:00:00-04:00</published><updated>2011-05-23T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2011-05-23:/how-to-write-self-updating-python-programs-using-pip-and-git.html</id><summary type="html">&lt;p&gt;If you are a pip&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; and virtualenv user you already know how easy it is
to install python packages. Unlike the bad old days when I started
programming in Python, 9 years ago, it is now easy to add, remove and
manage python modules. In fact we can leverage …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you are a pip&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; and virtualenv user you already know how easy it is
to install python packages. Unlike the bad old days when I started
programming in Python, 9 years ago, it is now easy to add, remove and
manage python modules. In fact we can leverage pip to create an &lt;code&gt;update&lt;/code&gt;
command for a python program, for example and ease of illustration, a
shell utility.&lt;/p&gt;
&lt;h3&gt;Table of Contents&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Desired Features&lt;/li&gt;
&lt;li&gt;Basic Idea&lt;/li&gt;
&lt;li&gt;Implementation&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Desired Features&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Uses a server controlled by the owner (instead of the Python Package
  Index).&lt;/li&gt;
&lt;li&gt;Install an arbitrary version of the program.&lt;/li&gt;
&lt;li&gt;Defaults to updating to the newest version of the major release one
  is tracking.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I often want my programs to update themselves from a specific location.
For instance an internal server or perhaps my github account.
Fortunately pip already supports such nicities with the &lt;code&gt;-e&lt;/code&gt; for the
&lt;code&gt;install&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Additionally, when running a generic update you often want to stay on
the same major revision and simply get the bug fixes. However, it is
important to provide the option to update to any arbitrary release
including tracking the master branch.&lt;/p&gt;
&lt;h2&gt;Basic Idea&lt;/h2&gt;
&lt;p&gt;Use Pip and the &lt;code&gt;-e&lt;/code&gt; option plus a base URL to automatically update your
software. eg. Have you software run pip for the user.&lt;/p&gt;
&lt;p&gt;example command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install --upgrade --src=&amp;quot;$HOME/.src&amp;quot; -e git+&amp;lt;URL&amp;gt;@&amp;lt;REV&amp;gt;#egg=PACKAGE_NAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Tracking Major Versions&lt;/h4&gt;
&lt;p&gt;To track major version updates some care must be taken in setting up the
repository. I use branches instead of tags to track major releases. This
allows me to push out bug fix updates for every one tracking that
release. I tag minor releases to allow users to install a specific
version.&lt;/p&gt;
&lt;p&gt;Branches&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;master&lt;/li&gt;
&lt;li&gt;stable&lt;/li&gt;
&lt;li&gt;r0.1&lt;/li&gt;
&lt;li&gt;r0.2&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;rN&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Tags&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;r0.1&lt;/li&gt;
&lt;li&gt;r0.1.1&lt;/li&gt;
&lt;li&gt;r0.1.x&lt;/li&gt;
&lt;li&gt;...&lt;/li&gt;
&lt;li&gt;rN&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Pip Gotcha&lt;/h4&gt;
&lt;p&gt;When checking out branches using pip you have to supply
&lt;code&gt;origin/branchname&lt;/code&gt; ex:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--upgrade --src=&amp;quot;$HOME/.src&amp;quot; -e git+https://github.com/user/repo.git@origin/branch#egg=PACKAGE_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;While when checking out a commit you should not supply origin&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;pip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;install&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;--upgrade --src=&amp;quot;$HOME/.src&amp;quot; -e git+https://github.com/user/repo.git@COMMIT_ID#egg=PACKAGE_NAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Why does pip work like this? Because of the commands it executes. For
the command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pip install --upgrade --src=&amp;quot;$HOME/.src&amp;quot; -e git+https://github.com/user/repo.git@&amp;lt;VERSION&amp;gt;#egg=PACKAGE_NAME
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;pip runs&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git fetch -q git reset --hard -q &amp;lt;VERSION&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h4&gt;Store the tracked version in the source&lt;/h4&gt;
&lt;p&gt;To ensure the update command installs the correct updates I put which
release to checkout in the source code. This allows me to "release" a
version by creating a branch and then changing the RELEASE constant to
point the name of the branch.&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;p&gt;Note: This is example code only, you should modify for security and
stability of your enviroment.&lt;/p&gt;
&lt;p&gt;Note: I didn't include virtualenv support in this code but it is trivial
to add.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;subprocess&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;check_call&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt; 
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;getopt&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;getopt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;GetoptError&lt;/span&gt; 
&lt;span class="n"&gt;RELEASE&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;master&amp;#39;&lt;/span&gt; &lt;span class="c1"&gt;# default release &lt;/span&gt;
&lt;span class="n"&gt;SRC_DIR&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$HOME/.src&amp;quot;&lt;/span&gt; &lt;span class="c1"&gt;# checkout directory &lt;/span&gt;
&lt;span class="n"&gt;UPDATE_CMD&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="c1"&gt;# base command &lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;pip install --src=&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;quot; --upgrade -e &amp;#39;&lt;/span&gt; 
&lt;span class="s1"&gt;&amp;#39;git://github.com/timtadh/swork.git@&lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;#egg=swork&amp;#39;&lt;/span&gt; 
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@command&lt;/span&gt; 
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;getopt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;sr:&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sudo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;src=&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;release=&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;commit=&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; 
    &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="n"&gt;GetoptError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
        &lt;span class="n"&gt;usage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error_codes&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;option&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;False&lt;/span&gt; 
    &lt;span class="n"&gt;src_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;SRC_DIR&lt;/span&gt; 
    &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RELEASE&lt;/span&gt; 
    &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt; 
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;opts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-s&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--sudo&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
            &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt; 
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;-r&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;--release&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; 
            &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; 
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--src&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,):&lt;/span&gt; 
            &lt;span class="n"&gt;src_dir&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt; 
        &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;opt&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;--commit&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,):&lt;/span&gt; 
            &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;arg&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;isdigit&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="c1"&gt;## Check if it is a version &lt;/span&gt;
        &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;r&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt; 
    &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;origin/&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt; &lt;span class="c1"&gt;## assume it is a branch&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="c1"&gt;## if a commit is supplied use that &lt;/span&gt;
        &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UPDATE_CMD&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;commit&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;cmd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;UPDATE_CMD&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src_dir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;release&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;sudo &lt;/span&gt;&lt;span class="si"&gt;%s&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; 
        &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cmd&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;&lt;a href="http://www.pip-installer.org/en/latest/index.html"&gt;http://www.pip-installer.org/en/latest/index.html&lt;/a&gt; "A Python package installer."&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Announcing swork - Simplify your Shell Configuration</title><link href="https://hackthology.com/announcing-swork-simplify-your-shell-configuration.html" rel="alternate"/><published>2011-05-18T00:00:00-04:00</published><updated>2011-05-18T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2011-05-18:/announcing-swork-simplify-your-shell-configuration.html</id><summary type="html">&lt;p&gt;If you are like me, and if you are reading this you may very well be,
you spend an inordinate amount of time juggling inane details, like
shell environment variables, while programming. Now there is nothing
wrong with setting, exporting, and then unsetting variables, mounting
and unmounting FUSE partitions, starting …&lt;/p&gt;</summary><content type="html">&lt;p&gt;If you are like me, and if you are reading this you may very well be,
you spend an inordinate amount of time juggling inane details, like
shell environment variables, while programming. Now there is nothing
wrong with setting, exporting, and then unsetting variables, mounting
and unmounting FUSE partitions, starting routine backups, and so on but
it does get tedious after a while. Eventually, you may have written a
host of scripts to solve these various problems. Today I present
&lt;a href="https://github.com/timtadh/swork"&gt;swork&lt;/a&gt; (or start work) a command line
utility to help manage these little one off scripts with ease.&lt;/p&gt;
&lt;h1&gt;Don't Repeat Yourself&lt;/h1&gt;
&lt;p&gt;A typical pattern seen in scripts, such as virtualenv's activate script,
is the storing of old environment variables such that the changes made
by the script can be easily undone. Every non-trivial script I write
seems to include this detail, and I am tired of it. It is boring, it is
simple, and it is abstract-able. So I have abstracted. swork frees you
from needing to write this code. When you want to go back the original
state of the shell, you simply type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;swork&lt;span class="w"&gt; &lt;/span&gt;restore
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As long as you have run swork at some point in the past on the current
shell (or rather the current bash process) swork will restore
environment of the shell to the state it originally found it.&lt;/p&gt;
&lt;h1&gt;Writing Configuration Scripts&lt;/h1&gt;
&lt;p&gt;While, swork saves you the trouble of saving and restoring variables,
you still have to write the scripts to run. Fortunately, this is very
easy. You simply write a bash script (or any executable) then you add it
to the \~/.sworkrc (located conveniently in your home directory).&lt;/p&gt;
&lt;h3&gt;Example setenv file:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="nb"&gt;source&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;env/bin/activate&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# activate a virtualenv&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;SOMEVAR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;new value&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;some/new/stuff&amp;quot;&lt;/span&gt;:&lt;span class="nv"&gt;$PATH&lt;/span&gt;
&lt;span class="nb"&gt;export&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;PYTHONPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;more/new/stuff&amp;quot;&lt;/span&gt;:&lt;span class="nv"&gt;$PYTHONPATH&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;example .sworkrc file:&lt;/h3&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;project1&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/path/to/project1/root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;start_cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;source /path/to/project1/root/then/setenv&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;teardown_cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;echo &amp;#39;project1 teardown&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;project2&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/path/to/project2/root&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;start_cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;source /path/to/scripts/project2_setenv&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nt"&gt;&amp;quot;teardown_cmd&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;echo &amp;#39;project2 teardown&amp;#39;&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h1&gt;Wrapping Up&lt;/h1&gt;
&lt;p&gt;swork makes it easy for you to manage the environment on you shell
allowing you to switch contexts with minimum fuss. It currently
implements the minimum functionality to be useful, but is just waiting
for your feature request!&lt;/p&gt;
&lt;p&gt;check it out on github:
&lt;a href="https://github.com/timtadh/swork"&gt;https://github.com/timtadh/swork&lt;/a&gt;&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Grammars, Ambiguity, and Expressibility</title><link href="https://hackthology.com/grammars-ambiguity-and-expressibility.html" rel="alternate"/><published>2011-02-17T00:00:00-05:00</published><updated>2011-02-17T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2011-02-17:/grammars-ambiguity-and-expressibility.html</id><summary type="html">&lt;p&gt;Last night I gave a talk at CWRU Hacker Society about formal languages.
This is the first talk in a series of lectures I will be giving on
compilers. Unfortunately, unlike my regular expression talk I did not
get a recording of the audio. I may do a write up …&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last night I gave a talk at CWRU Hacker Society about formal languages.
This is the first talk in a series of lectures I will be giving on
compilers. Unfortunately, unlike my regular expression talk I did not
get a recording of the audio. I may do a write up of exactly what I
talked about later. Until then enjoy my "slides."&lt;/p&gt;
&lt;p&gt;&lt;iframe
  src="http://crocodoc.com/04Z8BP?embedded=true" height="600" width="100%"&gt;
&lt;/iframe&gt;
&lt;/p&gt;</content><category term="Blog"/></entry><entry><title>Interpreting the Free Software Movement as Religion</title><link href="https://hackthology.com/interpreting-the-free-software-movement-as-religion.html" rel="alternate"/><published>2010-12-08T00:00:00-05:00</published><updated>2010-12-08T00:00:00-05:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2010-12-08:/interpreting-the-free-software-movement-as-religion.html</id><summary type="html">&lt;p&gt;&lt;em&gt;A person should aspire to live an upright life openly with pride, and
this means saying “No” to proprietary software.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;- RMS&lt;/p&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;The Free Software movement which began in earnest twenty-five years ago
has become one of the most quietly influential movements of the Internet
age. Today, many social phenomenas …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;A person should aspire to live an upright life openly with pride, and
this means saying “No” to proprietary software.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;- RMS&lt;/p&gt;
&lt;h3&gt;Introduction&lt;/h3&gt;
&lt;p&gt;The Free Software movement which began in earnest twenty-five years ago
has become one of the most quietly influential movements of the Internet
age. Today, many social phenomenas occurring in our networked world,
such as Wikileaks, can be understood more completely by understanding
the Free Software movement. The Free Software movement can be usefully
analyzed from many perspectives however, this paper will use the lens of
religion. Specifically, the movement will be analyzed from the context
of selected writing from its founder, Richard M. Stallman, using the
categories defined by &lt;a href="http://en.wikipedia.org/wiki/Mircea_Eliade" title="Mircea Eliade"&gt;Mircea
Eliade&lt;/a&gt;.
Through the use of Eliade's categories one understands Stallman to be
demarcating the sacred from the profane in an attempt to return to an
archaic past.&lt;/p&gt;
&lt;h3&gt;Eliade's Terms and Categories&lt;/h3&gt;
&lt;p&gt;In his 1957 treatise, The Sacred and the Profane , Mircea Eliade creates
categories, such as sacred vs profane, and attempts to fit many
different religious traditions into the categories. Methodologically
this approach has a serious shortcoming, the supporting traditions do
not always fit well into the chosen categories. However, since Eliade
has defined broadly useful, even if not universally applicable,
categories for interpreting religious traditions. The utilization of
these categories highlights the religious nature of the Free Software.&lt;/p&gt;
&lt;p&gt;Eliade's primary purpose in his treatise is to discuss the experiential
demarcation between the sacred and the profane. Eliade defines the
sacred in two senses. The first is recursive: the sacred is the opposite
of the profane.&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt; In this sense one can place objects
into two categories, sacred and profane, as long as they don't overlap.
Eliade clarifies this slightly through use of Rudolf Otto's term, the
wholly other,&lt;sup id="fnref:2"&gt;&lt;a class="footnote-ref" href="#fn:2"&gt;2&lt;/a&gt;&lt;/sup&gt; indicating the sacred manifests itself as
wholly different than the profane. By using Otto's language, Eliade
indicates the sacred has an element to the divine.&lt;/p&gt;
&lt;p&gt;For the purposes of this paper we will stipulatively take the divine to
mean: that which seems to the individual to have a numinous quality. An
object which has a numinous quality is one which seems irreducible and
the individual thus feels a creature dependence
towards.&lt;sup id="fnref:3"&gt;&lt;a class="footnote-ref" href="#fn:3"&gt;3&lt;/a&gt;&lt;/sup&gt; Thus, the sacred is the manifestation of the
numinous into the corporeal. The profane, on the other hand, is the
common, that which seems to be understandable. These stipulative
definitions conform to Eliade's requirements: the sacred is opposite of
the profane, and the sacred is wholly different than the profane.&lt;/p&gt;
&lt;p&gt;In addition to his categories, sacred and profane, Eliade defines two
related categories: archaic society and modern society. The man who
lives in archaic society, homo religiosus, seeks to exist as much as
possible in or around the sacred.&lt;sup id="fnref:4"&gt;&lt;a class="footnote-ref" href="#fn:4"&gt;4&lt;/a&gt;&lt;/sup&gt; In contrast the man
of modern societies, modern man, exists in a desacralized
environment.&lt;sup id="fnref:5"&gt;&lt;a class="footnote-ref" href="#fn:5"&gt;5&lt;/a&gt;&lt;/sup&gt; The modern man depending on his
temperament may look back to the religious man either romantically or
derisively. Thus, modern and archaic do not indicate, as they
traditionally do, an essential ordering or time line. It may be that
archaic and modern coexist with each look back to the other as a
mythical past while eagerly looking forward to a time when man is more
or less religious.&lt;/p&gt;
&lt;h3&gt;The Free Software Movement&lt;/h3&gt;
&lt;p&gt;What is the Free Software movement? How can it be understood as
religious, using the terms and categories defined by Eliade? The Free
Software movement was started in 1984 with the publication of the GNU
Manifesto by Richard M. Stallman. Stallman had become disgusted with the
unethical nature of software and computer usage and sought a return to
an earlier time where users freely shared and modified programs. To
enable this return, he set about to create an ecosystem of software
which was protected from being made proprietary. In many ways Stallman
succeeded: today there is large amount of Free Software available. Every
computer user unwittingly uses such software on a daily basis, and
companies such as Google and Facebook could not exist without Free
Software.&lt;/p&gt;
&lt;p&gt;What unethical nature was Stallman disgusted with? The answer lies in
the GNU Manifesto where Stallman states, I consider that the golden rule
requires that if I like a program I must share it with other people who
like it. Software sellers want to divide the users and conquer them,
making each user agree not to share with others. I refuse to break
solidarity with other users in this way.&lt;sup id="fnref:6"&gt;&lt;a class="footnote-ref" href="#fn:6"&gt;6&lt;/a&gt;&lt;/sup&gt; It seems to
Stallman he should obey the golden rule. One may guess from the text
Stallman would define the golden rule as a principle of reciprocity.
Thus, if an individual likes a program and would want another to share
it with him he is ethically required to share the program with another
as well. Furthermore, an individual must not restrict those he shares
software with from further sharing the software, or from modifying the
software to suit their needs better. To prevent such sharing and
modification would violate his golden rule.&lt;sup id="fnref:7"&gt;&lt;a class="footnote-ref" href="#fn:7"&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;It is important to note Stallman does not believe that all things should
be shared alike. He only considers such freedom ethical where there is
no harm done to the person who shares by sharing. Stallman states:
"Owners say that they suffer harm or economic loss when users copy
programs themselves. But the copying has no direct effect on the owner,
and it harms no one.&lt;sup id="fnref:8"&gt;&lt;a class="footnote-ref" href="#fn:8"&gt;8&lt;/a&gt;&lt;/sup&gt; Thus, Stallman believes that
copying a program does not harm the original owner, because the owner
does not loose the use of the program because a copy is made. Such
copies can be made indefinitely. In the same way Stallman defends the
right to modify software: whether you run or change a program I wrote
affects you directly and me only indirectly. Whether you give a copy to
your friend affects you and your friend much more than it affects me. I
shouldnt have the power to tell you not to do these things. No one
should.&lt;sup id="fnref:9"&gt;&lt;a class="footnote-ref" href="#fn:9"&gt;9&lt;/a&gt;&lt;/sup&gt; Thus, Stallman has constructed his own ethical
system based on how the golden rule seemed to him.&lt;/p&gt;
&lt;p&gt;To explain and understand his movement, Stallman constructed a founding
narrative. The narrative begins in ancient times when copyright as a
concept did not exist. Stallman explains that in those times the roles
of authors, copiers, scribes, and commentators were muddled. Everyone
who participated in written culture freely copied, improved, and
commented on previous works.&lt;sup id="fnref:10"&gt;&lt;a class="footnote-ref" href="#fn:10"&gt;10&lt;/a&gt;&lt;/sup&gt; Stallman holds this
copyright-free society up as the exemplar from our historical past for
how one should relate to written work.&lt;/p&gt;
&lt;p&gt;Stallman continues his narrative by connecting the experiences of early
computer programmers (his in particular) to the copyright-free society
detailed above. While copyright existed when computing culture began in
the 40's and 50's it was not yet universally applied to computer source
code. Stallman participated in this society when he joined the MIT
Artificial Intelligence Lab in 1971: When I started working at the MIT
Articial Intelligence Lab in 1971, I became part of a software-sharing
community that had existed for many years. Sharing of software was not
limited to our particular community; it is as old as computers, just as
sharing of recipes is as old as cooking. But we did it more than
most.&lt;sup id="fnref:11"&gt;&lt;a class="footnote-ref" href="#fn:11"&gt;11&lt;/a&gt;&lt;/sup&gt; Stallman holds his early experiences in the AI
Lab as a second exemplar for the proper orders of society, where
software is freely shared, edited, commented, and ported.&lt;/p&gt;
&lt;p&gt;However, Stallman's perfect society eventually fell into disrepair.
Programmers were asked to sign software licenses and non disclosure
agreements when the university purchased new equipment and software. To
Stallman these events had a chaogonic&lt;sup id="fnref:12"&gt;&lt;a class="footnote-ref" href="#fn:12"&gt;12&lt;/a&gt;&lt;/sup&gt; quality: This
meant that the first step in using a computer was to promise not to help
your neighbor. A cooperating community was forbidden. The rule made by
the owners of proprietary software was, 'If you share with your
neighbor, you are a pirate. If you want any changes, beg us to make
them.'&lt;sup id="fnref:13"&gt;&lt;a class="footnote-ref" href="#fn:13"&gt;13&lt;/a&gt;&lt;/sup&gt; Thus, the ideal of community which had obeyed
the golden rule began to unravel. No longer could a programmer freely
help his neighbor, no longer could a programmer freely fix bugs, no
longer could a programmer port software to new platforms. The
programmers were now at the mercy of contracts and legal agreements.&lt;/p&gt;
&lt;p&gt;In the depths of this disarray, Stallman experienced a heirophany,
Eliade's term for the sacred manifesting itself. It began with the AI
Lab being gifted a printer from Xerox. However, despite giving them the
printer, Xerox refused to share the code for the
driver.&lt;sup id="fnref:14"&gt;&lt;a class="footnote-ref" href="#fn:14"&gt;14&lt;/a&gt;&lt;/sup&gt; Unfortunately, the driver had bugs in it.
When Stallman offered to fix the bugs if they gave him their code, they
refused. The experience was transformative. Stallman could no longer
accept the status quo of license and non-disclosure agreements. He set
out to change the world, so he could return to an ideal society where
programmers helped their neighbors.&lt;sup id="fnref:15"&gt;&lt;a class="footnote-ref" href="#fn:15"&gt;15&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Thus, according to Stallman's narrative detailed above, Stallman set out
to purge his life of the corrupting influence of proprietary software.
Unfortunately, to rid himself of proprietary software he needed to
create a new ecosystem of Free Software. So he quit his job at MIT and
began working on several Free Software programs. Stallman states: I
realized that I was elected to do the job.&lt;sup id="fnref:16"&gt;&lt;a class="footnote-ref" href="#fn:16"&gt;16&lt;/a&gt;&lt;/sup&gt; Thus, he
began the GNU project to create a Free operating system and ecosystem of
software. Without, such an ecosystem Stallman feels one cannot live an
upright life as a programmer.&lt;sup id="fnref:17"&gt;&lt;a class="footnote-ref" href="#fn:17"&gt;17&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Therefore, the Free Software movement seeks to establish an alternative
reality where all software written is Free. Users are free to modify and
redistribute software. No one is free to limit another's use of
software. This movement can be understood using Eliade's categories of
sacred vs profane, and archaic society vs modern society.&lt;/p&gt;
&lt;h3&gt;Interpretation&lt;/h3&gt;
&lt;p&gt;The copyright free societies Stallman references in his narrative
parallel the Eliadian concept of the archaic society. In both cases
these societies are held up as exemplars of what it means to be truly
religious, to be a homo religiosus. In Stallman's pre-copyright society,
programmers shared with each other freely, they modified programs
without hesitation; unwittingly they obeyed his golden rule and helped
their neighbors. In modern society programmers no longer share code and
modify programs. They are prevented from doing so. Thus, they no longer
obey the golden rule. By not obeying the golden rule they have become
corrupt.&lt;sup id="fnref:18"&gt;&lt;a class="footnote-ref" href="#fn:18"&gt;18&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Stallman's narrative fits into Eliade's categories of the modern society
vs. the archaic society. Stallman represents himself as a truly
religious person living in the modern society seeking to return to the
archaic society. His method for returning to the archaic society is to
resacralize the world.&lt;/p&gt;
&lt;p&gt;To sacralize, one must have a concept of something that is sacred vs.
something that is profane. For to sacralize one make the the profane
sacred. For Stallman, Free Sofware itself is sacred. Free Software is
opposite the profane proprietary software. Proprietary software cannot
be shared and it cannot be modified. Free Software can be explicitly
shared and modified. Free Software also manifests a numinous quality.
Specifically, Free Software is the revelation of the ideal divine
society today. In the ideal society all software is Free Software. To
have Free Software in present society is to experience the revelation of
the ideal. Thus, Free Software is not just sharable and modifiable it
also sacred. Free Software is Sacred Software.&lt;/p&gt;
&lt;p&gt;Stallman desires to return to his ideal archaic society where
programmers were more religious and users could share and modify
programs at will. To bring about the return of the archaic society he
must resacralize the present profane society. To do so he created the
GNU Project to manifest Sacred Software into the present profane space.
Thus, Stallman marks off the sacred, Free Software, from the profane,
proprietary software, in an attempt to return humanity to the ideal
society.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;The Free Software movement can be understood as a religious movement
using Eliade's terms and categories. Stallman basis his movement on his
understanding of the golden rule. He uses his understanding of the rule
to construct an ethical system for the production and use of software.
Stallman then constructs a narrative to explain how society has moved
from a religious ethical past to a profane present. To return society to
the ideal past, Stallman attempts resacralize the present society by
creating Free Software. Free Software is sacred. By introducing Free
Software into present society, society becomes more sacred. The
utilization of Eliade's categories clarified the religious aspects of
the Free Software movement.&lt;/p&gt;
&lt;hr&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Eliade, M.  &lt;a href="http://www.amazon.com/Sacred-Profane-Nature-Religion/dp/015679201X?tag=dudugo-20"&gt;&lt;em&gt;The Sacred and the Profane: The Nature of Religion&lt;/em&gt;&lt;/a&gt; trans. Trask, W. Harcourt Inc. New York. 1957. pg 10. Hearafter: &lt;em&gt;Sacred and Profane&lt;/em&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:2"&gt;
&lt;p&gt;&lt;em&gt;Ibib&lt;/em&gt;. pg 2. and Otto, R.  &lt;a href="http://www.amazon.com/Idea-Holy-R-Otto/dp/0195002105/"&gt;&lt;em&gt;The Idea of the Holy&lt;/em&gt;&lt;/a&gt; trans.  Harvey, J. Oxford University Press, New York. 1958. pg 25.  Hereafter: &lt;em&gt;The Holy&lt;/em&gt;&amp;#160;&lt;a class="footnote-backref" href="#fnref:2" title="Jump back to footnote 2 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:3"&gt;
&lt;p&gt;&lt;em&gt;The Holy&lt;/em&gt; pg. 6-7&amp;#160;&lt;a class="footnote-backref" href="#fnref:3" title="Jump back to footnote 3 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:4"&gt;
&lt;p&gt;&lt;em&gt;Sacred and Profane&lt;/em&gt; pg. 12, 15&amp;#160;&lt;a class="footnote-backref" href="#fnref:4" title="Jump back to footnote 4 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:5"&gt;
&lt;p&gt;&lt;em&gt;Sacred and Profane&lt;/em&gt; pg. 17&amp;#160;&lt;a class="footnote-backref" href="#fnref:5" title="Jump back to footnote 5 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:6"&gt;
&lt;p&gt;Stallman, R. M.  &lt;a href="http://shop.fsf.org/product/free-software-free-society/"&gt;&lt;em&gt;Free Software, Free Society: Selected Essays of Richard M. Stallman.&lt;/em&gt;&lt;/a&gt; GNU Press, Boston, 2002. pg. 34. Hereafter: &lt;em&gt;Free Software&lt;/em&gt;.&amp;#160;&lt;a class="footnote-backref" href="#fnref:6" title="Jump back to footnote 6 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:7"&gt;
&lt;p&gt;See &lt;em&gt;Free Software&lt;/em&gt; pg. 43 for a discussion of the precise meaning of Free Software.&amp;#160;&lt;a class="footnote-backref" href="#fnref:7" title="Jump back to footnote 7 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:8"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 48&amp;#160;&lt;a class="footnote-backref" href="#fnref:8" title="Jump back to footnote 8 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:9"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 49&amp;#160;&lt;a class="footnote-backref" href="#fnref:9" title="Jump back to footnote 9 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:10"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 39&amp;#160;&lt;a class="footnote-backref" href="#fnref:10" title="Jump back to footnote 10 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:11"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 17&amp;#160;&lt;a class="footnote-backref" href="#fnref:11" title="Jump back to footnote 11 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:12"&gt;
&lt;p&gt;Chaos creating, antonym of Cosmogonic. See Beal, T. K.  &lt;a href="http://www.amazon.com/Religion-Its-Monsters-Timothy-Beal/dp/0415925886"&gt;&lt;em&gt;Religion and its Monsters&lt;/em&gt;.&lt;/a&gt; Routledge, New York, 2002.&amp;#160;&lt;a class="footnote-backref" href="#fnref:12" title="Jump back to footnote 12 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:13"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 18&amp;#160;&lt;a class="footnote-backref" href="#fnref:13" title="Jump back to footnote 13 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:14"&gt;
&lt;p&gt;A driver is a piece of software which allow the computer to communicate with a piece of hardware. Every piece of hardware has a unique communication protocol, necessitating many different drivers.&amp;#160;&lt;a class="footnote-backref" href="#fnref:14" title="Jump back to footnote 14 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:15"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 19&amp;#160;&lt;a class="footnote-backref" href="#fnref:15" title="Jump back to footnote 15 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:16"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 19,20&amp;#160;&lt;a class="footnote-backref" href="#fnref:16" title="Jump back to footnote 16 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:17"&gt;
&lt;p&gt;&lt;em&gt;Free Software&lt;/em&gt; pg. 57&amp;#160;&lt;a class="footnote-backref" href="#fnref:17" title="Jump back to footnote 17 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li id="fn:18"&gt;
&lt;p&gt;For an example of Stallman using such language see for instance &lt;em&gt;Free Software&lt;/em&gt; pg. 130&amp;#160;&lt;a class="footnote-backref" href="#fnref:18" title="Jump back to footnote 18 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="Blog"/></entry><entry><title>Lessons Learned While Implementing a B+Tree</title><link href="https://hackthology.com/lessons-learned-while-implementing-a-btree.html" rel="alternate"/><published>2010-04-10T00:00:00-04:00</published><updated>2010-04-10T00:00:00-04:00</updated><author><name>Tim Henderson</name></author><id>tag:hackthology.com,2010-04-10:/lessons-learned-while-implementing-a-btree.html</id><summary type="html">&lt;p&gt;B+Trees are complex disk based trees used to index large amounts of
data. They are used in everything from file systems, to relation
databases, to new style databases gaining popularity today. Sometimes a
domain specific application needs to index a large amount of data, but
cannot use a traditional …&lt;/p&gt;</summary><content type="html">&lt;p&gt;B+Trees are complex disk based trees used to index large amounts of
data. They are used in everything from file systems, to relation
databases, to new style databases gaining popularity today. Sometimes a
domain specific application needs to index a large amount of data, but
cannot use a traditional database, or one of the NoSQL databases. In
such instances the development team needs to roll their own indices.
Here is an introduction to the B+Tree (one of the indexes my team
created) and lessons I learned while implementing it.&lt;/p&gt;
&lt;h2&gt;Introduction to the B+Tree&lt;/h2&gt;
&lt;p&gt;B+Trees are one of the fundamental index structures used by databases
today. This includes new style SQL free databases. The B+Tree popularity
stems from their performance approaching optimal performance in terms of
disk reads for range queries in a 1 dimensional space. What is a 1
dimensional space when talking about computer data which could be
anything (not just numbers)? It is any collection of objects where the
user accesses the object using only one attribute at a time.&lt;/p&gt;
&lt;p&gt;For example if we have an object which has X, Y, and Z as attributes
queries would only take place on X, or Y, or Z, but never on XY, or YZ,
or XZ, or XYZ. A collection where multiple attributes are used to access
the data elements are known as multidimensional spaces. For these spaces
there are many other structures which have better performance than
B+Trees.&lt;/p&gt;
&lt;p&gt;B+Trees perform particularly well (in comparison to some other indices)
when executing range queries. A range query is typically expressed as
inequality such as "give me all strings between 'blossom' and 'brunet.'"&lt;/p&gt;
&lt;p&gt;When I say their performance is approaching optimal in number of disk
reads what do I mean? Why are we not measuring performance in number of
instructions executed (like we do when we analyze a binary search)? In
memory algorithms and structures like sorted arrays and binary searches
are largely bound by the number CPU cycles it takes to execute the
algorithm. We usually neglect CPU cache performance and memory locality
when analyzing them, arguing these are constant in terms of the
asymptotic performance of the algorithm. However, for a disk based
structure like B+Trees the time it takes to read (or write) to a disk
becomes the dominant term, since disks are extremely slow in comparison
to main memory. Therefore for disk structures we analyze their
performance in terms of disk reads/writes.&lt;/p&gt;
&lt;h2&gt;Basic Structure of the B+ Tree&lt;/h2&gt;
&lt;p&gt;While I will not give a through explanation of the exact structure and
properties of B+ Tree (I leave that to algorithm and database textbooks
by the likes of Knuth, Sedgewick, and Ullman), I will describe its basic
structure.&lt;/p&gt;
&lt;p&gt;A B+Tree is best thought of as a key-value store. It is structured as a
generalized tree. Instead of having only one key in each node it has N
keys in each node, where N is referred to as the &lt;em&gt;degree&lt;/em&gt; of the B+Tree.
In the B+Tree there are 2 kinds of nodes, interior nodes, and exterior
(leaf) nodes. The interior nodes hold keys and pointers to nodes. The
exterior nodes hold keys and their associated values. This indicates
that the interior nodes have a different (usually higher) degree than
the exterior nodes.&lt;/p&gt;
&lt;p&gt;The reason the tree is structured this way is because it is rooted in
the nature of disk access. Disks to not return 1 byte when you ask for 1
byte instead they return what is called the disk block to which that
byte belongs, the operating system then sorts out which byte it is that
you need. B+Tree exploit the situation by making their nodes fit exactly
into the size of one disk block. Since the degree of the interior nodes
is high, this makes the tree extremely wide, which is a good thing since
it means fewer disk reads to find the value associated with any one key.&lt;/p&gt;
&lt;div style="text-align:center"&gt;
  &lt;a href="/images/bptree1.png"&gt;
    &lt;img
      alt="Example B+Tree"
      src="/images/bptree1.png"/&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;p&gt;Figure 1. &lt;strong&gt;An Example B+Tree&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In figure 1 you can see an example B+Tree. For this illustration I
neglect showing the values, and have the order of the interior nodes
equal to the order of the exterior nodes. In general this will not be
the case. One thing to note in this simple example is how the exterior
nodes are chained together in order. This is why it is efficient to
execute a range query on the B+Tree. One can simply find the first key
in the range, and then traverse the leaf nodes until the last key has
been found.&lt;/p&gt;
&lt;h2&gt;Implementing the B+Tree&lt;/h2&gt;
&lt;p&gt;I made the decision to use TDD (Test Driven Development) for
implementing the B+Tree. TDD has a lot of pluses when trying to create a
data structure of any kind. When implementing a data structure one
typically knows exactly how the structure should function, what it
should do, and what it should never do. By writing tests first, you can
ensure that when you finish a method, it actually works. This speeds
development time especially since you already know how the structure
should function. It makes it quicker to find bugs, and to battle test
the B+Tree. Since I have released the B+Tree to the rest of my team to
use, there has not yet been a bug filled against it.&lt;/p&gt;
&lt;p&gt;So knowing that we are using TDD, and knowing what the structure is and
how it performs. What is the best way to begin implementing this complex
structure? The way I started was to create a general structure called a
block file. My block files abstracted the notion of reading and writing
blocks (and buffering them). I also created objects to model a block
that could contain either keys and pointers, or keys and records
(instead of values from here on I will use the term records). Actually
my blocks are even more general than that as I intend to reuse them for
other disk based index structures like linear hashing in the future.&lt;/p&gt;
&lt;p&gt;I also created what I called a ByteSlice. My ByteSlice was an array of
bytes of arbitrary length. I use it to represent, keys, records, and
pointers; everything in the B+Tree. My ByteSlice implemented a
comparator, so it could be sorted, and conversions from integer types of
various lengths to the ByteSlice and back again. By implementing this
general type my B+Trees can easily deal with any kind of data and
perform in exactly the same way.&lt;/p&gt;
&lt;p&gt;After the infrastructure was created I began working on my first
iteration of the B+Tree. The first iteration was based on the algorithms
give by Robert Sedgewick in his excellent book "Algorithms in C++." I
managed to get this implementation up, running, and fully tested in a
matter of days. However, the version given by Sedgewick which inspired
my implementation did not deal gracefully with duplicate keys. Thus, I
need to invent my own way of handling duplicate keys.&lt;/p&gt;
&lt;h2&gt;Approaches to Handling Duplicate Keys in B+Trees&lt;/h2&gt;
&lt;p&gt;There are several different ways of handling duplicate keys. One way is
use an unmodified insert algorithm which allows duplicate keys in blocks
but is otherwise unchanged. The issue with a structure such as this is
the search algorithm must be modified to take into account several
corner cases which arise. For instance one of the invariants of a B+Tree
may be violated in this structure. Specifically if there are many
duplicate keys, a copy of one of the keys may be in a non-leaf block.
However, the key may appear in blocks that which appear logically before
the block which is pointed at by the key in the internal block. Thus the
search algorithm must be modified to look in the previous blocks to the
one suggested by the unmodified search algorithm. This will slow down
the common case for search.&lt;/p&gt;
&lt;p&gt;There is another issue with this straight forward implementation, if
there are many duplicate keys in the index, the index size may be taller
than necessary. Consider a situation were for each unique key there are
perhaps hundreds of duplicates, the index size will be proportional to
the total number of keys in the main file, however, you only need to
index an index on the unique keys. One of the files indexed in our
program will be indexing has such characteristics to its data. It
indexes strings (as the keys) with associated instances where those
strings show up in our documents. There can be hundreds to thousands of
instances of each unique string.&lt;/p&gt;
&lt;p&gt;Therefore the approach I took was to store only the unique keys in the
index, and have the duplicates captured in overflow blocks in the main
file. An example of such a tree can be seen in figure 2. Consider key 6;
there are 5 instances of this key in the tree. The tree is order 3,
indicating the keys cannot all fit in one block. To handle this
situation an overflow block is chained to the block which is indexed by
the tree structure. The overflow block then points to the next relevant
block in the tree.&lt;/p&gt;
&lt;div style="text-align:center"&gt;
  &lt;a href="/images/bptree2.png"&gt;
    &lt;img
      alt="Example B+Tree with Duplicate Keys"
      src="/images/bptree2.png"/&gt;
  &lt;/a&gt;
&lt;/div&gt;

&lt;p&gt;Figure 2. &lt;strong&gt;A B+Tree with duplicate keys and overflow blocks.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To create a structure such as this, the insert algorithm had to be
modified. Like the previous version these modifications do not come
without a cost, in particular the invariant which states all block must
be at least half full has been relaxed. This is not true in this B+Tree,
some blocks like the one containing key number 7, are not half full.
This problem could be partially solved by using key rotations to balance
the tree better. However, there are still corner cases where there would
be a block which is under-full. One such corner case includes when a key
falls between two keys which have overflow blocks. It must then be in a
block by itself, since this B+Tree has the invariant which state that if
a block is overflowing it can only contain one unique key. In the future
we would like to implement key rotations to help partially alleviate the
problem of under-full blocks.&lt;/p&gt;
&lt;p&gt;The advantage of this approach to B+Trees with duplicate keys is the
index size is small no matter how the ratio of duplicate keys to the
total number of keys in the file. This property allows our searches to
be conducted quicker. Since the overflow blocks are chained into the
B+Tree structure we still have the property of being able to fast
sequential scans. One consequence is we have defined all queries on our
B+Trees to be range queries. This is fine because all of our queries
were already range queries. In conclusion we relax the condition that
all blocks must be at least half full to gain higher performance during
search.&lt;/p&gt;
&lt;h2&gt;The Lessons Learned&lt;/h2&gt;
&lt;p&gt;The biggest lessons learned through the journey:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The Value of Test Driven Development&lt;/em&gt; The impact TDD had on the
    development time of the B+Tree vs. other structures in the project
    cannot be understated. TDD dramatically reduced the time it took to
    develop the structure (from over a month for some of the other
    structures to under two weeks for the B+Tree), and has ensured
    reliability of the structure once it entered production.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;The Value of the Iterative Approach&lt;/em&gt; By starting simple, testing,
    and then adding complexity I was able to get a better grasp on the
    problems posed by the modifications we needed to make to the
    structure. For instance I before I tried method 2 for duplicate
    keys, I modeled the data we would be putting into our tree and
    visualized the resulting structure. I found the structure would
    perform poorly. However, the same code allowed my to visualize
    method 2 and see that it would perform well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;Visualizations as Part of Development&lt;/em&gt; Writing code allowing you to
    visualize the structure you are developing can really help you find
    bugs quicker. The best tool to do this with is graphviz. The
    pictures used in this blog where generated as part of unit test
    cases. My building a visualization framework early as part of your
    unit tests you can further reduce development time. When a bug a
    appears it can be enormously helpful to visualize the actual
    structure of the tree at the time the bug manifested.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusions&lt;/h2&gt;
&lt;p&gt;When the right choice for your project isn't DBMS, but you still need to
index large data, don't fear you can write the index structures
yourself. By using TDD, iterating, and visualizing as you go you can
ensure the index structure you create will perform well, and will never
get into an incorrect state. Databases are not a black box, and they are
not always the right answer. When required you can create you own
system.&lt;/p&gt;</content><category term="Blog"/></entry></feed>