Whenever someone argues the uselessness or redundancy of a particular word, a helpful framework to understand their perspective is "Lumpers vs Splitters" : https://en.wikipedia.org/wiki/Lumpers_and_splitters
An extreme caricature example of a "lumper" would just use the word "computer" to label all Turing Complete devices with logic gates. In that mindset, having a bunch of different words like "mainframe", "pc", "smartphone", "game console", "FPGA", etc are all redundant because they're all "computers" which makes the various other words pointless.
On the other hand, the Splitters focus on the differences and I previously commented why "transpiler" keeps being used even though it's "redundant" for the Lumpers : https://news.ycombinator.com/item?id=28602355
We're all Lumpers vs Splitters to different degrees for different topics. A casual music listener who thinks of orchestral music as background sounds for the elevator would be "lump" both Mozart and Bach together as "classical music". But an enthusiast would get irritated and argue "Bach is not classical music, it's Baroque music. Mozart is classical music."
The latest example of this I saw was someone complaining about the word "embedding" used in LLMs. They were asking ... if an embedding is a vector, why didn't they just re-use the word "vector"?!? Why is there an extra different word?!? Lumpers-vs-splitters.
I'm not convinced your L/S dichotomy applies. The concern there is that the natural world (or some objective target domain) has natural joints, and the job of the scientist (, philosopher, et al.) is to uncover those joints. You want to keep 'hair splitting' until the finest bones of reality are clear, then grouping hairs up into lumps, so their joints and connections are clear. The debate is whether the present categorisation objectively under/over-generates , and whether there is a factor of the matter. If it over-includes, then real structure is missing.
In the case of embeddings vs. vectors, classical vs., baroque, transpiler vs., compiler -- i think the apparent 'lumper' is just a person ignorant of classification scheme offered, or at least, ignorant of what property it purports to capture.
In each case there is a real objective distinction beneath the broader category that one offers in reply, and that settles the matter. There is no debate: a transpiler is a specific kind of compiler; an embedding vector is a specific kinds of vector; and so on.
There is nothing at stake here as far as whether the categorisation is tracking objective structure. There is only ignorance on the part of the lumper: the ignorant will, of course, always adopt more general categories ("thing" in the most zero-knowledge case).
A real splitter/lumper debate would be something like: how do we classify all possible programs which have programs as their input and output? Then a brainstorm which does not include present joint-carving terms, eg., transformers = whole class, transformer-sourcers = whole class on source code, ...
It's all about context, isn't it? "Humans vs. animals" is an important distinction to make in some contexts and useless in others. Insisting on the fact that humans are also animals if we're talking about, say, "language in humans vs. animals" is unproductive. It just makes discussions harder by forcing everyone to add "_non-human_ animals" to every mention. But if we're talking about, say, cellular biology, it's unproductive to force everyone to write "human and animal cells" instead of just "animal cells".
Similarly, distinguishing between transpilers and compilers might be important in some contexts and useless in others. Transpilers are source-to-source compilers, a subset of compilers. Whether it matters depends on the context.
> An extreme caricature example of a "lumper" would just use the word "computer" to label all Turing Complete devices with logic gates.
I don't think that's a caricature at all; I've often seen people argue that it should include things like Vannevar Bush's differential analyzer, basically because historically it did, even though such devices are neither Turing-complete nor contain logic gates.
'computer' is an ambiguous word. In a mathematical sense a computational process is just any which can be described as a function from the naturals to naturals. Ie., any discrete function. This includes a vast array of processes.
A programmable computer is a physical device which has input states which can be deterministicaly set, and reliably produce output states.
A digital computer is one whose state transition is discrete. An analogue computer has continuous state transition -- but still, necessarily, discrete states (by def of computer).
An electronic digital programmable computer is an electric computer whose voltage transitions count as states discretely (ie., 0/1 V cutoffs, etc.); its programmable because we can set those states causally and deterministically; and its output state arises causally and deterministically from its input state.
In any given context these 'hidden adjectives' will be inlined. The 'inlining' of these adjectives causes an apparent gatekeepery Lumpy/Splitter debate -- but it isnt a real one. Its just ignorance about the objective structure of the domain, and so a mistaken understanding about what adjectives/properties are being inlined.
In fact ‘computer’ used to be a job description: a person who computes.
Yes, definitely. And "nice" used to mean "insignificant". But they don't have those meanings now.
Most functions from the naturals to naturals are uncomputable, which I would think calls into question your first definition.
It's unfortunate that "computer" is the word we ended up with for these things.
Ah well, that's true -- so we can be more specific: discrete, discrete computable, and so on.
But to the overall point, this kind of reply is exactly why I don't think this is a case of L vs. S -- your reply just forces a concession to my definition, because I am just wrong about the property I was purporting to capture.
With all the right joint-carving properties to hand, there is a very clear matrix and hierarchy of definitions:
With the physical serving as implementations of partial elements of the mathematical.
Word definitions are arbitrary social constructs, so they can't really be correct or incorrect, just popular or unpopular. Your suggested definitions do not reflect current popular usage of the word "computer" anywhere I'm familiar with, which is roughly "Turing-complete digital device that isn't a cellphone, tablet, video game console, or pocket calculator". This is a definition with major ontological problems, including things such as automotive engine control units, UNIVAC 1, the Cray-1, a Commodore PET, and my laptop, which have nothing in common that they don't also share with my cellphone or an Xbox. Nevertheless, that seems to be the common usage.
> Word definitions are arbitrary social constructs, so they can't really be correct or incorrect, just popular or unpopular.
If you mean that classifications are a matter of convention and utility, then that can be the case, but it isn’t always and can’t be entirely. Classifications of utility presuppose objective features and thus the possibility of classification. How else could something be said to be useful?
Where paradigmatic artifacts are concerned, we are dealing with classifications that join human use with objective features. A computer understood as a physical device used for the purpose of computing presupposes a human use of that physical thing “computer-wise”, that is to say objectively, no physical device per se is a computer, because nothing inherent in the thing is computing (what Searle called “observer relative“). But the physical machine is objectively something which is to say ultimately a collection of physical elements of certain kinds operating on one another in a manner that affords a computational use.
We may compare paradigmatic artifacts with natural kinds, which do have an objective identity. For instance, human beings may be classified according to an ontological genus and an ontological specific difference such as “rational animal“.
Now, we may dispute certain definitions, but the point is that if reality is intelligible–something presupposed by science and by our discussion here at the risk of otherwise falling into incoherence–that means concepts reflect reality, and since concepts are general, we already have the basis for classification.
No, I don't mean that classifications are a matter of convention and utility, just word definitions. I think that some classifications can be better or worse, precisely because concepts can reflect reality well or poorly. That's why I said that the currently popular definition of "computer" has ontological problems.
I'm not sure that your definition helps capture what people mean by "computer" or helps us approach a more ontologically coherent definition either. If, by words like "computing" and "computation", you mean things like "what computers do", it's almost entirely circular, except for your introduction of observer-relativity. (Which is an interesting question of its own—perhaps the turbulence at the base of Niagara Falls this morning could be correctly interpreted as finding a proof of the Riemann Hypothesis, if we knew what features to pay attention to.)
But, if you mean things like "numerical calculation", most of the time that people are using computers, they are not using them for numerical calculation or anything similar; they are using them to store, retrieve, transmit, and search data, and if anything the programmers think of as numerical is happening at all, it's entirely subordinate to that higher purpose, things like array indexing. (Which is again observer-relative—you can think of array indexing as integer arithmetic mod 2⁶⁴, but you can also model it purely in terms of propositional logic.)
And I think that's one of the biggest pitfalls in the "computer" terminology: it puts the focus on relatively minor applications like accounting, 3-D rendering, and LLM inference, rather than on either the machine's Protean or universal nature or the purposes to which it is normally put. (This is a separate pitfall from random and arbitrary exclusions like cellphones and game consoles.)
That's very interesting!
Splitters make more sense to me since different things should be categorized differently.
However, I believe a major problem in modern computing is when the splitter becomes an "abstraction-splitter."
For example, take the mouse. The mouse is used to control the mouse cursor, and that's very easy to understand. But we also have other devices that can control the mouse cursor, such as the stylus and touchscreen devices.
A lumper would just say that all these types of devices are "mouses" since they behave the same way mouses do, while a splitter would come up with some stupid term like "pointing devices" and then further split it into "precise pointing devices" and "coarse pointing devices" ensuring that nobody has absolutely no idea what they are talking about.
As modern hardware and software keeps getting built on piles and piles of abstractions, I feel this problem keeps getting worse.
I don't understand what the issue is: a transpiler is a compiler that outputs in a language that human programmers use.
It's good to be aware of that from an engineering standpoint, because the host language will have significantly different limitations, interoperability and ecosystem, compared to regular binary or some VM byte-code.
Also, I believe that they are meaningfully different in terms of compiler architecture. Outputting an assembly-like is quite different from generating an AST of a high-level programming language. Yes of course it's fuzzy because some compilers use intermediate representations that in some cases are fairly high-level, but still they are not meant for human use and there are many practical differences.
It's a clearly delineated concept, why not have a word for it.
GCC outputs textual GNU assembly language, in which I have written, for example, a web server, a Tetris game, a Forth interpreter, and an interpreter for an object-oriented language with pattern-matching. Perhaps you are under the illusion that I am not a human programmer because this is some kind of superhuman feat, but to me it seems easier than programming in high-level languages. It just takes longer. I think that's a common experience.
Historically speaking, almost all video games and operating systems were written in assembly languages similar to this until the 80s.
Transpilers are compilers that translate from one programming language to the other. I am not 100% sure where these "lies" come from, but it's literally in the name, it's clearly a portmanteau of translating compiler... Where exactly are people thinking the "-piler" suffix comes from?
Yes, I know. You could argue that a C compiler is a transpiler, because assembly language is generally considered a programming language. If this is you, you have discovered that there are sometimes concepts that are not easy to rigorously define but are easy for people to understand. This is not a rare phenomenon. For me, the difference is that a transpiler is intending to target a programming language that will be later compiled by another compiler, and not just an assembler. But, it is ultimately true that this definition is still likely not 100% rigorous, nor is it likely going to have 100% consensus. Yet, people somehow know a transpiler when they see one. The word will continue to be used because it ultimately serves a useful purpose in communication.
One distinction is that compilers generally translate from a higher-level language to a lower-level language whereas Transpilers target two languages which are very close in the abstraction level.
For example a program that translated x86 assembly to RISC-V assembly would be considered a transpiler.
The article we are discussing has "Transpilers Target the Same Level of Abstraction" as "Lie #3", and it clearly explains why that is not true of the programs most commonly described as "transpilers". (Also, I've never heard anyone call a cross-assembler a "transpiler".)
On the contrary: it reifies people's prejudices and prevents them from seeing reality, often in the service of intentional deception, which for my purposes is the opposite of a useful purpose in communication.
There's currently a fad in my country for selling "micellar water" for personal skin cleansing, touted as an innovation. But "micelles" are just the structure that any surfactant forms in water, such as soap, dish detergent, or shampoo, once a certain critical concentration is reached, so "micellar water" is just water with detergent in it. People believe they are buying a new product because it's named with words that they don't know, but they are being intentionally deceived.
Similarly, health food stores are selling "collagen supplements" for US$300 per kilogram to prevent your skin from aging. These generally consist of collagen hydrolysate. The more common name for collagen hydrolysate is "gelatin". Food-grade gelatin sells for US$15 per kilogram. (There is some evidence that it works, but it's far from overwhelming, but what I'm focusing on here is the terminology.) People believe they are buying a special new health supplement because they don't know what gelatin is, but they are being intentionally deceived.
You might argue, "People somehow know micellar water when they see it," or, "People somehow know collagen supplements when they see them," but in fact they don't; they are merely repeating what it says on the jar because they don't know any better. They are imagining a distinction that doesn't exist in the real world, and that delusion makes them vulnerable to deception.
Precisely the same is true of "transpilers". The term is commonly used to mislead people into believing that a certain piece of software is not a compiler, so that knowledge about compilers does not apply to it.
> The term is commonly used to mislead people into believing that a certain piece of software is not a compiler, so that knowledge about compilers does not apply to it.
Why would people use a word that has the word "compiler" in it to try to trick people into thinking something is not a compiler? I'm filing this into "issues not caused by the thing that is being complained about".
IMO: Transpilers are compilers, but not all compilers are transpilers.
In my book, transpilers are compilers that consume a programming language and target human-readable code, to be consumed by another compiler or interpreter (either by itself, or to be integrated in other projects).
i.e. the TypeScript compiler is a transpiler from TS to JS, the Nim compiler is a transpiler from Nim to C, and so on.
I guess if you really want to be pedantic, one can argue (with the above definition) that `clang -S` might be seen as a transpiler from C to ASM, but at that point, do words mean anything to you?
For me, the "human-readable" part is key. It's not just that the output is e.g. javascript, but that it is more or less human-readable with about the same organization as the original code.
If you implement SKI combinators, or three-address instructions, as functions in javascript, and that's the output of your compiler, I would not call that a transpiler.
Exactly. For a web dev oriented example, I would call coffeescript a transpiler, since it would transform
# some comment
myFun = ->
alert 'Hello CoffeeScript!'
into
// some comment
var myFun;
myFun = function() {
return alert('Hello CoffeeScript!');
};
clearly intending the output code to be quite readable (even preserving comments).
Whereas Elm is a compiler since it transforms
module Main exposing (main)
import Html
main =
Html.text "Hello Elm!"
into
(function(scope){
'use strict';
function F(arity, fun, wrapper) {
wrapper.a = arity;
wrapper.f = fun;
return wrapper;
}
// about 4000 lines ommitted
var $author$project$Main$main = $elm$html$Html$text('Hello Elm!');
_Platform_export({'Main':{'init':_VirtualDom_init($author$project$Main$main)(0)(0)}});}(this));
Clearly not intended for (easy) human consumption.
I can usually read JS generated by TS, but calling the C Nim outputs
"human-readable" is very generous considering it flattens most structured
control flow to goto. (It's hard to do it otherwise, Nim has to deal with
exceptions and destructors but C has neither.)
Classifying Nim as a transpiler also results in weird cases like NLVM[1]
which most would consider a compiler even though it is a back-end on the
same "level" as Nim's C generator.
I'd probably say that "transpiler" is not a very useful word with that definition.
Why is it useless? 'Compiler' denotes the general category, within which exist various sub-categories:
For example, a 'native compiler' outputs machine code for the host system, a 'cross compiler' outputs machine code for a different system, a 'bytecode compiler' outputs a custom binary format (e.g. VM instructions), and a 'transpiler' outputs source code. These distinctions are meaningful.
[deleted]
I can’t see why — I do think that the word does convey some sort of useful meaning with the above definition.
I think the distinction is meaningful - for example many compilers used to have C backends (GCC for example did) - so you code went through almost the entire compiler pipeline - from frontend to IR to backend where the backend did almost everything a compiler does, it only skipped target machine specific stuff like register allocation (possibly even that was done), arch specific optimizations and assembly generation.
A transpiler to me focuses on having to change or understand the code as little as possible - perhaps it can operate on the syntax level without having to understand scopes, variable types, the workings of the language. It does AST->AST transforms (or something even less sophisticated, like string manipulation).
In my mind, you could have a C++ to C transpiler (which removes C++ constructs and turns them into C ones, although C++ is impossible to compile without a rich understanding of the code), and you could have a C++ to C compiler, which would be a fully featured compiler, architected in the way I described in the start of the post, and these would be two entirely different pieces of software.
So I'd say the term is meaningful, even if not strictly well defined.
> Lie #3: Transpilers Target the Same Level of Abstraction
> This is pretty much the same as (2). The input and output languages have the syntax of JavaScript but the fact that compiling one feature requires a whole program transformation gives away the fact that these are not the same language
It is not really the same as (2), you can't cherry pick the example of Babel and generalise it to every transpiler ever. There are several transpilers which transpile from one high-level language to another high-level language such as kotlin to swift. i.e; targeting the same level of abstraction.
Wonder what this person would say about macro expansions in scheme, maybe that should also be considered a compiler as per their definition.
BabelJS is the central example of "transpilers"; if BabelJS lacks some purported defining attribute of "transpilers", that definition is unsalvageable, even if there are other programs commonly called "transpilers" that do have that attribute.
> Compilers already do things that “transpilers” are supposed to do. And they do it better because they are built on the foundation of language semantics instead of syntactic manipulation.
I think the note about generators may be a good definition for when one language is "more powerful" than another; at least it's a good heuristic:
> The input and output languages have the syntax of JavaScript but the fact that compiling one feature [generators] requires a whole program transformation gives away the fact that these are not the same language. If we’re to get beyond the vagaries of syntax and actually talk about what the expressive power of languages is, we need to talk about semantics.
If a given program change is local in language X but global in language Y, that is a way in which language X has more expressive power.
This is kind of fuzzy because you can virtually always avoid this by implementing an interpreter, or its moral equivalent, for language X in language Y, and writing your system in that DSL (embedded or otherwise), rather than directly in language Y. Then, that anything that would be a local change in language X is still a local change. But this sort of requires knowing ahead of time that you're going to want to make that kind of change.
Thanks for the last link! At first read, the regeneration code is nuts: using a switch to assign a value, then comparing hard coded values. I only used generator functions in TS after they were supported in JS, so I’m going to step through that, just to understand it more.
Yeah, I mean, you either kind of have to do something like protothreads, or break apart the function into fragments at the yield points, converting it to explicit continuation-passing style.
Meaningless word + list of "lies"...
Nice read anyways.
"BabelJS is arguably one of the first “transpilers” that was developed so that people could experiment with JavaScript’s new language features that did not yet have browser implementations"
Just my two cents. Haxe was created long time ago, and BabelJS is arguably not one of the first "transpilers" people can play with.
I am not fond of the word either, but only because the use has often been used as a diminutive.
When used, it has often been implied that a compiler that outputs to a human-readable programming language wouldn't be a "real compiler".
Still far better than "Serverless".
I don't really understand the reasoning in the article. Nobody argues that orange is a meaningless word just because it's not wrong to call an orange a fruit.
Sure, a transpiler is a specialized form of compiler. However that doesn't mean it's not much clearer to describe a transpiler using the more specific name. As such recommending someone replace "compiler" with "transpiler" (when appropriate) does not mean using compiler is wrong. It simply means that, outside of some very niche-interest poetry, using transpiler is better!
"Programming languages are not just syntax; they have semantics too. Pretending that you can get away with just manipulating the former is delusional and results in bad tools."
So eloquently put, what starts off as just simple syntactic conversion usually snowballs into semantics very quickly.
It would be good if we had a term that didn't confuse linking with translation. In English compiling means joining together many parts, after all.
That one is historically interesting.
I suspect the first compilers were named that because they were making compilations of assembly routines, probably slightly modified/specialised to the rest of the routines.
Compilers still do that. Some of the input is your source,
but there's also "the compiler runtime" which is essentially a lot of extra routines that get spliced in, and probably "the language runtime" which gets similar treatment.
So compilers are still joining together parts, we've just mostly forgotten what crt or udiv.s are.
Linking and loading are more dubious names, but also they refer to specialised compilers that don't need to exist and probably shouldn't any more, so that may resolve itself over time.
The first compilers were called "translators". The first linker/loader (kinda, A-0 was a... strange tool, by modern standards) was actually called "compiler", precisely because of the generic meaning of the word "compile".
Today's meaningless word: Cloud
Language interoperability is a material question. Outputting Javascript, Python, C++ vs assembler/machine code have very different implications for calls to/from other languages
Is JIT also meaningless?
But ultimately if you don’t want to use a word, don’t use it. Not wanting to hear a word says more about the listener than the speaker
"Transpiler" is no less well-defined a term than "compiler".
The definition of compiler i learned was “takes some code, translate it to semantically equivalent code in a different language (which might be machine language, bytecode…)”. This is also used in PLaI, a respected learning resource: https://www.plai.org/
I think this is a pretty acceptable definition, and yes, it does make the term transpiler a little useless.
What I would add to your definition, to make a distinction from the common usage of compilation, is that the target language is on an approximately equivalent level of abstraction to the source. So, for example, Rust -> machine code is not transpilation, but Rust -> C++ is.
I think this is how the word is commonly understood, and it’s not useless (even if there’s no absolute standard of when it does or does not apply).
Edit: sorry, realise I should have read the article before commenting. The article calls out my definition as one of their ‘lies’. I guess I just disagree with the article. Words can be useful even without a 100% watertight definition. They’re for communication as well as classification.
One of the problems is that you might not use the target language at the equivalent level of abstraction. For example, C is a popular target language, but the C emitted may be very unidiomatic and nothing like human consumable code, it's not all that unusual that a language compiles all code to one big C function where the function calls in the language are jumps, which is a way to get around the limitations of the C calling conventions and stack.
The same thing applies to compilation to Javascript, the resulting code may use a tiny subset of the language.
I don't like the word transpiler, because there is nothing useful about the distinction (unless you count people using it to denigrate compilers that doesn't target traditional machine code).
I could see the case of using it as a name when the transformation is reversible, like you could probably turn Javascript back into Coffeescript.
What value does the word have? When I'm writing a compiler, it doesn't matter whether I target C or asm, or Javascript, as my output language. I'll still write it the same way.
OK, but words are not only for compiler-writers. As someone who encounters your compiler, if it targets an output language at a similar level as the input language it will give me a headstart in understanding what it does if I see it referred to as a transpiler rather than simply a compiler.
Overall, I find this discussion very odd. It seems like a kind of deletionism for the dictionary. I mean, what's the use of the word 'crimson'? Anything that's crimson is also just 'red'. Why keep 'large' when we have 'big'? You could delete a large percentage of English words by following this line of thinking.
It gives you a better idea what a thing does?
To me, it doesn't. If someone says "tsc is a transpiler", it gives me nothing actionable. If you do say "it transpiles to JS", then I've got something, but that could just be "compiles to JS". It doesn't really tell me how the thing is constructed either.
Whenever someone argues the uselessness or redundancy of a particular word, a helpful framework to understand their perspective is "Lumpers vs Splitters" : https://en.wikipedia.org/wiki/Lumpers_and_splitters
An extreme caricature example of a "lumper" would just use the word "computer" to label all Turing Complete devices with logic gates. In that mindset, having a bunch of different words like "mainframe", "pc", "smartphone", "game console", "FPGA", etc are all redundant because they're all "computers" which makes the various other words pointless.
On the other hand, the Splitters focus on the differences and I previously commented why "transpiler" keeps being used even though it's "redundant" for the Lumpers : https://news.ycombinator.com/item?id=28602355
We're all Lumpers vs Splitters to different degrees for different topics. A casual music listener who thinks of orchestral music as background sounds for the elevator would be "lump" both Mozart and Bach together as "classical music". But an enthusiast would get irritated and argue "Bach is not classical music, it's Baroque music. Mozart is classical music."
The latest example of this I saw was someone complaining about the word "embedding" used in LLMs. They were asking ... if an embedding is a vector, why didn't they just re-use the word "vector"?!? Why is there an extra different word?!? Lumpers-vs-splitters.
I'm not convinced your L/S dichotomy applies. The concern there is that the natural world (or some objective target domain) has natural joints, and the job of the scientist (, philosopher, et al.) is to uncover those joints. You want to keep 'hair splitting' until the finest bones of reality are clear, then grouping hairs up into lumps, so their joints and connections are clear. The debate is whether the present categorisation objectively under/over-generates , and whether there is a factor of the matter. If it over-includes, then real structure is missing.
In the case of embeddings vs. vectors, classical vs., baroque, transpiler vs., compiler -- i think the apparent 'lumper' is just a person ignorant of classification scheme offered, or at least, ignorant of what property it purports to capture.
In each case there is a real objective distinction beneath the broader category that one offers in reply, and that settles the matter. There is no debate: a transpiler is a specific kind of compiler; an embedding vector is a specific kinds of vector; and so on.
There is nothing at stake here as far as whether the categorisation is tracking objective structure. There is only ignorance on the part of the lumper: the ignorant will, of course, always adopt more general categories ("thing" in the most zero-knowledge case).
A real splitter/lumper debate would be something like: how do we classify all possible programs which have programs as their input and output? Then a brainstorm which does not include present joint-carving terms, eg., transformers = whole class, transformer-sourcers = whole class on source code, ...
Ahh, so you're a meta-splitter.
https://xkcd.com/2518/
> I'm not convinced your L/S dichotomy applies.
Proceeds to urm actually split.
All ontologies are false. But some are useful.
It's all about context, isn't it? "Humans vs. animals" is an important distinction to make in some contexts and useless in others. Insisting on the fact that humans are also animals if we're talking about, say, "language in humans vs. animals" is unproductive. It just makes discussions harder by forcing everyone to add "_non-human_ animals" to every mention. But if we're talking about, say, cellular biology, it's unproductive to force everyone to write "human and animal cells" instead of just "animal cells".
Similarly, distinguishing between transpilers and compilers might be important in some contexts and useless in others. Transpilers are source-to-source compilers, a subset of compilers. Whether it matters depends on the context.
> An extreme caricature example of a "lumper" would just use the word "computer" to label all Turing Complete devices with logic gates.
I don't think that's a caricature at all; I've often seen people argue that it should include things like Vannevar Bush's differential analyzer, basically because historically it did, even though such devices are neither Turing-complete nor contain logic gates.
'computer' is an ambiguous word. In a mathematical sense a computational process is just any which can be described as a function from the naturals to naturals. Ie., any discrete function. This includes a vast array of processes.
A programmable computer is a physical device which has input states which can be deterministicaly set, and reliably produce output states.
A digital computer is one whose state transition is discrete. An analogue computer has continuous state transition -- but still, necessarily, discrete states (by def of computer).
An electronic digital programmable computer is an electric computer whose voltage transitions count as states discretely (ie., 0/1 V cutoffs, etc.); its programmable because we can set those states causally and deterministically; and its output state arises causally and deterministically from its input state.
In any given context these 'hidden adjectives' will be inlined. The 'inlining' of these adjectives causes an apparent gatekeepery Lumpy/Splitter debate -- but it isnt a real one. Its just ignorance about the objective structure of the domain, and so a mistaken understanding about what adjectives/properties are being inlined.
In fact ‘computer’ used to be a job description: a person who computes.
Yes, definitely. And "nice" used to mean "insignificant". But they don't have those meanings now.
Most functions from the naturals to naturals are uncomputable, which I would think calls into question your first definition.
It's unfortunate that "computer" is the word we ended up with for these things.
Ah well, that's true -- so we can be more specific: discrete, discrete computable, and so on.
But to the overall point, this kind of reply is exactly why I don't think this is a case of L vs. S -- your reply just forces a concession to my definition, because I am just wrong about the property I was purporting to capture.
With all the right joint-carving properties to hand, there is a very clear matrix and hierarchy of definitions:
abstract mathematical hierarchy vs., physical hierarchy
With the physical serving as implementations of partial elements of the mathematical.
Word definitions are arbitrary social constructs, so they can't really be correct or incorrect, just popular or unpopular. Your suggested definitions do not reflect current popular usage of the word "computer" anywhere I'm familiar with, which is roughly "Turing-complete digital device that isn't a cellphone, tablet, video game console, or pocket calculator". This is a definition with major ontological problems, including things such as automotive engine control units, UNIVAC 1, the Cray-1, a Commodore PET, and my laptop, which have nothing in common that they don't also share with my cellphone or an Xbox. Nevertheless, that seems to be the common usage.
> Word definitions are arbitrary social constructs, so they can't really be correct or incorrect, just popular or unpopular.
If you mean that classifications are a matter of convention and utility, then that can be the case, but it isn’t always and can’t be entirely. Classifications of utility presuppose objective features and thus the possibility of classification. How else could something be said to be useful?
Where paradigmatic artifacts are concerned, we are dealing with classifications that join human use with objective features. A computer understood as a physical device used for the purpose of computing presupposes a human use of that physical thing “computer-wise”, that is to say objectively, no physical device per se is a computer, because nothing inherent in the thing is computing (what Searle called “observer relative“). But the physical machine is objectively something which is to say ultimately a collection of physical elements of certain kinds operating on one another in a manner that affords a computational use.
We may compare paradigmatic artifacts with natural kinds, which do have an objective identity. For instance, human beings may be classified according to an ontological genus and an ontological specific difference such as “rational animal“.
Now, we may dispute certain definitions, but the point is that if reality is intelligible–something presupposed by science and by our discussion here at the risk of otherwise falling into incoherence–that means concepts reflect reality, and since concepts are general, we already have the basis for classification.
No, I don't mean that classifications are a matter of convention and utility, just word definitions. I think that some classifications can be better or worse, precisely because concepts can reflect reality well or poorly. That's why I said that the currently popular definition of "computer" has ontological problems.
I'm not sure that your definition helps capture what people mean by "computer" or helps us approach a more ontologically coherent definition either. If, by words like "computing" and "computation", you mean things like "what computers do", it's almost entirely circular, except for your introduction of observer-relativity. (Which is an interesting question of its own—perhaps the turbulence at the base of Niagara Falls this morning could be correctly interpreted as finding a proof of the Riemann Hypothesis, if we knew what features to pay attention to.)
But, if you mean things like "numerical calculation", most of the time that people are using computers, they are not using them for numerical calculation or anything similar; they are using them to store, retrieve, transmit, and search data, and if anything the programmers think of as numerical is happening at all, it's entirely subordinate to that higher purpose, things like array indexing. (Which is again observer-relative—you can think of array indexing as integer arithmetic mod 2⁶⁴, but you can also model it purely in terms of propositional logic.)
And I think that's one of the biggest pitfalls in the "computer" terminology: it puts the focus on relatively minor applications like accounting, 3-D rendering, and LLM inference, rather than on either the machine's Protean or universal nature or the purposes to which it is normally put. (This is a separate pitfall from random and arbitrary exclusions like cellphones and game consoles.)
That's very interesting!
Splitters make more sense to me since different things should be categorized differently.
However, I believe a major problem in modern computing is when the splitter becomes an "abstraction-splitter."
For example, take the mouse. The mouse is used to control the mouse cursor, and that's very easy to understand. But we also have other devices that can control the mouse cursor, such as the stylus and touchscreen devices.
A lumper would just say that all these types of devices are "mouses" since they behave the same way mouses do, while a splitter would come up with some stupid term like "pointing devices" and then further split it into "precise pointing devices" and "coarse pointing devices" ensuring that nobody has absolutely no idea what they are talking about.
As modern hardware and software keeps getting built on piles and piles of abstractions, I feel this problem keeps getting worse.
I don't understand what the issue is: a transpiler is a compiler that outputs in a language that human programmers use.
It's good to be aware of that from an engineering standpoint, because the host language will have significantly different limitations, interoperability and ecosystem, compared to regular binary or some VM byte-code.
Also, I believe that they are meaningfully different in terms of compiler architecture. Outputting an assembly-like is quite different from generating an AST of a high-level programming language. Yes of course it's fuzzy because some compilers use intermediate representations that in some cases are fairly high-level, but still they are not meant for human use and there are many practical differences.
It's a clearly delineated concept, why not have a word for it.
GCC outputs textual GNU assembly language, in which I have written, for example, a web server, a Tetris game, a Forth interpreter, and an interpreter for an object-oriented language with pattern-matching. Perhaps you are under the illusion that I am not a human programmer because this is some kind of superhuman feat, but to me it seems easier than programming in high-level languages. It just takes longer. I think that's a common experience.
Historically speaking, almost all video games and operating systems were written in assembly languages similar to this until the 80s.
https://news.ycombinator.com/item?id=45912557
Thank you for the link; I've responded comprehensively at https://news.ycombinator.com/item?id=45914592.
You’re being \__
Transpilers are compilers that translate from one programming language to the other. I am not 100% sure where these "lies" come from, but it's literally in the name, it's clearly a portmanteau of translating compiler... Where exactly are people thinking the "-piler" suffix comes from?
Yes, I know. You could argue that a C compiler is a transpiler, because assembly language is generally considered a programming language. If this is you, you have discovered that there are sometimes concepts that are not easy to rigorously define but are easy for people to understand. This is not a rare phenomenon. For me, the difference is that a transpiler is intending to target a programming language that will be later compiled by another compiler, and not just an assembler. But, it is ultimately true that this definition is still likely not 100% rigorous, nor is it likely going to have 100% consensus. Yet, people somehow know a transpiler when they see one. The word will continue to be used because it ultimately serves a useful purpose in communication.
One distinction is that compilers generally translate from a higher-level language to a lower-level language whereas Transpilers target two languages which are very close in the abstraction level. For example a program that translated x86 assembly to RISC-V assembly would be considered a transpiler.
The article we are discussing has "Transpilers Target the Same Level of Abstraction" as "Lie #3", and it clearly explains why that is not true of the programs most commonly described as "transpilers". (Also, I've never heard anyone call a cross-assembler a "transpiler".)
On the contrary: it reifies people's prejudices and prevents them from seeing reality, often in the service of intentional deception, which for my purposes is the opposite of a useful purpose in communication.
There's currently a fad in my country for selling "micellar water" for personal skin cleansing, touted as an innovation. But "micelles" are just the structure that any surfactant forms in water, such as soap, dish detergent, or shampoo, once a certain critical concentration is reached, so "micellar water" is just water with detergent in it. People believe they are buying a new product because it's named with words that they don't know, but they are being intentionally deceived.
Similarly, health food stores are selling "collagen supplements" for US$300 per kilogram to prevent your skin from aging. These generally consist of collagen hydrolysate. The more common name for collagen hydrolysate is "gelatin". Food-grade gelatin sells for US$15 per kilogram. (There is some evidence that it works, but it's far from overwhelming, but what I'm focusing on here is the terminology.) People believe they are buying a special new health supplement because they don't know what gelatin is, but they are being intentionally deceived.
You might argue, "People somehow know micellar water when they see it," or, "People somehow know collagen supplements when they see them," but in fact they don't; they are merely repeating what it says on the jar because they don't know any better. They are imagining a distinction that doesn't exist in the real world, and that delusion makes them vulnerable to deception.
Precisely the same is true of "transpilers". The term is commonly used to mislead people into believing that a certain piece of software is not a compiler, so that knowledge about compilers does not apply to it.
> The term is commonly used to mislead people into believing that a certain piece of software is not a compiler, so that knowledge about compilers does not apply to it.
Why would people use a word that has the word "compiler" in it to try to trick people into thinking something is not a compiler? I'm filing this into "issues not caused by the thing that is being complained about".
IMO: Transpilers are compilers, but not all compilers are transpilers.
In my book, transpilers are compilers that consume a programming language and target human-readable code, to be consumed by another compiler or interpreter (either by itself, or to be integrated in other projects).
i.e. the TypeScript compiler is a transpiler from TS to JS, the Nim compiler is a transpiler from Nim to C, and so on.
I guess if you really want to be pedantic, one can argue (with the above definition) that `clang -S` might be seen as a transpiler from C to ASM, but at that point, do words mean anything to you?
For me, the "human-readable" part is key. It's not just that the output is e.g. javascript, but that it is more or less human-readable with about the same organization as the original code.
If you implement SKI combinators, or three-address instructions, as functions in javascript, and that's the output of your compiler, I would not call that a transpiler.
Exactly. For a web dev oriented example, I would call coffeescript a transpiler, since it would transform
into clearly intending the output code to be quite readable (even preserving comments).Whereas Elm is a compiler since it transforms
into Clearly not intended for (easy) human consumption.I can usually read JS generated by TS, but calling the C Nim outputs "human-readable" is very generous considering it flattens most structured control flow to goto. (It's hard to do it otherwise, Nim has to deal with exceptions and destructors but C has neither.)
Classifying Nim as a transpiler also results in weird cases like NLVM[1] which most would consider a compiler even though it is a back-end on the same "level" as Nim's C generator.
[1]: https://github.com/arnetheduck/nlvm
I'd probably say that "transpiler" is not a very useful word with that definition.
Why is it useless? 'Compiler' denotes the general category, within which exist various sub-categories:
For example, a 'native compiler' outputs machine code for the host system, a 'cross compiler' outputs machine code for a different system, a 'bytecode compiler' outputs a custom binary format (e.g. VM instructions), and a 'transpiler' outputs source code. These distinctions are meaningful.
I can’t see why — I do think that the word does convey some sort of useful meaning with the above definition.
I think the distinction is meaningful - for example many compilers used to have C backends (GCC for example did) - so you code went through almost the entire compiler pipeline - from frontend to IR to backend where the backend did almost everything a compiler does, it only skipped target machine specific stuff like register allocation (possibly even that was done), arch specific optimizations and assembly generation.
A transpiler to me focuses on having to change or understand the code as little as possible - perhaps it can operate on the syntax level without having to understand scopes, variable types, the workings of the language. It does AST->AST transforms (or something even less sophisticated, like string manipulation).
In my mind, you could have a C++ to C transpiler (which removes C++ constructs and turns them into C ones, although C++ is impossible to compile without a rich understanding of the code), and you could have a C++ to C compiler, which would be a fully featured compiler, architected in the way I described in the start of the post, and these would be two entirely different pieces of software.
So I'd say the term is meaningful, even if not strictly well defined.
> Lie #3: Transpilers Target the Same Level of Abstraction
> This is pretty much the same as (2). The input and output languages have the syntax of JavaScript but the fact that compiling one feature requires a whole program transformation gives away the fact that these are not the same language
It is not really the same as (2), you can't cherry pick the example of Babel and generalise it to every transpiler ever. There are several transpilers which transpile from one high-level language to another high-level language such as kotlin to swift. i.e; targeting the same level of abstraction.
Wonder what this person would say about macro expansions in scheme, maybe that should also be considered a compiler as per their definition.
BabelJS is the central example of "transpilers"; if BabelJS lacks some purported defining attribute of "transpilers", that definition is unsalvageable, even if there are other programs commonly called "transpilers" that do have that attribute.
> Compilers already do things that “transpilers” are supposed to do. And they do it better because they are built on the foundation of language semantics instead of syntactic manipulation.
So you do know the difference.
The link to Lindsey Kuper's post https://decomposition.al/blog/2017/07/30/what-do-people-mean... is great!
I think the note about generators may be a good definition for when one language is "more powerful" than another; at least it's a good heuristic:
> The input and output languages have the syntax of JavaScript but the fact that compiling one feature [generators] requires a whole program transformation gives away the fact that these are not the same language. If we’re to get beyond the vagaries of syntax and actually talk about what the expressive power of languages is, we need to talk about semantics.
If a given program change is local in language X but global in language Y, that is a way in which language X has more expressive power.
This is kind of fuzzy because you can virtually always avoid this by implementing an interpreter, or its moral equivalent, for language X in language Y, and writing your system in that DSL (embedded or otherwise), rather than directly in language Y. Then, that anything that would be a local change in language X is still a local change. But this sort of requires knowing ahead of time that you're going to want to make that kind of change.
Sadly https://people.csail.mit.edu/files/pubs/stopify-pldi18.pdf is 403. But possibly https://people.csail.mit.edu/rachit/files/pubs/stopify-pldi1... is the right link.
Thanks for the last link! At first read, the regeneration code is nuts: using a switch to assign a value, then comparing hard coded values. I only used generator functions in TS after they were supported in JS, so I’m going to step through that, just to understand it more.
Yeah, I mean, you either kind of have to do something like protothreads, or break apart the function into fragments at the yield points, converting it to explicit continuation-passing style.
Meaningless word + list of "lies"... Nice read anyways.
"BabelJS is arguably one of the first “transpilers” that was developed so that people could experiment with JavaScript’s new language features that did not yet have browser implementations"
Just my two cents. Haxe was created long time ago, and BabelJS is arguably not one of the first "transpilers" people can play with.
[1] https://en.wikipedia.org/wiki/Haxe
[2] https://haxe.org
I am not fond of the word either, but only because the use has often been used as a diminutive.
When used, it has often been implied that a compiler that outputs to a human-readable programming language wouldn't be a "real compiler".
Still far better than "Serverless".
I don't really understand the reasoning in the article. Nobody argues that orange is a meaningless word just because it's not wrong to call an orange a fruit.
Sure, a transpiler is a specialized form of compiler. However that doesn't mean it's not much clearer to describe a transpiler using the more specific name. As such recommending someone replace "compiler" with "transpiler" (when appropriate) does not mean using compiler is wrong. It simply means that, outside of some very niche-interest poetry, using transpiler is better!
"Programming languages are not just syntax; they have semantics too. Pretending that you can get away with just manipulating the former is delusional and results in bad tools."
So eloquently put, what starts off as just simple syntactic conversion usually snowballs into semantics very quickly.
It would be good if we had a term that didn't confuse linking with translation. In English compiling means joining together many parts, after all.
That one is historically interesting.
I suspect the first compilers were named that because they were making compilations of assembly routines, probably slightly modified/specialised to the rest of the routines.
Compilers still do that. Some of the input is your source, but there's also "the compiler runtime" which is essentially a lot of extra routines that get spliced in, and probably "the language runtime" which gets similar treatment.
So compilers are still joining together parts, we've just mostly forgotten what crt or udiv.s are.
Linking and loading are more dubious names, but also they refer to specialised compilers that don't need to exist and probably shouldn't any more, so that may resolve itself over time.
The first compilers were called "translators". The first linker/loader (kinda, A-0 was a... strange tool, by modern standards) was actually called "compiler", precisely because of the generic meaning of the word "compile".
Today's meaningless word: Cloud
Language interoperability is a material question. Outputting Javascript, Python, C++ vs assembler/machine code have very different implications for calls to/from other languages
Is JIT also meaningless?
But ultimately if you don’t want to use a word, don’t use it. Not wanting to hear a word says more about the listener than the speaker
"Transpiler" is no less well-defined a term than "compiler".
The definition of compiler i learned was “takes some code, translate it to semantically equivalent code in a different language (which might be machine language, bytecode…)”. This is also used in PLaI, a respected learning resource: https://www.plai.org/
I think this is a pretty acceptable definition, and yes, it does make the term transpiler a little useless.
What I would add to your definition, to make a distinction from the common usage of compilation, is that the target language is on an approximately equivalent level of abstraction to the source. So, for example, Rust -> machine code is not transpilation, but Rust -> C++ is.
I think this is how the word is commonly understood, and it’s not useless (even if there’s no absolute standard of when it does or does not apply).
Edit: sorry, realise I should have read the article before commenting. The article calls out my definition as one of their ‘lies’. I guess I just disagree with the article. Words can be useful even without a 100% watertight definition. They’re for communication as well as classification.
One of the problems is that you might not use the target language at the equivalent level of abstraction. For example, C is a popular target language, but the C emitted may be very unidiomatic and nothing like human consumable code, it's not all that unusual that a language compiles all code to one big C function where the function calls in the language are jumps, which is a way to get around the limitations of the C calling conventions and stack.
The same thing applies to compilation to Javascript, the resulting code may use a tiny subset of the language.
I don't like the word transpiler, because there is nothing useful about the distinction (unless you count people using it to denigrate compilers that doesn't target traditional machine code).
I could see the case of using it as a name when the transformation is reversible, like you could probably turn Javascript back into Coffeescript.
What value does the word have? When I'm writing a compiler, it doesn't matter whether I target C or asm, or Javascript, as my output language. I'll still write it the same way.
OK, but words are not only for compiler-writers. As someone who encounters your compiler, if it targets an output language at a similar level as the input language it will give me a headstart in understanding what it does if I see it referred to as a transpiler rather than simply a compiler.
Overall, I find this discussion very odd. It seems like a kind of deletionism for the dictionary. I mean, what's the use of the word 'crimson'? Anything that's crimson is also just 'red'. Why keep 'large' when we have 'big'? You could delete a large percentage of English words by following this line of thinking.
It gives you a better idea what a thing does?
To me, it doesn't. If someone says "tsc is a transpiler", it gives me nothing actionable. If you do say "it transpiles to JS", then I've got something, but that could just be "compiles to JS". It doesn't really tell me how the thing is constructed either.