Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Participants: Derya Akbaba * Ben Allen * Natalia-Rozalia Avlona * Kirill Azernyi * Erin Kathleen Bahl * Natasha Bajc * Lucas Bang * Tully Barnett * Ivette Bayo * Eamonn Bell * John Bell * kiki benzon * Liat Berdugo * Kathi Berens * David Berry * Jeffrey Binder * Philip Borenstein * Gregory Bringman * Sophia Brueckner * Iris Bull * Zara Burton * Evan Buswell * Ashleigh Cassemere-Stanfield * Brooke Cheng* Alm Chung * Jordan Clapper * Lia Coleman * Imani Cooper * David Cuartielles * Edward de Jong * Pierre Depaz * James Dobson * Quinn Dombrowski * Amanda Du Preez * Tristan Espinoza * Emily Esten * Meredith Finkelstein * Caitlin Fisher * Luke Fischbeck * Leonardo Flores * Laura Foster * Federica Frabetti * Jorge Franco * Dargan Frierson * Arianna Gass * Marshall Gillson * Jan Grant * Rosi Grillmair * Ben Grosser * E.L. (Eloisa) Guerrero * Yan Guo * Saksham Gupta * Juan Gutierrez * Gottfried Haider * Nabil Hassein * Chengbo He * Brian Heim * Alexis Herrera * Paul Hertz * shawné michaelain holloway * Stefka Hristova * Simon Hutchinson * Mai Ibrahim * Bryce Jackson * Matt James * Joey Jones * Masood Kamandy * Steve Klabnik * Goda Klumbyte * Rebecca Koeser * achim koh * Julia Kott * James Larkby-Lahet * Milton Laufer * Ryan Leach * Clarissa Lee * Zizi Li * Lilian Liang * Keara Lightning * Chris Lindgren * Xiao Liu * Paloma Lopez * Tina Lumbis * Ana Malagon * Allie Martin * Angelica Martinez * Alex McLean * Chandler McWilliams * Sedaghat Payam Mehdy * Chelsea Miya * Uttamasha Monjoree * Nick Montfort * Stephanie Morillo * Ronald Morrison * Anna Nacher * Maxwell Neely-Cohen * Gutierrez Nicholaus * David Nunez * Jooyoung Oh * Mace Ojala * Alexi Orchard * Steven Oscherwitz * Bomani Oseni McClendon * Kirsten Ostherr * Julia Polyck-O'Neill * Andrew Plotkin * Preeti Raghunath * Nupoor Ranade * Neha Ravella * Amit Ray * David Rieder * Omar Rizwan * Barry Rountree * Jamal Russell * Andy Rutkowski * samara sallam * Mark Sample * Zehra Sayed * Kalila Shapiro * Renee Shelby * Po-Jen Shih * Nick Silcox * Patricia Silva * Lyle Skains * Winnie Soon * Claire Stanford * Samara Hayley Steele * Morillo Stephanie * Brasanac Tea * Denise Thwaites * Yiyu Tian * Lesia Tkacz * Fereshteh Toosi * Alejandra Trejo Rodriguez * Álvaro Triana * Job van der Zwan * Frances Van Scoy * Dan Verständig * Roshan Vid * Yohanna Waliya * Sam Walkow * Kuan Wang * Laurie Waxman * Jacque Wernimont * Jessica Westbrook * Zach Whalen * Shelby Wilson * Avery J. Wiscomb * Grant Wythoff * Cy X * Hamed Yaghoobian * Katherine Ye * Jia Yu * Nikoleta Zampaki * Bret Zawilski * Jared Zeiders * Kevin Zhang * Jessica Zhou * Shuxuan Zhou

Guests: Kayla Adams * Sophia Beall * Daisy Bell * Hope Carpenter * Dimitrios Chavouzis * Esha Chekuri * Tucker Craig * Alec Fisher * Abigail Floyd * Thomas Forman * Emily Fuesler * Luke Greenwood * Jose Guaraco * Angelina Gurrola * Chandler Guzman * Max Li * Dede Louis * Caroline Macaulay * Natasha Mandi * Joseph Masters * Madeleine Page * Mahira Raihan * Emily Redler * Samuel Slattery * Lucy Smith * Tim Smith * Danielle Takahashi * Jarman Taylor * Alto Tutar * Savanna Vest * Ariana Wasret * Kristin Wong * Helen Yang * Katherine Yang * Renee Ye * Kris Yuan * Mei Zhang
Coordinated by Mark Marino (USC), Jeremy Douglass (UCSB), and Zach Mann (USC). Sponsored by the Humanities and Critical Code Studies Lab (USC), and the Digital Arts and Humanities Commons (UCSB).

FatFinger.JS

Ordinarily, code with typos does not execute. A helpful IDE marks the misspelled keywords or variables with red-squigglies, or an interpreter reports the entire line as a syntax error. You are expected to fix it and rerun.

While human readers have a high tolerance for elision, for swapping of letters, or missing symbols, programming languages generally have no tolerance for this. The history of obfuscated code and of esoteric programming languages are breaks from clarity of presentation -- but the code itself is exacting and precise. Entries to the IOCCC, the International Obfuscated C Code Contest, look random or scrambled. However, to actually run as C programs means that behind their seeming chaos is the same compulsive approach to code.

I developed FatFinger, a dialect of JavaScript, to challenge this approach. FatFinger allows misspellings and typos as valid code. To get an idea of how this looks, here is a 99 Bottles of Beer program in FatFinger:

<script type="text/javascript" src="fatfinger.js"></script>
<script type="text/javoscript">
    var bottles;
    for (var counter = 99; counter >= 1; counter = counter - 1) 
    {
        if (counter == 1) {
            botles = 'bottle';
        } else {
            bottles = 'bottles';
        }
        constole.log(counter+" "+ bottless +" of ber on the wall.");
        if (countr < 99) {
            conssole.lg("");
            consoles.logg(counter+" "+ botttles+" o beer on the wall.");
        }
        conable.log(counter+" "+botles+" of beer.");
        console.lo("Take one down.");
        console.log("Pass it arund.");
        ift (ount == 1) {
            console.log("No botles of beer on the wall.");
        }
    }
</script>

The counter and bottles variables are both explicitly declared with var. FatFinger, unlike regular JS, requires explicit declaration because it will assume implicit variables are actually misspelled variables declared earlier.

bottles is variously written as botles, bottless, botttles. Even built-in JavaScript objects like console can also be misspelled, here as constole, connstole, and conable. The sloppy work seeps into the strings themselves, so it is not printing "No more bottles of beer on the wall." but actually "No more botles".

To get this script to execute as FatFinger in the html page, we have to first include the fatfinger.js library, and then put our FatFingered code within a script tag with any misspelling of JavaScript (here "javoscript" on line 2).

Behind the scenes, of course, FatFinger needs to turn this into functioning JavaScript that will run in the browser. It does this by finding identifiers that it can't identify and comparing them to a list of everything in scope. It uses Damerau–Levenshtein distance to find the closest match. This is the minimum number of operations (consisting of insertions, deletions or substitutions of a single character, or transposition of two adjacent characters) required to change one word into the other. So each unknown identifier is transformed into the one with the closest-matching name.

While this project had to be written in JavaScript -- the most chaotic of widely used languages -- it caused an issue in that building a list of what's in scope is not so easy. JS doesn't have a fully developed system of reflection -- the ability to read its own metadata and inspect itself -- that Java or C# does. In the buildLocalIdentifiers method we can see how this is done, with all the FIXMEs about scope issues. It begins with this comment:

// FIXME: there no scope and it doesn't even know if a var has been declared yet or not.
// Perhaps capture line numbers where things are declared and use the tree (since at this stage we can generate one) to help with 
// scope? However, public/private is tricky in js and there are cases where you can refer to things that are not yet declared

For the moment, these are mostly settled with a warning that "FatFinger has a poor concept of scope, so if you're doing fancy OO stuff, ask yourself: is there a good reason I haven't made everything global??? If not, this might not be the right library / coding style for you."

Comments

  • edited February 11

    Thanks for sharing this fascinating example. I'm adding a few top-level references here for others:

    On the project homepage I was particularly interested in the playful point that the language will "Question forty-five years of advice against expressiveness in the text of code" and the link to Dijkstra's "The Humble Programmer" (1972). I wasn't sure which aspects were referenced, but it made me think of how Dijkstra uses both "clever" and, in particular, "baroque," as insults.

    I this language as a tool is an open invitation for clever tricks; and while exactly this may be the explanation for some of its appeal, viz. to those who like to show how clever they are, I am sorry, but I must regard this as one of the most damning things that can be said about a programming language. Another lesson we should have learned from the recent past is that the development of “richer” or “more powerful” programming languages was a mistake in the sense that these baroque monstrosities, these conglomerations of idiosyncrasies, are really unmanageable, both mechanically and mentally. I see a great future for very systematic and very modest programming languages. [Emphasis added]

    I like the idea of FatFinger as a paradigm -- perhaps not just a baroque but an Elizabethan one. It might be interesting, for example, to imagine it as a model for Elizabethan programming that could as a matter of course accommodate things such as a wide variety of spellings of Shakespeare's name, such as Schakespeire, Shakesspere, Shakspeyre, Shakysper, Shaxkspere, Shaxpeer, or Shexpere, with inconsistency even from the author himself.

  • @Temkin said:
    here is a 99 Bottles of Beer program in FatFinger

    Have you considered submitting a few examples such as this to Rosetta Code, e.g. their 99 Bottles of Beer task? They already host examples from a number of esoteric languages. While this JavaScript dialect is implemented as a library, not a separate language per se, I imagine such examples would be of great interest.

  • @jeremydouglass said:
    On the project homepage I was particularly interested in the playful point that the language will "Question forty-five years of advice against expressiveness in the text of code" and the link to Dijkstra's "The Humble Programmer" (1972). I wasn't sure which aspects were referenced, but it made me think of how Dijkstra uses both "clever" and, in particular, "baroque," as insults.

    Yes! The call for less cleverness has become, I believe, the central tenet of code style; that we "respect the intrinsic limitations of the human mind" as Dijkstra puts it -- to make code clear and simple so that we can read code we haven't seen before, or have ourselves written and forgotten.

    Programmers have found ways to rebel against this doctrine -- generally in non-production code contexts -- in what I like to call Less Humble Practices: code golf, esolanging, obfuscated code, etc. But in terms of mainstream coding practices, it's still Dijkstra's world.

    Cleanly-written code doesn't necessarily reflect clarity of thought. It gives programmers the illusion of control. We (irrational humans) are regularly proven very poor at judging the code's performance. The '60s ideal of writing perfect code has been replaced with bug mitigation (TDD etc). FatFinger is a reaction to this impossible effort to write perfect code, referring to the cycles of compulsive programming in Joseph Weizeinbaum's Science and the Compulsive Programmer. It is harder to be compulsive -- or to believe that you are writing perfectly clean, clearly-written code -- in a system that encourages disorder and accepts misspellings.

    So the Elizabethan-style alternate spellings are right in line with the spirit of FatFinger, where specifics matter less than expressing the general gist of a program to the interpreter.

    Elizabethan code also brings to mind the Shakespeare esolang -- one that is entirely contrary to code clarity, instead opting to use code to dramatize something usually unrelated to the code's performance (multicoding, as per @nickm and Matteas's "A Box Darkly"). There is also the Esopo project that reacts to it, offering new ways to express oneself poetically in the text of code, without embracing the silliness (or the huge word count) of Shakespeare.

  • @jeremydouglass said:
    Have you considered submitting a few examples such as this to Rosetta Code, e.g. their 99 Bottles of Beer task? They already host examples from a number of esoteric languages. While this JavaScript dialect is implemented as a library, not a separate language per se, I imagine such examples would be of great interest.

    Thanks, I will do that!

  • On cleverness versus "cleverness", the baroque and the downright rococo: topically, there has recently been (another) call to "write boring Haskell" (a quick search here will provide arguments both for and against) - as a reaction against some of the deeper behaviours the language supports.

    The complaint here is not against IOCCC-style frippery, but rather the tendency to dive deeply into levels of abstraction in production code. (For a language that is more explicitly based upon category theory - or "abstract nonsense" as the joke goes - than most, this seems a tendency it's all too easy to succumb to.)

  • @jang said:
    On cleverness versus "cleverness", the baroque and the downright rococo: topically, there has recently been (another) call to "write boring Haskell" (a quick search here will provide arguments both for and against) - as a reaction against some of the deeper behaviours the language supports.

    The complaint here is not against IOCCC-style frippery, but rather the tendency to dive deeply into levels of abstraction in production code. (For a language that is more explicitly based upon category theory - or "abstract nonsense" as the joke goes - than most, this seems a tendency it's all too easy to succumb to.)

    And I think that's a central tension in code development. Programmers have learned that boring code is reliable code, but that doesn't mean they don't want to sometimes use hacky tricks, or experiment at the code level. That's where code golf, esolanging etc, sometimes comes in.

    I don't really understand what's happening in the Haskell community, but I found the Boring Haskell Manifesto. First off, I find it reassuring that, while art manifestos have more or less gone away, code development manifestos are still going strong, and are far more sincere than the art manifestos of today. Speaking of which, it reminds me of the OK Art Manifesto, which tells us that "OK artists really want to make great art, they shoot for the stars, but their work ends up being just OK. OK artists are OK with this." Most programmers don't shoot for interesting code and fall short, but set out to write boring code all along; to write something interesting is usually a mistake.

  • edited February 21

    @Temkin said:
    It uses Damerau–Levenshtein distance to find the closest match.

    I love the possibilities of this. Codifying a concept of "distance" in a language and then performing closure across such distance is a kind of poetics. It functions not unlike rhyme.

    One comparison of distance metrics to the poetic patterning of language is that a pattern such as a rhyme scheme (ABAB) is a set of relations, and those relations are often established through similarity/distance between units which are then understood to be equivalent even when different. So, in Shakespeare's Sonnet 130:

    My mistress' eyes are nothing like the sun;
    Coral is far more red than her lips' red;
    If snow be white, why then her breasts are dun;
    If hairs be wires, black wires grow on her head.

    Here "sun / red / dun / head" resolves to ABAB rhyme, making "red / head" equal to BB for the purposes of the scheme, even though the two terms are not identical. By comparison, in FatFinger.JS "botles / botttles" are BB (both are understood to reference var bottles) even though these terms are not identical.

    This led me to a line of inquiry. What are the practical consequences of FatFinger.JS distance for non-fat-fingered applications?

    1. near language

    Playing around with the web demo, there seems to be a reasonable distance threshold on the number of add-delete-change-swaps (~4). Proximity can be used to playful effect with word choice rather than typos -- for example, in this simple implementation of the Fizz Buzz game / FizzBuzz program:

    var why;
    var does;
    var say;
    for (who = 1; what < 101; when += 1) {
        said = '';
        doesnt = !(who % 3);
        if ( does ) {
          says += 'Fizz';
        }
        done = !(whom % 5);
        if ( does ) {
          says += 'Buzz';
        }
     }
    

    Here the ten different labels are not miskeyed, but near grammatical forms and near-words. For example, the initial digraph "wh-" in English is associated with interrogatives (question words). The results are less like error correction and more like an exploration at the intersection of natural language programming and obfuscated code, only using a rewriter rather than a generator. The simplified output only contains three variables (ABC):

    var why;
    var does;
    var say;
    for (why = 1; why < 101; why += 1) {
        say = '';
        does = !(why % 3);
        if ( does ) {
          say += 'Fizz';
        }
        does = !(why % 5);
        if ( does ) {
          say += 'Buzz';
        }
     }
    

    2. Infinite distance

    What if distance-based coding was scoped, and each scope always matched something (at any distance). In theory, this would mean that any unknown would always be taken as the previous declaration:

    var A;
    zzzzzzzz = 0;
    

    The terms would would match, because A is "the only variable in the room" so to speak -- and thus the addressee or referent. This creates an unrestricted field of language for scopes with one declared variable, a bipartite field for two variables, et cetera. So this would be valid:

    var value = 1;
    five = one + two + three + four + five;
    ten = five + five;
    hundred = ten * ten;
    console.log(result);
    

    ...as it would resolve to:

    var value = 1;
    value = value + value + value + value + value;
    value = value + value;
    value = value * value;
    console.log(value);
    

    The effect would be somewhat like the way in spoken language we may assume the attachment of new referents to priors.

    "Hypatia walked in. She looked around, and then the mathematician sat down.

    I say "would" throughout these examples because FatFinger.JS does not actually work that way -- at least not completely. It is not a tabula rasa that starts out empty and gets populated by new variable names as they are declared by the coder. Instead, it is already pre-populated with things like the built-in keywords of JavaScript: words like alert, document, name, et cetera.

    3. Poetics at the intersection of English and JavaScript

    Given that some language API is already present and already exerting a gravitational pull one nearby language, I was curious what the effects were. As an initial test I tried running words from Ogden's Basic English list (~850 words) through FatFinger.js as undeclared variable names in the form word++; in order to see if and when the parser would replace them common English words with JavaScript words.

    The following is a list of the pre-existing synonyms that resolved to JavaScript keywords; a kind of rhyming dictionary for default FatFinger.JS (although some of its effects could be disrupted with each new declaration).

    In each entry the keyword is given first, then a list of all the Basic English words that might resolve to it. I was so pleased with the results that I'm naming it.


    "In Other Words (Fat Dactyls)"
    2020-02-20

    • alert

      • angry, answer, art, basket, camera, cart, danger, debt, earth, east, electric, expert, heart, heat, here, left, meat, paper, quality, regret, short, sleep, sort, start, sweet, test, there, violent
    • confirm

      • comfort, country, bottle, canvas, committee, common, complete, complex, conscious, control, cotton, little, measure, muscle, poison, possible, responsible, tongue
    • document

      • adjustment, argument, development, different, government, instrument
    • history

      • discovery, harmony, industry, library, military, picture, scissors, sister
    • location

      • addition, attention, attraction, behavior, comparison, competition, condition, connection, decision, digestion, direction, discussion, education, expansion, fiction, invention, motion, observation, operation, position, question, reaction, relation, suggestion
    • name

      • angle, awake, base, brake, cake, care, damage, dark, day, edge, example, face, flame, hammer, hate, have, knife, late, make, male, mark, mass, may, nail, nerve, news, note, number, page, paste, rail, range, rate, ray, safe, same, shade, shake, shame, snake, some, space, spade, table, take, taste, time, trade, walk, wall
    • navigator

      • daughter
    • prompt

      • attempt, group, produce, profit, property, protest, pump, thought
    • screen

      • between, degree, garden, green, science, screw, secret, street, sudden, summer

    At this point it is tempting to write a group of simple FatFinger.JS programs in this constrained vocabulary, and I still may. However to me this is already a piece of writing (upon which other writing could be built), and it already suggests insights and at least one conclusion. "In Other Words" is a discovered vocabulary which is poetic in itself. It is not contained anywhere in the source code of FatFinger.JS, but which is nonetheless effected, purely by how an implementation of closing distances causes the English language to interact with JavaScript. This suggests that, given a computed distance or difference and a potential vocabulary, any equivalent coding language or tool also has its own poetic vocabulary: a secret thesaurus waiting to be discovered.

Sign In or Register to comment.