10 ms·
Transpiler, a Meaningless Word (2023)
- Rochus 11mo ago"Transpiler" is no less well-defined a term than "compiler".
- nrinaudo 11mo agoThe 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/ https://www.plai.org/ I think this is a pretty acceptable definition, and yes, it does make the term transpiler a little useless.
- deleted 11mo ago[deleted]
- gmac 11mo agoWhat 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.
- writebetterc 11mo agoWhat 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.
- gmac 11mo agoIt gives you a better idea what a thing does?
- writebetterc 11mo agoTo 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.
- gmac 11mo agoOK, 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.
- kryptiskt 11mo agoOne 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.
- f38 11mo ago> 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.
- goranmoomin 11mo agoIMO: 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?
- writebetterc 11mo agoI'd probably say that "transpiler" is not a very useful word with that definition.
- cygx 11mo agoWhy 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.
- goranmoomin 11mo agoI can’t see why — I do think that the word does convey some sort of useful meaning with the above definition.
- deleted 11mo ago[deleted]
- ssrc 11mo agoFor 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.
- fulafel 11mo agoIt 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.
- JonChesterfield 11mo agoThat 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.
- Joker_vD 11mo agoThe 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".
- jasode 11mo agoWhenever 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 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 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.
- kragen 11mo ago> 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.
- mjburgess 11mo ago'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.
- jchw 11mo agoTranspilers 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.
- s20n 11mo agoOne 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.
- kragen 11mo agoThe 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".)
- jchw 11mo agoAbstraction layers are close to the truth, but I think it's just slightly off. It comes down to the fact that transpilers are considered source-to-source compilers, but one man's intermediate code is another man's source code. If you are logically considering neither the input and the output to be "source code", then you might not consider it to be a transpiler for the same reasons that an assembler is rarely called a compiler, even though assemblers can have compiler-like features: consider LLVM IR, for example. This is why a cross-assembler is not often referred to as a transpiler. Of course, terminology is often tricky: the term "recompiler" is often used for this sort of thing, even though neither the input nor the output is generally considered "source code", probably because they are designed to essentially construct a result as similar as possible to if you were able to recompile the source code for another target. This seems to contrast fairly well with "decompiler", as a recompiler may perform similar reconstructive analysis to a decompiler, but ultimately outputs more object code. Not that I am an authority on anything here, but I think these terms ultimately do make sense and reconcile with each-other. When people say "Same Level of Abstraction", I think what they are expressing is that they believe both of the programming languages for the input and output are of a similar level of expressiveness, though it isn't always exact, and the example of compiling down constructs like async/await shows how this isn't always cut-and-dry. It doesn't imply that source-to-source translations, though, are necessarily trivial, either: A transpiler that tries to compile Go code to Python would have to deal with non-trivial transformations even though Python is arguably a higher level of abstraction and expressiveness, not lower. The issue isn't necessarily the abstraction level or expressiveness, it's just an impedance mismatch between the source language and the destination language. It also doesn't mean that the resulting code is readable or not readable, only that the code isn't considered low level enough to be bytecode or "object code". You can easily see how there is some subjectivity here, but usually things fall far away enough from the gray area that there isn't much of a need to worry about this. If you can decompile Java bytecode and .NET IL back to nearly full-fidelity source code, does that call into question whether they're "compilers" or the bytecode is really object code? I think in those cases it gets close and more specific factors start to play into the semantics. To me this is nothing unusual with terminology and semantics, they often get a lot more detailed as you zoom in, which becomes necessary when you get close to boundaries. And that makes it easier to just apply a tautological definition in some cases: like for Java and .NET, we can say their bytecode is object code because that's what they're considered to be already, because that's what the developers consider them to be. Not as satisfying, but a useful shortcut: if we are already willing to accept this in other contexts, there's not necessarily a good reason to question it now. And to go full circle, most compilers are not considered transpilers, IMO, because their output is considered to be object code or intermediate code rather than source code. And again, the distinction is not exact, because the intermediate code is also turing complete, also has a human readable representation, and people can and do write code in assembly. But brainfuck is also turing complete, and that doesn't mean that brainfuck and C are similarly expressive.
- merlinthegreen 11mo agoI 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!
- oersted 11mo agoI 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.
- kragen 11mo agoGCC 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.
- NuclearPM 11mo agoYou’re being \__
- crazygringo 11mo agohttps://news.ycombinator.com/item?id=45912557 https://news.ycombinator.com/item?id=45912557
- kragen 11mo agoThank you for the link; I've responded comprehensively at https://news.ycombinator.com/item?id=45914592 https://news.ycombinator.com/item?id=45914592.
- Bengalilol 11mo agoMeaningless 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 https://en.wikipedia.org/wiki/Haxe [2] https://haxe.org https://haxe.org
- paulsutter 11mo agoLanguage 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
- torginus 11mo agoI 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.
- kragen 11mo agoThe link to Lindsey Kuper's post https://decomposition.al/blog/2017/07/30/what-do-people-mean-when-they-say-transpiler/ 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 https://people.csail.mit.edu/files/pubs/stopify-pldi18.pdf is 403. But possibly https://people.csail.mit.edu/rachit/files/pubs/stopify-pldi18.pdf https://people.csail.mit.edu/rachit/files/pubs/stopify-pldi1... is the right link.
- JoBrad 11mo agoThanks 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.
- kragen 11mo agoYeah, 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.
- nurettin 11mo agoToday's meaningless word: Cloud
- Findecanor 11mo agoI 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".
- theanonymousone 11mo agoStill far better than "Serverless".
- s20n 11mo ago> 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.
- kragen 11mo agoBabelJS 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.
- zk108 11mo ago"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.
- hn92726819 11mo ago> We can make it a bit more terse using list comprehensions: import functools as ft def fact(n): lst = range(1, n) return ft.reduce(lambda acc, x: acc*x, lst) Amusing that there's not a list comprehension in sight.
- adsharma 11mo agoWe need a new word for a universal transpiler. Something that can transpile to 7 or more languages. Poly-transpiler? It will also trigger more people.
- StopDisinfo910 11mo agoI think it's pretty clear to anyone with experience in the field that the notion of compilers, interpreters, transpilers are porous and even more so when you had the concept of VM ("Let's interpret a compiled artefact") and JIT ("I put a compiler in your interpreter. Don't worry, it all runs on the same VM in the end.") These things live on a continuum. Still, I think the different worlds are useful. They put forward different concepts and ideas. It helps framing things.
- SAI_Peregrinus 11mo agoA compiler takes in one language and outputs some other language. E.g. C to LLVM IR or LLVM IR to x86_64 assembly. An assembler is a type of compiler that takes in an assembly language and outputs machine code. A transpiler is a type of compiler that takes in a language commonly used by humans to directly write programs and outputs another language commonly used by humans to directly write programs. E.g. c2rust is a C to unsafe Rust compiler, and since both are human-used languages it's a transpiler. Assembly language isn't commonly written by humans though it used to be, so arguably compilers to assembly language are no longer transpilers even though they used to be. The existence of a transpiler implies a cispiler, a compiler that takes in code in one language and outputs code in that same language. Autoformatters are cispilers.
- mbo 11mo agoPartial evaluators would also be considered cispilers.
- tuveson 11mo agoI like the cover of the book Crafting Interpreters: https://craftinginterpreters.com/image/header.png https://craftinginterpreters.com/image/header.png It's basically a flowchart showing all of the different things that we mean when we say compiler/interpreter/transpiler, and which bits they have in common. Funny, but it has two paths for transpiler - the kind that parses and outputs source from an AST, and the asm.js kind, that actually just uses a high-level language as an assembly-ish target.
- vzaliva 11mo agoIn the academic programming languages research community, the term "transpiler" is barely used. For example, Google Scholar search for "transpiler" yields just 3200 results, compared to ~1.4M for "compiler".
- swatson741 11mo agoI think the term transpiler is ok. It’s not pedagogical or anything but most engineering jargon is like that, and this defiantly isn’t the worst one I’ve seen.
- carsonj 11mo agoI always understood transpilers to be defined by what they do, not how they work. Whether it's implemented as an AST transformation or something more complex would be irrelevant.
- jrm4 11mo agoThere are a whole lot of meaningless, or worse, misleading words in computing, and this isn't one of them. What it lacks in technical precision, it makes up for with that little bit of utility. It doesn't much confuse things. Off the top, lets compare that to "serverless."
- bitwize 11mo agoIt's like "sideload". It's a buzzword for something else, something more general, that applies in certain conditions.
- msla 11mo agoMy punt: Compilers and transpilers are both translators, and the only meaningful difference is whether the output is meant to be easily edited by a human, which is a spectrum more than a hard dividing line. The p2c Pascal to C translator [1] is pretty clearly a transpiler in that the C it outputs is pretty readable, the Stalin Scheme to C translator [2] is more clearly a compiler in that its output, even though it's C, is not human-readable unless you're a very dedicated type of person. [1] https://github.com/FranklinChen/p2c https://github.com/FranklinChen/p2c [2] https://en.wikipedia.org/wiki/Stalin_%28Scheme_implementation%29 https://en.wikipedia.org/wiki/Stalin_%28Scheme_implementatio... So, where does BabelJS sit? Somewhere in between, depending on what language features you used in the input code. Obviously generators require heavy transformations, but other features don't.
- wseqyrku 11mo agoCategory theory is on fire in this thread
- coldtea 11mo agoI find it a useful world to point to the distinction of converting code between two equally high level programming languages, vs between a higher level language to a low level representation (assembly, C, java bytecode, llvm ir, etc) target. "Compiler already covers that"? Yeah, and animal already covers cat, shall we drop the term cat too?