1. 33
  1. 10

    I may just be missing the point because I’m cranky (I should probably drink some water…) but, in light of the stated aim of giving practitioners a beneficial definition, this definition-narrowing project feels a bit quixotic?

    I guess the reason is a little ironic.

    I agree that we don’t communicate clearly about abstraction, and that a lot of the lack of clarity is a byproduct of how many ~distinct practices we are sweeping under this particular rug. But the project doesn’t seem to stop and ask if, despite the lack of clarity, the term is closing over this many things for ~good reasons (in a way that is consistent with the word’s etymology).

    IANAPLT, but abstracting is, much like theorizing, an exercise in making sense of things–and forging (neologizing) the grammar necessary to do so.

    1. 7

      One of the early academic culture shocks I had back when, as a young engineering student, I tried to seriously dabble in humanities and enroll in philosophy or history classes, was that almost every serious book I picked up started with an entire section consisting of an inventory of how every major author defined the thing that book was about. Every course started with a very serious discussion about said definitions, too, and it was pretty challenging for me. Smartass (student, yes?) me thought this was ridiculous: I thought, you know, if no one has been able to even come up with a satisfactory definition of what historiography is, for example, maybe it shouldn’t be a course?

      It took me a while to realize that there’s a difference between advancing a particular classification, which has real investigative value, and simply quibbling on classification and definition, which is, well, just quibbling. The former, I think, has exactly the property that you mention, or perhaps more aptly put, its “mathematical inverse”:

      But the project doesn’t seem to stop and ask if, despite the lack of clarity, the term is closing over this many things for ~good reasons (in a way that is consistent with the word’s etymology).

      There are about as many definitions and conventions about the Middle Ages, for example, as there are authors. But choosing one over the other does not in any way impede the study of medieval culture. In fact, no matter which one you’re partial to, considering other definitions may help shed light over a particular problem or phenomenon. All major works on the topic disagree about its boundaries somewhat, but everyone understands how it works and they’re universally useful.

      Then there are of course the various book sections, papers, articles and essays which spend pages trying to answer questions like “should X be classified as a philosopher of late antiquity, or early middle ages?”. Unsurprisingly, no one finds those too important.

      I think there’s value to this approach in technical debates, too. It’s not a problem that only “young” branches of engineering have. Software engineering isn’t the only one that’s struggling with definitions and it’s not because it’s young – there are plenty of electrical engineers (myself included) who are really antsy about transformers being classified as electrical machines, since nothing is spinning inside a transformer, and both are more like 150-200 years old at this point. But it is a tight margin to walk on. The border between good-natured investigation and quibbling is pretty fuzzy.

      1. 2

        Historiography is pretty much universally agreed to be the history of how histories have been told over historical time. But that just pushes the problem back one square because then you have to define history, and I don’t think there’s any consensus there. Everyone agrees it has to do with the past, but it’s pretty slippery beyond that.

        My take is history is the way that the past continues to be important today. Something is important if it makes a causal difference (it doesn’t just wash out as chaotic noise). Causal influence can broken down into physical (the Roman aqueducts are still there, eg) or ideological (the idea of a Roman empire influences a lot of European behavior) influence. And so on, each of those concepts can be broken down and clarified basically forever. :-)

        1. 2

          Historiography is pretty much universally agreed to be the history of how histories have been told over historical time.

          Well, yes, on a high level, but the fact that this definition is a little recursive is exactly why it’s usually not formulated quite that way, and it’s also not the only definition that’s presented in introductory courses, or at least not in all introductory courses, I guess?

          The one I was given went something along the lines of the study of the methods that historians used to investigate, present, and interpret history over time. This isn’t a trivial distinction, because the methods and even the object of historical investigation have evolved over time, even in recent times. For example, for the longest time, historians were concerned with understanding the context in which a historical work was written primarily in order to assess its veridicity.

          E.g. European historians in antiquity and the middle ages sometimes went out of their way to paint a favourable image of their protector, or an unfavourable image of an otherwise apt ruler who, unfortunately, happened not to be Christian. Understanding when they were presenting fact and when they were talking out of their ass is obviously important, and sometimes you have to resort to indirect evidence to figure that out, because there are no other sources to verify a claim from. But in time, people have tried to make this exercise even more productive, and use it to understand how social values have changed, how the role that Christian doctrine (itself in perpetual evolution) has played in the interpretation of history, or even how various ethical or ecclesiastical views have spread over time.

          These things – and this is the second reason why introductory lectures are a little more complicated than “this is what it is, now let’s get to it” – haven’t always been a part of historiography, or they haven’t played the same role they play today. You have to explain how this has changed over time, and how historiographers themselves have viewed their field, even views which are now completely obsolete, otherwise someone will read a book from the 1910s and get entirely the wrong message.

          The term itself is polysemantic – it’s commonly used to refer not only to the discipline itself, but also to what used to be its primary object of study, i.e. written sources of history and especially secondary sources. It seems obvious to you and me that, when someone says “the siege and fall of Constantinople are prominently featured in Western historiography” means that there are lots of history books about it, not that historiographers (in the modern sense, which is nothing like what historiographer meant back in the 17th century meant) paid a lot of attention to it. But it’s really something that has to be stated, even if just for clarity.

      2. 4

        I found it deeply insightful.

        Specifically, as a formal framework for giving precision to intuition I’ve built up over the years. To use the article’s framework, I found an abstraction mapping my personal heuristics and models about abstraction to this simpler, unifying idea.

        1. 2

          I wouldn’t argue that it’s uninsightful.

          I think it’s a kind of missing-the-forest-for-the-trees. It focuses on things we might touch when abstracting and not on what we accomplish by abstracting. It proposes a narrower definition of the term in the more literal context, and doesn’t acknowledge–let alone fill–the hole it’s leaving in the more motivational one.

          1. 3

            I think you might be misreading the intent. The author’s primary interest is applying “academic” insights like these back in the real world. The motivation here is to improve your skills as a code designer. Granted, it would have been helpful to see a problem worked though applying these insights, but I took this as a high-level piece, where those kinds of lessons were left as exercises to the reader.

            As I read it, the “narrower definition” you’re referring to is meant as framework for evaluating real-world abstractions, and perhaps for finding them too. So if something “feels funny” about a design, you can analyze it through this lens, finding the two domains, evaluating precisely how the abstract domain helps you – which operations track between the concrete domain and abstract one and does that simplify your problem? It might help pinpoint where an abstraction is “leaky” and how to fix that.

            1. 1

              Not sure there is daylight between this statement of motive and the one in my first post (but of course I still agree that I may be misunderstanding).

              In any case, names are abstractions. Part of naming things is deciding where they start and end. In part by association and in part because they can be described with slightly less woo, the tools and techniques we use to separate, extract, group, collect–and to name the things separated, extracted, grouped, and collected–become a synechdoche for what we’re here to do.

              I suppose the traditional way to think of this is carving nature at its joints, but I would resist framing it that way. There’s a risk of missing the point and reifying joints just because they appear to be natural. Sometimes this is right, and sometimes not. Our perception lies, of course, and two creatures that appear related are in fact far from it.

              The article focuses on a narrow thing:

              abstractions are mappings between a complex concrete world and a simple idealized one. For concrete data types, an abstraction maps a complicated data structure to the basic data it represents. For systems, an abstraction relates the tiny state changes from every line implementing a TCP stack with the information found in the actual protocol diagram. These abstractions become useful when one can define interesting operations purely on the abstract form

              It tries to remove from our quiver (and keep for itself) a term we use to acknowledge that namemaking–including the guesses we make about where the seams lurk–is how we weave a grammar that helps humans (continually) make sense of the program/problem domains.

              The ~world of this grammar need not be simple or idealized. It may often be–but is at its most fraught when it tries desperately to avoid or simplify intrinsic complexity that the humans must inevitably come to terms with. We can likewise weave simplified/idealized grammars that do not make much sense to many humans.

      3. 7

        This article makes many good points, but I think there is some danger in trying to “reclaim” terms from programming to be more like their mathematical counterparts. Unfortunately a very common pattern is that words from math are abused by programmers. The terms are diluted and distorted when put into practice.

        For example, I’ve given up on “regular expression”. “Regex” or “regular expression” now means something Perl-like. However, the distinction between math and programming IS of engineering consequence, so now I advocate ALSO using the term “regular language”.

        That is, programmers should learn both words because they refer to different things. There’s intentionally no conflict between “regex” aka “regular expression” and “regular language”.

        https://www.oilshell.org/blog/2020/07/eggex-theory.html

        One that I will not give up on yet is “context free”. There seem to be extremely baffling and confident misunderstandings by of this term, e.g.: https://lobste.rs/s/h9ypxi/is_golang_s_grammar_context_free . This post makes no sense because the author’s conception of the term “context free” is simply wrong.

        (And that’s not the first one; Walter Bright of D misunderstands of the term as well … You can use words poorly and still be a great engineer.)

        A key difference here is that being context free has virtually no engineering consequences, while being regular does. So programmers should simply not use this word – they should use words that refers to the engineering issues they care about – does it run fast, LALR(1), can you write a syntax highlighter in vim for it, etc.


        The article seems to be defining “abstraction” as roughly “good abstraction”. I like the emphasis on precision:

        The purpose of abstraction is not to be vague, but to create a new semantic level in which one can be absolutely precise.

        However that’s not what abstraction means to programmers. I would quibble with all these statements at the end:

        • functions are not abstractions
        • Anti-unification is not abstraction
        • Indirection is hella not abstraction
        • Typeclasses and interfaces are not abstraction

        One way you can see this is that everybody knows what “duplication is better than the wrong abstraction” means.

        So abstractions can be poor, they can be wrong, and they are necessarily leaky (as Joel says).

        I think the article would be better served by defining or finding a better term for the strong, Djikstra kind of abstraction. Otherwise it’s kind of like shouting into the wind “regexes aren’t regular”!!! This has been known for decades but programmers still use the word the other way because it’s in all their documentation. Similarly with “abstraction”.

        For example, I purposely used the term “narrow waist” to make several points about design decisions with engineering consequences:

        And although it’s an existing term, it was both unfamiliar and useful to many readers. I noted in the second post that the clearest objection is that a narrow waist is simply a “standard”. But there can be bad standards, and all standards have to come from somewhere.

        So choosing words is very difficult but I think this line of thought (which it looks like will be continued in future blog posts, which I expect to be valuable) needs another one IMO!


        It could just be “strong abstraction” or “Djikstra abstraction”, etc. I also question whether most programmers will ever create a truly strong abstraction (including myself). I think they are mostly “discovered” by a small group, evolved, and then used widely.

        I’d also note that in practice leaky abstractions ARE useful, and they’re the rule more than the exception. JSON is leaky because C has fixed size integers, Python has arbitrary size integers, and JavaScript has floats. TCP is a very tight abstraction but performance concerns leak (e.g. are you using wired or wireless), and configuration leaks too (did you connect to hotel wi-fi)

        1. 2

          JSON is leaky because C has fixed size integers, Python has arbitrary size integers, and JavaScript has floats. TCP is a very tight abstraction but performance concerns leak (e.g. are you using wired or wireless), and configuration leaks too (did you connect to hotel wi-fi)

          TCP is a good example, but JSON is not, in my opinion. The fact that C has no native arbitrary sized integers has absolutely nothing to do with JSON. Only with specific JSON implementations, that simply fail to implement the full specification.

          1. 2

            There are no semantics of numbers (or strings or anything else) in JSON spec. It’s purely syntax.

            So all those implementations do in fact conform to the spec.

            JSON is a compromise by definition (one of the properties of a narrow waist), and that’s a feature not a bug. The languages are fundamentally different but they need to interoperate

            This is precisely where programming has a much different flavor than math.

            1. 2

              Come on, we all know what numbers mean in JSON. At the very minimum, it means 64-bit floating point numbers. And in general, it means whatever range you need. If you need to represent 255-bit integers (like elliptic curve points or whatever), and your language of choice fails to properly translate them to a data structure that faithfully represent that number, that’s not a leaky abstraction, that’s an error, plain and simple.

              Would you call the possibility of such errors a feature? Tell me, how narrow that waist really is? Shall we limit ourselves to simple precision floating points numbers? 32-bit signed integers? At the end of the day, you need a fully specified JSON flavour to build a reliable protocol. And if you need to process big numbers, you’d better handle them correctly even in C. Lucky you, JSON is easy to parse.

              You talk like programming is different than the rest of math because of such lack of rigour. That would be a fatal mistake. Math often runs on humans, which can automatically correct mistakes or lift ambiguities. The cognitive engines programs run on are not so forgiving: everything runs on a fully specified formal language (I’m talking about the compiler & actual computer, not the specs), and any deviation from our expectations can have interesting consequences. And you’re suggesting that having a partially unspecified protocol in extremely wide use out there is a good thing??

              Programming is different, but I think for other reasons. Imperative programming in particular is very different from your usual high school math, not least because of its temporal logic. Program organisation has strong ties to graph theory, that most people never learn before college. Type theory is crucial to programming language designers (and Go designers should have studied Pierce’s work dammit), and you’d be hard press not to see it as extremely rigorous math.

              Programming is different, but what it definitely is not, is more forgiving.

              1. 1

                Come on, we all know what numbers mean in JSON.

                We literally don’t! JSON doesn’t actually define the meaning (semantics) of numbers.

                JSON is agnostic about the semantics of numbers. In any programming language, there can be a variety of number types of various capacities and complements, fixed or floating, binary or decimal. That can make interchange between different programming languages difficult. JSON instead offers only the representation of numbers that humans use: a sequence of digits.

                1. 2

                  Thanks for the link, I followed it and noticed that you have omitted the end of the paragraph:

                  All programming languages know how to make sense of digit sequences even if they disagree on internal representations. That is enough to allow interchange.

                  Indeed C and Python will not represent numbers the same way. But a JSON library better correctly handle any number that comes its way (for any particular use case), even if those are 42 digit decimal integers. In fact, this sentence confirms my intuition that JSON numbers are never meant to have less precision than the number of significant digits suggest. It was naughty of you to omit it.

                  I mean, those are numbers, right? We humans definitely agree on what they mean, and the only wiggle room we have there is rounding errors for floating point numbers. No one in their right mind would say the numbers 9876543210 and 1286608618 are equal just because their programming language of choice happens to use 32-bit unsigned integers by default. Interchange requires that they are not.

                  Object semantics however are a bit more worrying:

                  The JSON syntax does not impose any restrictions on the strings used as names, does not require that name strings be unique, and does not assign any significance to the ordering of name/value pairs. These are all semantic considerations that may be defined by JSON processors or in specifications defining specific uses of JSON for data interchange.

                  Not requiring keys to be unique is unfortunate, given how pretty much all implementations tend to assume they are. Same thing for ordering, there’s a hint that we’d be allowed to ascribe some significance to it, if we chose to spec our protocol that way. At least they do suggest that for any given application, such ambiguities should be lifted, so the only real effect here is fragmentation.

                  1. 1

                    But a JSON library better correctly handle any number that comes its way (for any particular use case), even if those are 42 digit decimal integers.

                    Hah! I wish it were true.

                    Alas, “any number” is not well defined in general, so it’s difficult to scope what “handling any number” would require of implementations. A browser’s Javascript engine may not be able to manage numbers that my beefy threadripper desktop can manage. JSON permits this! It says that implementations can have varying capacity for numbers while remaining spec-compliant.

                    I mean, those are numbers, right? We humans definitely agree on what they mean, and the only wiggle room we have there is rounding errors for floating point numbers. No one in their right mind would say the numbers 9876543210 and 1286608618 are equal just because their programming language of choice happens to use 32-bit unsigned integers by default. Interchange requires that they are not.

                    We humans know what numbers are abstractly, sure! But “what numbers mean to humans” and “what numbers mean in JSON” are two distinct things. JSON numbers are definitely not defined or required to be 64-bit floats, much less whatever range I decide I need them to be. They’re more or less undefined!

                    1. 1

                      Alas, “any number” is not well defined in general,

                      Not so much poorly defined than impossible to fully implement (computers are finite, and the range of numbers they can handle is finite as well), but that’s not the important bit. The important bit is, I wrote “any number that comes its way”.

                      In any given real situation, you’re supposed to know what range of numbers you’d expose your library to. If that range exceeds what this library can handle, use another library. Make one if you have to (as I’ve said above, JSON is easy to parse).

                      JSON numbers are definitely not defined or required to be […] whatever range I decide I need them to be.

                      That would mean you can’t safely use JSON. Like, ever. But you do use JSON from time to time, don’t you? In practice what you do is making sure the JSON flavour you are using is good enough for the data your problem will throw at it.

                      1. 1

                        That would mean you can’t safely use JSON. Like, ever.

                        For stricter definitions of “safely” that’s true! It is absolutely possible that a big big number delivered to my low-power JSON parser produces an error, or even an invalid value. Safety is a spectrum, not a boolean; i don’t think any protocol or language or construct realized by a von Neumann computational machine can provide perfect safety in the sense you mean.

        2. 4

          More generally, abstractions are universal properties (WP, nLab). For example, the natural numbers (WP, nLab) are the universal way to count the size of discrete collections.

          See also Shutt’s take on abstraction and abstractive power, which is also category-theoretic but defines abstractiveness as a sort of derivative of expressiveness, itself a derivative of semantics.

          1. 4

            My view is that to attempt to define abstraction in strictly computing terms is problematic. Part of that problem is that mechanisms of programming like the module, class, object, inheritance, composition, ADT, procedure and function, are *means” to support the act of abstraction. To derive a definition of abstraction from them is nonsensical.

            Consider instead that to abstract is to create concepts to capture the complexity of the world around us. It is a core human process.

            A concept is a generalized idea of a collection of phenomena, based on knowledge of common properties of instances in the collection. A phenomenon is a thing that has definite, individual existence in reality or in the mind. Concepts themselves are formally described in terms of their intension, extension and designation. Furthermore there are two typical viewpoints: the Aristotelian and the Prototypical.

            1. 3

              Thank you for “anti-unification” I needed to be able to name that.

              1. 3

                I think what Sussman was implying is that all of your ‘not abstraction’ definitions are captured by the more general definition which is the primary one… Even changing the name of a function (and doing nothing else) mixes a different semantic and qualifies as ‘an abstraction’ under a certain way of looking at things.

                Maybe you can ask him for me :wink: but in real world programming even ‘trivial’ transformations on the names of functions can have profound effects on what the code does (by modifying the semantic, which changes how the code is used).

                We don’t have a word for, ‘generally fiddling around’, what are we changing? Maybe you can suggest one, but I’ll stick with Sussman’s suggestion for now.

                1. 1

                  Sussman was talking about universal properties in category theory, using an example from the category of groups.

                  1. 2

                    Yeah! Consider the case where phi is a ‘renaming’ if your domain allows it (otherwise phi is some kind of identity) and f equals h.

                    Still an abstraction.

                2. 2

                  Which of these categories does “OS” fall into? Virtual memory? fork()?

                  1. 2

                    I’ll take virtual memory… The abstraction is actually “memory”, that is, a contiguous set of integer addresses at which you can store and retrieve data (or fail to do so in a defined way) using machine instructions. There are many and various implementations of “memory”: physical RAM, paged virtual memory, the even more “virtual” memory of an emulated processor, etc. But they all implement the same abstraction that the machine code is written to rely on.

                  2. 1

                    This is a definition of abstraction, but is it the definition? Abstraction is an abstract concept! 😉 I think anything which encapsulates a complex domain and presents a simplified model qualifies.