<!DOCTYPE article PUBLIC "-//NLM//DTD JATS (Z39.96) Journal Archiving and Interchange DTD v1.0 20120330//EN" "JATS-archivearticle1.dtd">
<article xmlns:xlink="http://www.w3.org/1999/xlink">
  <front>
    <journal-meta />
    <article-meta>
      <title-group>
        <article-title>Perfecting Nothingness by Refactoring Whitespace</article-title>
      </title-group>
      <contrib-group>
        <contrib contrib-type="author">
          <string-name>Rutger Witmans</string-name>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <contrib contrib-type="author">
          <string-name>Vadim Zaytsev</string-name>
          <xref ref-type="aff" rid="aff0">0</xref>
          <xref ref-type="aff" rid="aff1">1</xref>
        </contrib>
        <aff id="aff0">
          <label>0</label>
          <institution>Formal Methods &amp; Tools, University of Twente</institution>
          ,
          <addr-line>Enschede</addr-line>
          ,
          <country country="NL">The Netherlands</country>
        </aff>
        <aff id="aff1">
          <label>1</label>
          <institution>Technical Computer Science, University of Twente</institution>
          ,
          <addr-line>Enschede</addr-line>
          ,
          <country country="NL">The Netherlands</country>
        </aff>
      </contrib-group>
      <abstract>
        <p>In this paper we explore the possibilities of refactoring code in Whitespace, a programming language which only recognises whitespace characters as code, and tolerates textual comments that describe the program. The paper presents a list of possible refactorings applicable to Whitespace, and describes a tool that automates some of these refactorings. The functionality of the tool is demonstrated with concrete examples. Refactoring is a important systematic process of improving code without creating new functionality, improving long-term properties of the code such as readability, maintainability, changeability, testability, extendability and safety. We argue that, despite the lack of real-life applications for Whitespace specifically, it is beneficial to apply refactoring methodology to it, since lessons learnt from esoteric languages can be ported elsewhere - in this case, to assemblers and similarly restrictive software languages.</p>
      </abstract>
      <kwd-group>
        <kwd>eol&gt;Whitespace</kwd>
        <kwd>program refactoring</kwd>
        <kwd>esoteric languages</kwd>
        <kwd>second generation languages</kwd>
      </kwd-group>
    </article-meta>
  </front>
  <body>
    <sec id="sec-1">
      <title>1. Motivation</title>
      <p>nique, often applied manually by developers (with
automation support from the IDE) with the original intent
There are many ways to classify software languages [1]. — to improve the design of existing code [9]. However,
One of them is a spectrum from the most mainstream it is also very useful as a part of composite techniques.
and widespread languages, to most exotic and esoteric For instance, one can apply it as a program
transformaones. The mainstream side can be represented by the tion on elements of a test suite, possibly augmenting it
TIOBE index [2], the current top ten being Python, C, with more test cases with known execution outcomes.
Java, C++, C#, Visual Basic, JavaScript, SQL, PHP and Go. In the past, this is exactly what the second author has
On the other side, esoteric languages, as the name sug- tried to do [10] to augment the labour-intensive
progests, are designed for one specific purpose of local inter- cess of testing the Raincode Assembler Compiler [11, 12]
est: to have the smallest compiler, as it was the case with with mutative fuzzing. The endeavour was ultimately
brainf*ck [3], to use statements that are as far from all unsuccessful: fuzzing only worked on the level of macros
other languages as possible, as it was with INTERCAL [4], (where it did contribute somewhat, and found at least one
or to provide a feasibly tiny playground for implementing of-by-one bug in the compiler), but the original goal of
legacy languages, as it happened with BabyCobol [5]. testing the instruction implementations failed. The main
One of such languages is Whitespace [6], and it was reason was the dificulty to define any kind of refactoring
designed from a driving principle that whitespace — the transformations that make sense: changing even one bit
part of the source code which is traditionally ignored by of the test program had potentially numerous and hardly
the compiler as insignificant — is precisely the only part predictable efects.
of the code which is significant, and the rest of the code Several years later, we try a diferent approach: instead
such as visible punctuation, letters and numbers, are in- of codeveloping all the elements of the fuzzing
infrassignificant and skipped by the compiler. The language tructure, we focus only on refactorings; and instead of
was designed by Edwin Brady around 2003 [6], and has facing a gigantic language requiring 1500+ pages of
docenjoyed some attention in the meantime, leading to the umentation just to cover the byte-level basics, we focus
existence of many implementations and programs to try on one tiny esoteric language with similar properties —
software evolution techniques and tools on. namely, dificulty of defining what constitutes a
refactorRefactoring [7, 8] can be used as a standalone tech- ing within it. If by any chance our results will happen to
help some Whitespace developer to improve readability
of their code, that could only make the world a better
place to live in.</p>
      <p>SATToSE’23: Post-proceedings of the 15th Seminar on Advanced
Techniques and Tools for Software Evolution, June 2023, Fisciano, Italy
$ r.c.h.witmans@student.utwente.nl (R. Witmans);
vadim@grammarware.net (V. Zaytsev)
 https://github.com/rwitmans (R. Witmans);
http://grammarware.net (V. Zaytsev)
0000-0001-7764-4224 (V. Zaytsev)</p>
      <p>© 2023 Copyright for this paper by its authors. Use permitted under Creative
CPWrEooUrckReshdoinpgs IhStpN:/c1e6u1r3-w-0s.o7r3g CCoEmmUoRns LWiceonsrekAstthribouptionP4r.0oIncteerenadtiionnagl s(CC(CBYE4U.0)R.-WS.org)</p>
    </sec>
    <sec id="sec-2">
      <title>2. Background</title>
      <p>elegance and functionality of this distinctive
programming paradigm. However, first we explain the basics of
In the vast realm of software languages, where intrica- the language itself, to make this story self-contained.
cies of syntax and verbosity often shape the landscape, Whitespace supports the following instructions:
an esoteric programming language stands out,
challenging these conventions. Whitespace [6], a language • \_\_ = push (a value on the stack)
conceived by Edwin Brady around 2003, transcends the • \_\n\_ = dup (duplicate the top of the stack)
norms and redefines the very essence of coding, high- • \_\t\_ = lift (copy the ℎ item on the stack
lighting the beauty that can be found in minimalism and onto the top of the stack)
turning whitespace perception inside out. • \_\n\t = swap (the top two values on the stack)</p>
      <p>At its core, Whitespace embodies a design that is de- • \_\n\n = drop (the top of the stack)
liberately unconventional. While mainstream program- • \_\t\n = dropN (slide  items of the stack,
keepming languages rely on an array of keywords, operators, ing the top item)
and identifiers [ 13], Whitespace takes a dramatically • \t\_\_\_ = add (two top values on the stack)
diferent approach. Its code comprises just three fun- • \t\_\_\t = sub (subtract the top value on the
damental characters: space (which we will denote as stack from the one after it)
\_), tabulation (\t) and newline (\n). In this
minimalistic arrangement, Whitespace signifies the essence of • \t\_\_\n = mul (multiply two top values on the
functionality through its whitespace, presenting a stark stack)
departure from the verbose nature of traditional software • \t\_\t\_ = div (integer division of two top
vallanguages. ues on the stack)</p>
      <p>In essence, Whitespace stands as a testament to purity • \t\t\_ = store (in heap)
in programming. In contrast to languages where code • \t\t\t = retrieve (from heap)
is defined by intricate syntax, Whitespace’s elegance • \n\_\_ = label (define for later use)
lies in embracing emptiness. Its programs are essentially • \n\_\n = jump (unconditionally)
assembler-level algorithms expressed as sequences of • \n\_\t = call (to return later)
whitespace characters, where patterns of spaces and tabs • \n\t\_ = jumpZ (conditionally, if zero is on the
elaborate computational operations. This purity extends top of the stack)
beyond aesthetics; it mirrors a programming philosophy • \n\t\t = jumpNeg (conditionally, if the top of
that peers into the essence of computation, devoid of the stack is negative)
distractions. This brings Whitespace closer to IBM High • \n\t\n = return (get back from a call)
Level Assembler [11, 12], Intel IA32 Assembler [14], Pow- • \n\n\n = stop (the programme)
erPC Assembler [15], ARM Assembler [16], Forth [17], to • \t\n\_\_ = writeC (output the character at the
some extent even to C [18] or at least its more restrictive top of the stack)
variants like SAC [19]. • \t\n\_\t = writeN (output the number at the</p>
      <p>Central to Whitespace’s uniqueness is its distinctive top of the stack)
mode of operation. The language is built exclusively
around a stack-based approach — just like Forth [17] and • i\tti\nnt\hte\lo_c=atiroenagdiCve(nrebayd tahcehtaorpacotfetrhaensdtapclka)ce
some of the most disciplined assemblers. Commands,
represented by sequences of whitespace characters, ma- • \t\n\t\t = readN (read a number and place it
nipulate this stack, orchestrating computations that res- in the location given by the top of the stack)
onate with a certain enigmatic beauty. The interplay
between whitespace and functionality is an embodiment
of Whitespace’s duality, where the visually unassuming
code conceals complex calculations beneath its surface.</p>
      <p>For programmers accustomed to conventional
languages, engaging with Whitespace presents a unique
challenge. Crafting meaningful programs requires a
fundamental shift in the programming mindset, relying on
whitespace characters to carry the program’s meaning
and on non-whitespace characters to provide comments.</p>
      <p>The latter aspect brings it conceptually closer to literate
programming [20, 21].</p>
      <p>In this paper, our focus lies on the potential for code
refactoring, exploring how this process can amplify the</p>
      <sec id="sec-2-1">
        <title>For this project, we wanted to rely on a tool which</title>
        <p>
          parses Whitespace code and turns it into an
intermediate representation, and after the refactorings turn the
newly refactored intermediate representation back into
Whitespace code. We have decided to use the Rust library
“whitespace-rs” [
          <xref ref-type="bibr" rid="ref1">22</xref>
          ]. This tool has all the features
necessary for testing, creating and transforming Whitespace
code. The library has created its own intermediate
representation, thus saving us the hassle of coming up with
such a representation. The library is able to run our
Whitespace programs, giving us the ability to test for
changes in behaviour.
        </p>
        <p>To show what our Intermediate Representation (IR)
looks like, we first have to explain how Whitespace
Push {value: Integer},
PushBig {value: BigInteger},
Duplicate,
Copy {index: usize},
Swap,
Discard,
Slide {amount: usize},
Add,
Subtract,
Multiply,
Divide,
Modulo,
Set,
Get,
Label,
Call {index: usize},
Jump {index: usize},
JumpIfZero {index: usize},
JumpIfNegative {index: usize},
EndSubroutine,
EndProgram,
PrintChar,
PrintNum,
InputChar,
InputNum,
and newline characters at the end of each line. For most
works. Whitespace has five diferent types of commands. people, it is not clear how this program should behave.
These types all have a diferent Instruction Modification For example, some lines contain more than one
instrucParameter (IMP). The IMP is a unique sequence of whites- tion. That is why we would like to use the IR. In Figure 1,
pace characters that selects one of these instruction types. on the right you can find the IR version of the same
After choosing an instruction type, you now enter the cor- Whitespace program. Here it becomes clear that
evresponding combination of whitespace characters to se- ery letter first gets pushed onto the stack by their ASCII
lect the instruction you want. Some of these instructions code and then printed. When it finally finished
printhave parameters, which are a sequence of tabs and spaces, ing the last character, the program exits. Using the IR
terminated with a Line Feed character. All Whitespace to create Whitespace programs was convenient for us
programs end with three line feed characters, indicat- since it sped up the time it took to create and analyse test
ing that there is no more code to parse. Combining all programs.
these instructions gives us a total of 24 instructions in
the Whitespace language. 3. Possible Refactorings</p>
        <p>
          With this in mind, in Listing 1 you will see the IR
of the Whitespace library we have decided to use. All Since the world has moved way past the list of
refactorthe 24 commands have their own unique and human- ings proposed by Opdyke [8] and Fowler et al [9] in the
understandable name (in our explanation earlier we have 1990s, we have mostly relied on developer-created grey
leaned towards decades-long terminology established by sources like Refactoring Guru [
          <xref ref-type="bibr" rid="ref2">23</xref>
          ]. We first looked at
Forth, but here we see some less context-aware choices what refactoring categories are possible. The following
like using Discard instead of drop; its pretty-printed categories are available:
version difers yet from this internal representation).
Using this IR, we are able to create our refactorings in an • [CM] Composing Methods
easier-to-understand language. • [MF] Moving Features between Objects
        </p>
        <p>In Figure 1, on the left you will see a complete working • [OD] Organising Data
program in Whitespace, specifically, a “Hello, world!” • [SE] Simplifying Conditional Expressions
program. In the example, you see a combination of spaces • [SM] Simplifying Method Calls
(the vertical stripes), tabulations (the horizontal stripes) • [DG] Dealing with Generalisation
• [CS] Code Smells</p>
        <p>We are ruling out everything that has to do with
object programming patterns since Whitespace is an
assembler-like language. Such languages generally miss
the object programming data structures needed to
perform such refactorings. Thus [MF], [OD] and [DG]
are high-level refactorings which we will not translate
that well. Whitespace does have instructions which are
called labels. These labels are points in the code you
can jump to where a certain piece of code gets executed.</p>
        <p>This functionality borrows some refactoring ideas from
the [SM] and [CM]. Whitespace also has instructions
for conditional jumps. This makes some of the ideas for
[SE] possible. Next to this, the list of code smells look
promising enough to deliver at least some refactorings
for us to perform, so we will be looking into [CS] as well.</p>
        <p>We will thus be looking through the following categories:
• [CM] Composing Methods Labels
• [SE] Simplifying Conditional Expressions
• [SM] Simplifying Method Calls Label Jumps
• [CS] Code Smells</p>
        <p>With these chosen categories, we have created a list
of refactorings which can be performed on Whitespace
code. The following list is the refactorings is our result
so far:
• [EM] Extract method
• [IM] Inline method
• [RM] Rename method
• [CC] Consolidate conditional expression
• [CD] Consolidate duplicate conditional
frag</p>
        <p>ments
• [RD] Remove dead code
• [RC] Remove clone/duplicate methods
the program without bringing new functionality. We see
that these first two methods of refactoring have opposite
ideas in mind, yet both methods are able to be utilized
exclusively from each other. For some methods, you might
have made use of too many methods. This makes it
unclear how the method works. On the other hand, using
too few methods overwhelms the reader and makes the
reader get lost in certain details which are not important.</p>
        <p>Because of this balance, it will be tricky to automate this
process. While it is possible to automate this based on
self-defined predicates, we will not be doing this in our
paper because this is beyond the scope of this research.</p>
        <sec id="sec-2-1-1">
          <title>3.3. [RM] Rename method</title>
        </sec>
      </sec>
      <sec id="sec-2-2">
        <title>The rename method refactoring is quite self-explanatory.</title>
        <p>The purpose of this refactoring normally is to rename the
method in order to make it more clear what the method
does. In the case of Whitespace, this is impossible.
Labels do not have ordinary names. Instead, they are
made up of a combination of tabs and spaces. Because of
this, the naming of labels is purely there to keep
uniqueness. However, since the naming does not matter, we
instead rename the labels to keep them as small as
possible. Not only will this increase the number of labels we
will have available to us, but it will also allow us to keep
the Whitespace code as small as possible.</p>
        <p>See subsubsection 4.1.1 for implementation details of
this refactoring.</p>
        <sec id="sec-2-2-1">
          <title>3.4. [CC] Consolidate conditional expression</title>
        </sec>
      </sec>
      <sec id="sec-2-3">
        <title>The consolidate conditional expression refactoring is a</title>
        <p>refactoring method where one looks at all the diferent
branches and then checks what branches lead to the same
instructions. We then group these branches into a
sin3.1. [EM] Extract method gular conditional statement that performs these actions.
The extract method refactoring is a refactoring where Grouping these conditionals gives clarity to code,
espea grouped sequence of instructions gets extracted into cially if you name this expression. While this can be
its own method so that this new method describes with done in Whitespace using labels and performing the
its method name what the sequence of instructions is conditional logic under one of these labels, we would like
supposed to do. This is useful when you have a large to argue that this refactoring is still too subjective. We
method which does multiple sub-tasks to perform its cannot easily decide whether a conditional statement is
functionality. Making it clear what the function does in complex and needs changing. We have thus decided not
these sub-steps is nice for the next reader of the code, to implement this refactoring into the tool.
so the readers are able to easily deduce what your code
does.</p>
        <sec id="sec-2-3-1">
          <title>3.2. [IM] Inline method</title>
        </sec>
      </sec>
      <sec id="sec-2-4">
        <title>The inline method refactoring is the opposite of this. If some functionality of a method is small, there is the possibility of performing that function on the spot. Refactoring code with this method gets rid of code which clutters</title>
        <sec id="sec-2-4-1">
          <title>3.5. [CD] Consolidate duplicate conditional fragments</title>
        </sec>
      </sec>
      <sec id="sec-2-5">
        <title>The consolidate duplicate conditional fragments refactor</title>
        <p>ing checks whether all branches execute the same piece
of code and then extracts this piece out of the branches.</p>
        <p>
          This refactoring makes clear what piece of code always
needs to be executed no matter what conditional branch
you might have taken. This clears up confusion about
what the if-statement tries to separate resulting in cleaner
code. We have chosen not to implement this method.
• If there is a label which is not jumped towards,
we will eliminate this label with the code
corresponding with this label.
3.6. [RD] Remove dead code Using this approach we are easily able to detect if
methods are not called. There are some downsides to
To explain removing dead code, we will first explain what this method which we will now point out. If there are
dead code is. "Dead or inactive code is any code that has two methods which will reference each other that are
no efect on the application’s behaviour" [
          <xref ref-type="bibr" rid="ref3">24</xref>
          ]. With this not called through the main method, they will both still
definition, we see that we want to remove code that has be seen as used code. This can be fixed by storing the
no efect on the application we are writing. While this label in which the method is called, and seeing whether
is trivial to do as a human, as a robot it is quite hard this name space is reached via the main method. If it is,
to notice when code is unused. Because of this, we will then this piece of code is not dead, otherwise, you can
eliminate unused methods instead, to keep complications mark it as dead code.
lower. That would not fix the second issue, however. If the
        </p>
        <p>See subsubsection 4.1.2 for implementation details of code mentions a jump to a certain label, but it would
this refactoring. never take this jump, then this called method would still
be seen as a used piece of code. However, This cannot
3.7. [RC] Remove clone/duplicate be true since this part of the code is never reached. One
methods would have to guarantee that this piece cannot be reached
using more complicated techniques.</p>
        <p>Last up, we will be removing duplicate methods. Du- Finally, we are just looking at dead methods and not
plicate methods are two methods which have the exact dead code in general. If code is specifically told to stop
same functionality. For Whitespace, this will mean to the execution and there are calls to other methods after
us that there are two diferent labels which are followed stopping execution, these called methods should be seen
by the same code and are not (co)recursive. Our tool is as dead. However, since we have not put in checks to
going to remove these methods since duplicate methods detect this behaviour, these methods are not removed.
only cause confusion and do not have any benefits to a A combination of [RD] with [RM] can be seen on
Figprogrammer. ure 2 (in pure Whitespace) or on Figure 3 (in Whitespace</p>
        <p>See subsubsection 4.1.3 for implementation details of IR).
this refactoring.</p>
      </sec>
    </sec>
    <sec id="sec-3">
      <title>4. Evaluation</title>
      <sec id="sec-3-1">
        <title>4.1. Implementation details</title>
        <sec id="sec-3-1-1">
          <title>In our proof of concept [25], we have implemented several refactorings, which we explain below in this section.</title>
          <p>4.1.1. [RM] Rename method
4.1.3. [RC] Remove clone/duplicate methods
For removing duplicate methods, we have created a plan
to detect these instances. Our plan is as follows:
• Analyse the code of all the methods.
• Group methods that have duplicate code.
• Remove grouped methods until there is one left.
• Change all jumps from the removed labels to the
grouped method that is left.
• Look at all our jump instructions and store to
what label they jump to.</p>
        </sec>
        <sec id="sec-3-1-2">
          <title>Given the small size of the space of possible label names in</title>
          <p>
            Whitespace, the obvious automated refactoring would With this, we have created a way to remove duplicate
be one that minimises label names. Serendipitously, this code without changing behaviour. There is one issue
functionality was already included in whitespace-rs, left with this implementation. If two instructions are
so we could simply rely on their implementation to swapped which are interchangeable, this plan would not
achieve our first working refactoring [
            <xref ref-type="bibr" rid="ref1">22</xref>
            ]. be comprehensive to detect all method duplication. The
way to fix this interchangeable code problem is to find
4.1.2. [RD] Remove dead code all patterns where code can be interchanged without
changing behaviour and detect duplicate code using these
For our dead code removal, we have created a plan to patterns.
detect unused methods and then remove these methods. A combination of [RC] with [RM] can be seen on
FigOur plan is as follows: ure 4 (in pure Whitespace) or on Figure 5 (in Whitespace
IR).
With all of the refactorings finished, we needed some test
programs to test whether the refactorings are applied
correctly and kept their behaviour. This turned out to
be a problem, since writing valid Whitespace code is
not human-friendly. However, we solved this problem by
writing in the format of the library their IR. The library
was then able to recognise this format and transform the
IR into a whitespace-encoded file, solving the issue of
writing Whitespace code.
4.2.1. Testing [RD]
          </p>
        </sec>
        <sec id="sec-3-1-3">
          <title>In software languages that permit low-level branching constructs, there are many ways to use a “method”, and</title>
          <p>
            thus dead code detection must run very advanced code
analysis algorithms and apply domain-specific heuristics.
For example, HLASM (IBM High Level ASseMbler) has
an EX(ECUTE) instruction which can modify the target
address of a branching instruction at runtime. COBOL
and BabyCobol [5] have a statement that can ALTER a
target of an existing GO TO statement at runtime. Older
versions of FORTRAN had computable GOTOs, as does
BabyCobol. Luckily, Whitespace is a bit more
straightforward, and making a call graph of all Call and Jump
locations to all the Labels, is suficient, if we take
fallthroughs into account.
4.2.2. Testing [RC]
Code clone management has been a topic of research for
many years [
            <xref ref-type="bibr" rid="ref5">26</xref>
            ]. Researchers and practitioners identify
many diferent clone types and clone detection method
families [
            <xref ref-type="bibr" rid="ref6">27</xref>
            ]. For this research, we opted for type-1
equivalence (precise character-level equality) of labelled
sections after all possible [RM] and [RD] refactorings have
been applied. Our tool marks clone pairs and in the
second pass removes one of them and replaces all calls to it
with the calls to the remaining one.
          </p>
        </sec>
      </sec>
    </sec>
    <sec id="sec-4">
      <title>5. Advanced Refactorings</title>
      <sec id="sec-4-1">
        <title>In this section, we consider other possible refactorings of</title>
        <p>Whitespace code which were not directly followed from
the Refactoring book [9] and its derivatives, but conform
to the general expectations about code refactoring, which
improving design while preserving observable behaviour.</p>
        <sec id="sec-4-1-1">
          <title>5.1. Control Flow Optimisation</title>
        </sec>
      </sec>
      <sec id="sec-4-2">
        <title>Control flow optimisation in Whitespace necessitates</title>
        <p>
          Control flow optimisation is not uncommon in compiler a meticulous analysis of the whitespace patterns
correconstruction since at least 1960s [
          <xref ref-type="bibr" rid="ref7 ref8">28, 29</xref>
          ]. It is an analy- sponding to commands. This analysis guides the
idensis and transformation technique known for enhancing tification of opportunities for optimisation. Techniques
program eficiency and readability, and especially per- borrowed from compiler optimisation, such as data flow
formance. In the context of Whitespace, control flow analysis and control dependence analysis, can be adapted
optimisation takes on unique significance. This section to the Whitespace context. These techniques enable the
delves into the intricacies of control flow optimisation identification of redundant or unnecessary commands,
within the confines of Whitespace, discussing its meth- leading to code simplification.
ods, implementation, rationale, and potential outcomes. Implementation of optimised control flow involves
        </p>
        <p>In Whitespace, control flow is inherently intertwined rewriting whitespace commands to eliminate
redunwith the stack-based execution model of the language. dancy, reorganise control structures, and minimise stack
Optimisation strategies focus on streamlining the se- operations. Given the absence of dedicated
optimisaquence of commands that manipulate the stack, ulti- tion tools for analysing Whitespace code, this process
is largely manual, demanding a profound understanding for parallelism within the Whitespace context.
of the language’s mechanics and the intricacies of the The pursuit of parallelism in Whitespace stems from
specific program. its stack-based execution model, where operations are
in</p>
        <p>Control flow optimisation in Whitespace serves a herently ordered and dependent on the state of the stack.
dual purpose: enhancing program eficiency and promot- However, careful analysis can reveal segments of code
ing code clarity. A leaner, more streamlined execution that exhibit independence in terms of stack interactions.
path reduces runtime overhead, translating to improved These independent segments provide the foundation for
performance for computationally intensive tasks. Fur- potential parallel execution, as they can be decoupled
thermore, optimised code is less prone to errors arising without afecting the overall program logic.
from complex control structures, thus augmenting pro- The critical task in code partitioning for parallelism
gram reliability. involves identifying segments of Whitespace code that</p>
        <p>The rationale behind control flow optimisation aligns can be executed in parallel without introducing data
dewith the overarching goal of refining Whitespace’s pendencies. This necessitates an intricate understanding
unique art form of code expression. While Whitespace of the program’s control flow, stack interactions, and the
emphasises minimalism and obscurity, control flow op- interplay between Whitespace commands. Independent
timisation seeks to harmonise this peculiarity with im- segments may arise from distinct branches of conditional
proved functionality and eficiency. The optimisation pro- logic, separate loops, or operations that manipulate
encess bridges the gap between the language’s enigmatic tirely separate data on the stack.
syntax and the pursuit of elegant, optimised solutions. While the identification of independent segments is</p>
        <p>The outcomes of control flow optimisation manifest in foundational, the practical implementation of parallel
exquantifiable performance gains, as optimised programs ecution in Whitespace presents challenges. Traditional
execute more swiftly and consume fewer resources. Ad- parallel programming paradigms, such as those found
ditionally, the optimisation process unearths hidden pat- in languages like C or Python, are inapplicable due to
terns within whitespace sequences, deepening the under- Whitespace’s unique stack-centric nature. Parallel
exestanding of Whitespace’s computational nature. cution introduces the potential for race conditions, where</p>
        <p>Future directions in control flow optimisation for multiple segments may access and manipulate the shared
Whitespace involve the development of automated tools stack simultaneously.
that aid programmers in identifying optimisation oppor- To circumvent race conditions and ensure consistent
tunities and implementing changes. These tools would execution, mechanisms for synchronisation and
commualleviate the manual efort currently required, broaden- nication between parallel segments must be devised. This
ing the applicability of control flow optimisation and requires the establishment of well-defined points for
inmaking it accessible to a wider audience. teraction, such as specific stack configurations at which</p>
        <p>Control flow optimisation within Whitespace stands parallel segments can synchronise and exchange data.
as a testament to the adaptability of optimisation princi- These synchronisation points mitigate conflicts arising
ples across diverse programming paradigms. The meth- from concurrent stack manipulations.
ods employed, the implementation strategies pursued, Code partitioning for parallelism in Whitespace holds
and the underlying rationale collectively contribute to the the promise of enhanced performance on modern
multienhancement of Whitespace’s unique code architecture, core systems. By concurrently executing independent
underscoring the symbiotic relationship between mini- segments, the overall runtime can be significantly
remalism and eficiency. As the realm of esoteric languages duced. This holds particular relevance for
computationcontinues to evolve, optimising control flow in Whites- ally intensive tasks, where the eficiency gains are most
pace remains an active field of exploration, promising pronounced.
further insights into the interplay of form and function For anyone willing, it is possible to develop specialised
in code. tools or compilers tailored to this unique context,
automating identification of independent segments,
intro5.2. Code Partitioning for Parallelism ducing synchronisation mechanisms, facilitating
generation of parallel-execution Whitespace code. Just like
Within the realm of Whitespace, the exploration of par- on other endeavours based on esoteric languages, the
allelism introduces a novel perspective on optimizing exploration of theoretical frameworks for analysing the
program execution. By partitioning Whitespace pro- parallelism potential within Whitespace programs could
grams into segments that can execute in parallel, the yield insights into optimal partitioning strategies
applipotential for leveraging modern multi-core systems for cable more generally.
improved performance becomes apparent. This section Code partitioning for parallelism introduces a novel
delves into the theoretical underpinnings, practical con- dimension to the realm of Whitespace programming.
siderations, and potential outcomes of code partitioning By identifying and leveraging independent segments of
code, the potential for harnessing modern multi-core sys- correlations, and opportunities for optimisation. For
intems to enhance program performance is illuminated. As stance, high stack depth values may indicate memory
Whitespace continues to captivate programmers with ineficiencies, whereas excessive branching complexity
its minimalist elegance, the pursuit of parallelism within might signal the need for code restructuring.
its stack-centric realm opens doors to new vistas of opti- The insights garnered from metrics lay the foundation
misation and eficiency. for targeted code refinement in Whitespace. A high stack
depth, for instance, may inspire eforts to minimise stack
5.3. Whitespace Code and Quality Metrics operations through algorithmic optimisations. Excessive
branching complexity could encourage the
simplificaIn the landscape of programming languages, the evalua- tion of control structures to enhance code readability
tion of code quality is paramount to fostering maintain- and maintainability. Metrics guide the balance between
ability, reliability, and performance. Within the unique the elegance of Whitespace’s minimalist syntax and the
context of Whitespace, the establishment of code met- pursuit of optimised, well-structured programs.
rics and quality metrics unveils a new dimension of as- The integration of metrics into Whitespace
programsessment. This section delves into the rationale behind ming potentially leads to the development of tooling
the application of metrics in the Whitespace paradigm, that automates metric calculation and analysis. Such
the metrics themselves, their interpretation, and the im- tools could guide programmers towards code
improveplications for code refinement. ments, recommend optimisations, and facilitate the
eval</p>
        <p>The application of code metrics and quality metrics to uation of codebases. Challenges include adapting
traWhitespace serves a dual purpose: to quantify the inher- ditional metrics to Whitespace’s unique attributes and
ent complexities of code and to provide objective criteria defining thresholds that align with the language’s
disfor evaluating its quality. As Whitespace’s minimal- tinctive goals.
ist nature conceals intricate computational operations, Metrics in the Whitespace landscape transcend
conmetrics ofer a lens through which to comprehend the ventional notions of code evaluation. They illuminate
program’s underlying intricacies. Additionally, metrics the intricate dance of whitespace commands, ofering a
serve as a means to guide code refinement, providing a quantifiable means to understand, analyze, and enhance
tangible framework for optimizing stack usage, execution program quality. As Whitespace continues to captivate
eficiency, and logical coherence. enthusiasts with its enigmatic charm, the application of</p>
        <p>In the context of Whitespace, the development of metrics underscores the symbiotic relationship between
metrics necessitates an alignment with its stack-centric quantitative analysis and qualitative code refinement.
architecture. Some relevant metrics include:</p>
        <p>
          Interpreting metrics within the Whitespace context
requires a nuanced understanding of the idiosyncrasies
of the language. Metrics do not merely serve as
benchmarks; they provide a framework for uncovering patterns,
1. Stack Depth: Quantifying the maximum and 6. Concluding Remarks
average stack depth during program execution
provides insights into memory consumption and In this paper, based on recent graduation project [
          <xref ref-type="bibr" rid="ref9">30</xref>
          ], we
potential bottlenecks. have described our approach to refactoring in
Whites2. Command Sequence Length: Measuring the pace. The tool is also available for public use under
GPLlength of command sequences contributes to un- 3 license [
          <xref ref-type="bibr" rid="ref4">25</xref>
          ]. To answer our main research question
derstanding the program’s complexity and poten- about what refactorings would make sense in
Whitestial for optimisation. pace, we first looked at diferent refactoring categories.
3. Instruction Density: Calculating the density From there we identified seven refactorings that are
posof instructions relative to whitespace characters sible on Whitespace code. To address the question of
reveals the eficiency of command utilisation. implementability, we chose three refactorings and
imple4. Branching Complexity: Assessing the branch- mented them into a tool. Our tool reads Whitespace code,
ing complexity through metrics like conditional- performs refactorings on this code using the generated IR,
to-total command ratio sheds light on the pro- and transforms the IR back into Whitespace code. This
gram’s logical structure. shows that it is possible to create a tool which detects and
5. Stack Operations: Quantifying the frequency applies possible refactorings on Whitespace. This work
of stack manipulations, such as pushes and pops, shows that even with minimal circumstances, it is always
ofers insights into computational steps and po- possible to refactor code even in minimal assembler-like
tential redundancies. languages. Furthermore, refactoring code is always
useful, be that code clarity or a minimal code footprint. We
conclude that refactoring Whitespace code is possible
and that refactoring Whitespace code improves the
readability and usability of such code.
        </p>
        <p>The refactorings proposed in this paper, are a work in 2605 of CEUR Workshop Proceedings, CEUR-WS.org,
progress. Further research and development are needed 2020, pp. 18–24. URL: http://ceur-ws.org/Vol-2605/
to fully realise the envisioned functionality. Next to this, 18.pdf.
more refactorings can be implemented, such as the dif- [11] V. Blagodarov, Y. Jaradin, V. Zaytsev, Tool Demo:
ferent conditional refactorings mentioned in section 3. Raincode Assembler Compiler, in: T. van der</p>
        <p>
          Furthermore, while some testing has been performed, Storm, E. Balland, D. Varró (Eds.), Proceedings of
there could be more tests added. Generating tests to show the Ninth International Conference on Software
results that accurately depict the tool is something worth Language Engineering (SLE), 2016, pp. 221–225.
considering to be done. Finally, profiling the tool itself doi:10.1145/2997364.2997387.
could help identifying useful optimisations to improve its [12] V. Zaytsev, Modelling of Language Syntax and
Seusability, especially regarding possible future extensions mantics: The Case of the Assembler Compiler,
ProFor anyone who would like to look at the tool or work ceedings of the 16th European Conference on
Modon it further, you can find the tool over at GitHub [
          <xref ref-type="bibr" rid="ref4">25</xref>
          ]. elling Foundations and Applications in the
Journal of Object Technology (ECMFA@JOT) 19 (2020).
doi:10.5381/jot.2020.19.2.a5.
        </p>
        <p>References [13] V. Zaytsev, Language Design with Intent, in: D.
Batory, J. Gray, V. Kulkarni (Eds.), Proceedings of the
[1] R. Lämmel, D. Mosen, A. Varanovich, Method and ACM/IEEE 20th International Conference on Model
Tool Support for Classifying Software Languages Driven Engineering Languages and Systems
(MoDwith Wikipedia, in: M. Erwig, R. F. Paige, E. Van
Wyk (Eds.), Proceedings of the Sixth International ELS), IEEE, 2017, pp. 45–52. doi:10.1109/MODELS.
Conference on Software Language Engineering, vol- [14] 2K0.1R7. .Ir1v6i.ne, Assembly Language for Intel-Based
ume 8225 of LNCS, Springer, 2013, pp. 249–259. Computers, 4th ed., Pearson Education, 2002.
doi:10.1007/978-3-319-02654-1_14. [15] T. Afzal, M. Breternitz, M. Kacher, S. Menyhert,
[2] P. Jansen, et al., TIOBE Index for April 2023, https: M. Ommerman, W. Su, Motorola powerpc
migra//www.tiobe.com/tiobe-index/, 2023. tion tools-emulation and translation, in:
COMP[3] S. Graue, R. Berge, C. Pressey, et al., brainfuck — CON’96. Technologies for the Information
Superesolang, https://esolangs.org/wiki/Brainfuck, 2005. highway Digest of Papers, IEEE, 1996, pp. 145–150.
[4] D. R. Woods, J. M. Lyon, The INTERCAL
Programming Language Reference Manual, https://www. [16] dPo.Ki:1n0ag.g1s1, 0S9.W/CeMlsPhC, OANR.M19:A96ss.e5m0b1l7y6L1a.nguage
Promuppetlabs.com/~breadbox/intercal-man/, 1973. gramming, Bournemouth University, School of
De[5] V. Zaytsev, Software Language Engineers’ Worst sign, Engineering, and Computing, 2004. URL: http:
Nightmare, in: R. Lämmel, L. Tratt, J. De Lara //www.rigwit.co.uk/ARMBook/ARMBook.pdf.
(Eds.), Proceedings of the 13th International Con- [17] E. D. Rather, D. R. Colburn, C. H. Moore, The
ference on Software Language Engineering (SLE), evolution of forth, in: History of programming
ACM, 2020, pp. 72–85. doi:10.1145/3426425. languages—II, 1996, pp. 625–670. doi:10.1145/
[6] 3E4.2B6r9a3d3y., Whitespace, https://web.archive.org/ [18] 2H3. 4S2ch8i6ld.t1, 0T5h7e8a3n2n.otated ANSI C Standard
Amerweb/20150623025348/http://compsoc.dur.ac.uk/ ican National Standard for Programming
Lanwhitespace, 2003. guages—C: ANSI/ISO 9899-1990, McGraw-Hill, Inc.,
[7] W. F. Opdyke, Refactoring: An aid in designing ap- 1990.</p>
        <p>plication frameworks and evolving object-oriented [19] C. Grelck, Single assignment c (sac) high
prosystems, in: Proceedings of the Symposium on ductivity meets high performance, in: V. Zsók,
Object-Oriented Programming Emphasizing Practi- Z. Horváth, R. Plasmeijer (Eds.), Revised Selected
cal Applications (SOOPPA), 1990. Papers of the Fourth Central European Functional
[8] W. F. Opdyke, Refactoring Object-Oriented Frame- Programming School (CEFP), Springer, Berlin,
works, Ph.D. thesis, University of Illinois at Urbana- Heidelberg, 2012, pp. 207–278. URL: https://doi.</p>
        <p>Champaign, 1992. org/10.1007/978-3-642-32096-5_5. doi:10.1007/
[9] M. Fowler, K. Beck, J. Brant, W. Opdyke, D. Roberts,</p>
        <p>Refactoring: Improving the Design or Existing [20] 9D7.8E-.K3-nu6t4h2, -L3it2e0ra9t6e-p5r_og5r.amming, The computer
Code, Addison-Wesley Professional, 1999.
[10] A. Gül, V. Zaytsev, Mutative Fuzzing for an Assem- journal 27 (1984) 97–111. doi:10.1093/comjnl/
bler Compiler, in: D. Di Nucci, C. De Roover (Eds.), [21] 2N7. .R2a.m97se.y, Literate programming simplified,
Post-proceedings of the 18th Belgium-Netherlands
IEEE software 11 (1994) 97–105. doi:10.1109/52.</p>
        <p>Software Evolution Workshop (BENEVOL), volume
311070.</p>
      </sec>
    </sec>
  </body>
  <back>
    <ref-list>
      <ref id="ref1">
        <mixed-citation>
          [22] CensoredUsername, whitespace-rs, https://github. com/CensoredUsername/whitespace-rs,
          <year>2016</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref2">
        <mixed-citation>
          [23]
          <string-name>
            <given-names>A.</given-names>
            <surname>Shvets</surname>
          </string-name>
          , Refactoring: Clean Your Code, https:// refactoring.guru/refactoring,
          <year>2022</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref3">
        <mixed-citation>
          [24]
          <string-name>
            <surname>C. de Kruif</surname>
          </string-name>
          , Using
          <article-title>-NFGs to Identify and Eliminate Dead Code in C# Programs</article-title>
          ,
          <source>Bachelor's thesis</source>
          , Universiteit Twente,
          <year>2022</year>
          . URL: http://purl.utwente.nl/ essays/91890.
        </mixed-citation>
      </ref>
      <ref id="ref4">
        <mixed-citation>
          [25]
          <string-name>
            <given-names>R.</given-names>
            <surname>Witmans</surname>
          </string-name>
          , whiteref, https://github.com/ rwitmans/whiteref/,
          <year>2023</year>
          .
        </mixed-citation>
      </ref>
      <ref id="ref5">
        <mixed-citation>
          [26]
          <string-name>
            <surname>C. K. Roy</surname>
            ,
            <given-names>J. R.</given-names>
          </string-name>
          <string-name>
            <surname>Cordy</surname>
          </string-name>
          ,
          <article-title>Benchmarks for Software Clone Detection: A Ten-Year Retrospective</article-title>
          ,
          <source>in: Proceedings of the 25th International Conference on Software Analysis, Evolution and Reengineering</source>
          , IEEE Computer Society,
          <year>2018</year>
          , pp.
          <fpage>26</fpage>
          -
          <lpage>37</lpage>
          . doi:
          <volume>10</volume>
          . 1109/SANER.
          <year>2018</year>
          .
          <volume>8330194</volume>
          .
        </mixed-citation>
      </ref>
      <ref id="ref6">
        <mixed-citation>
          [27]
          <string-name>
            <given-names>A.</given-names>
            <surname>Hamid</surname>
          </string-name>
          ,
          <string-name>
            <given-names>V.</given-names>
            <surname>Zaytsev</surname>
          </string-name>
          ,
          <article-title>Detecting Refactorable Clones by Slicing Program Dependence Graphs</article-title>
          , in: D.
          <string-name>
            <surname>Di Ruscio</surname>
          </string-name>
          , V. Zaytsev (Eds.),
          <source>Post-proceedings of the Seventh Seminar in Series on Advanced Techniques and Tools for Software Evolution (SATToSE</source>
          <year>2014</year>
          ), volume
          <volume>1354</volume>
          <source>of CEUR Workshop Proceedings, CEUR-WS.org</source>
          ,
          <year>2015</year>
          , pp.
          <fpage>37</fpage>
          -
          <lpage>48</lpage>
          . URL: http: //ceur-ws.
          <source>org/</source>
          Vol-
          <volume>1354</volume>
          /paper-04.pdf .
        </mixed-citation>
      </ref>
      <ref id="ref7">
        <mixed-citation>
          [28]
          <string-name>
            <given-names>F. E.</given-names>
            <surname>Allen</surname>
          </string-name>
          ,
          <article-title>Control flow analysis</article-title>
          ,
          <source>ACM Sigplan Notices</source>
          <volume>5</volume>
          (
          <year>1970</year>
          )
          <fpage>1</fpage>
          -
          <lpage>19</lpage>
          . doi:
          <volume>10</volume>
          .1145/390013. 808479.
        </mixed-citation>
      </ref>
      <ref id="ref8">
        <mixed-citation>
          [29]
          <string-name>
            <given-names>J.</given-names>
            <surname>Nievergelt</surname>
          </string-name>
          ,
          <article-title>On the automatic simplification of computer programs</article-title>
          ,
          <source>Communications of the ACM</source>
          <volume>8</volume>
          (
          <year>1965</year>
          )
          <fpage>366</fpage>
          -
          <lpage>370</lpage>
          .
        </mixed-citation>
      </ref>
      <ref id="ref9">
        <mixed-citation>
          [30]
          <string-name>
            <given-names>R.</given-names>
            <surname>Witmans</surname>
          </string-name>
          , Improving Nothingness: Refactorings on Whitespace,
          <source>Bachelor's thesis</source>
          , Universiteit Twente,
          <year>2023</year>
          . URL: http://purl.utwente.nl/essays/ 94374.
        </mixed-citation>
      </ref>
    </ref-list>
  </back>
</article>