Is Nim a Transpiler?
peterme.net
peterme.net
Is the level same-level-of-abstraction really part of the usual meaning of the term?
Here's a blog post by Lindsey Kuper that finds around 5 meanings, with only one of them (and being an unsourced Wikipedia article to boot) converging to the same idea about abstraction leve: http://composition.al/blog/2017/07/30/what-do-people-mean-wh...
No. That's just a definition by the author. The languages might operate on the same or close level of abstraction, but that doesn't mean that all logical constructs of the source and the transpiled target have to map. Especially the authors conclusion that a "transpilation is therefore a two-way process where you could go back and forth between languages" is not a necessary feature of a transpiler.
But now your “definition” of a transpiler depends on a subjective measure of “sameness”.
For instance, you called Python and Java the same level of abstraction, but in Java a lot of concern is devoted to properly typing numbers, whereas in Python this concern is ignored. If I really didn’t have to worry about the underlying hardware architecture, I would never care about the difference between a 16 bit and 32 bit number. Why aren’t 17 bit numbers a default type in Java? Why are there different sizes at all? Why can’t I just make everything infinity bits so I don’t have to worry about overflows? The answer to these questions have more to do with computer architecture than with Java.
And Java is even worse because now there are two machines: the hardware one and the virtual one, which is hard to always ignore. For some applications you can ignore the GC entirely, for others ignoring the GC will lead to catastrophic failure!
So is Java higher or lower or the same as Python? Depending on the axis measured, probably all three!
This is why people say it’s not so cut and dry. Any time someone puts down a sharp line, it’s easy to blur it. Which usually indicates there is no line at all.
What really comes through is that the author seems to think that transpiler status is somehow lesser, and the whole nitpicking about compilers/transpilers is just an attempt to make sure Nim lands squarely on the compiler side.
Maybe the conclusion that should be reached is the one the author is hinting towards at the end - which is that transpiler and compiler don't really have a strong distinction, and their usage is muddied enough that saying whether something is "actually" a transpiler or a compiler is mostly pointless. (And then there would be less worry that people "mistakenly" call Nim a transpiler, eh?)
The conclusion is definitely that these are loose terms that can apply to many different things. But some of the usages are more useful as differentiating terms than others. The very broad definitions of transpilers ends up making most if not all compilers into transpilers which isn't terribly useful, and the in-between ones I've found are so under-defined that the term ends up not meaning anything at all. This was merely my attempt at reaching a definition of transpiler that is not only a useful distinction from a compiler, but also serves as a more concrete term.
Also „machine code“ is not even the last step anymore, it gets further cached, interpreted compiled to instructions by the hardware. It’s abstraction layers all the way down.
For a transpiler, you generally need a tokenizer, then a parser to parse the token stream into an AST, which you will then have some set of transformation steps, often transforming into other ASTs for optimization steps or incremental transforms to the final target, before you take the final AST and serialize it out into the target.
Wherease for a compiler, you generally need a tokenizer, then a parser to parse the token stream into an AST, which you will then have some set of transformation steps, often transforming into other ASTs for optimization steps or incremental transforms to the final target, before you take the final AST and serialize it out into the target.
If I was hiring for a compiler position and someone showed up with 10 years of transpiler authorship on their resume, I wouldn't even look at them. Such divergent experience would be useless. It would be like hiring someone for a Javascript backend position when all they had was 10 years of intensive Javascript frontend experience. Madness. You'll go out of business making stupid hiring decisions like that.
I think you'll spend more time and effort hiring than you would've spent training.
I think, the background was the word transpiler was used by compiler creators as a way of gatekeeping.
Why do you think that?
I dunno anyone who makes compilers who would draw this distinction (I know a lot of people who make compilers). I think it's more used by language warriors who don't understand there really isn't a distinction.
(The usual term of disparagement in this context is "preprocessor"!)
Babel can be used as a macro system for JS, and macros are compilers.
You choose whether you want to emit C, C++, or JS. There's an experimental, fledgling community LLVM frontend for Nim, that is what I would call a "compiler":
https://github.com/arnetheduck/nlvm
What Jetbrains calls Kotlin -> JavaScript, is "transpilation"
What Google calls Java -> JavaScript in j2cl, is "transpilation"
But this is all pedantic IMO.
Very nice. Last time I experimented with Nim the lack of this was the single biggest dealbreaker.
> nlvm does not:
- understand C - as a consequence, header, emit and similar pragmas will not work - neither will the fancy importcpp/C++ features
- support all nim compiler flags and features - do file bugs for anything useful that's missing
One of the unique and best things about Nim (IMO) beyond being multi-target, is that you can do things like say "emit this exact C/C++ string", or "import this type from an existing header".With this LLVM backend, that doesn't work, and it doesn't support JS (which probably isn't a big deal to most people).
That means you can't do stuff like this:
type
VectorIterator {.importcpp: "std::vector<'0>::iterator".} [T] = object
# std::vector<int>::iterator x;
var x: VectorIterator[cint]
https://nim-lang.org/docs/manual.html#implementation-specifi...https://nim-lang.org/docs/manual.html#foreign-function-inter...
https://nim-lang.org/docs/manual.html#implementation-specifi...
It could definitely be better, and hopefully some day it will be, but I use Nim in a debugger quite frequently and it usually works out pretty well.
To me, if the thing that gets emitted is another regular programming language, you've done transpilation.
If the thing that gets emitted is IR, bytecode, object code, essentially anything that's not something you would read/write yourself and is a step further towards being executable, it's "compilation".
I see transpilation as lateral/horizontal movement on the "path to being able to run it" chain, and compilation as vertical movement towards the executable end-goal.
But, again -- "pedantic", and just my $0.02.
But since it also has native backends and C is its only other high level language, would you still consider it a compiler since you specifically mentioned "several other languages"?
I think it's kind of fun to look at this philosophically, since these are broad terms without perfect definitions.
MLton takes in the entire program source, including the standard library, at once. Because of that, there's a ton of information we know, which helps a ton for things like dead code elimination. Because of this, there's a lot of memory required, since we have the entire program's syntax/parse/any other type of tree in memory, and it's not going to be as fast as something like GCC since we're recompiling everything every time in MLton instead of only recompiling the changed modules.
Despite MLton being a bit slower to compile, it's truly an incredible compiler. I had Dr Fluet, the lead maintainer, as my compiler professor in college, and he's a wealth of knowledge. The compiler we wrote in class was in SML and compiled with MLton. The amount of optimizations that occur is insane, it made damn fast executables, and that applies to most big compilers like GCC, Clang, Rustc, etc. The big difference in optimizations is how much information we have at optimization time. Languages like C are a bit looser and thus information may be harder to derive. Rust has a stricter set of rules, so we have more guarantees about a program to base our optimizations around.
So I'm out of my depth at this point, but this post from the SE Stack Exchange was interesting in that it highlights that those cross boundary optimizations can be handled at link time. I'm not sure how much is possible compared to MLton. MLton will have more access to type info, I'd assume, but maybe some metadata is stored in a .o file that I'm just not aware of.
I don't know much about this serious level of optimization, but I assume big C compilers get optimizations that are equally, if not more impressive and do just fine.
What about the new beta Kotlin/JS compiler that does Kotlin -> frontend IR -> backend IR -> JavaScript?
I guess... "Compilation of Kotlin, then emittance of JS"?
Because I believe this uses the shared "FIR" IR that the JVM/Native backends use right?
This is why the whole argument/topic is so subjective/pedantic haha.
The old Kotlin/JS compiler is definitely closer than the new one to what might be called transpiler.
[1] https://blog.jetbrains.com/kotlin/2021/10/the-road-to-the-k2...
Check this Pascal to D transcompilation talk in DConf 2019 [1]. It will be great if similarly R language can be transcompiled to D since the effort has been futile so far to write a better and modern compiler for R [2].
[1] DConf 2019 - Transcompilation into D:
http://dconf.org/2019/talks/veelo.html
[2] Why R? 2020 Keynote - Jan Vitek - How I Learned to Love Failing at Compiling R:
If your target is something like C/JS, your translation stage must be fully aware of the idiosyncrasies of the target language. If you are targeting machine code, you will have to include optimization and register allocation stages before generating machine code and the final executable/library.
Of course, this makes Java, and others, to not actually be compiled. That makes sense to me.
Nim, JavaScript and C are all high level languages. Do they gain something from being labeled as a compiler?
Also, I'd classify C as a more intermediate language, rather than a high level one. It doesn't hold your hand as much as things like Python. So technically high -> intermediate would be going down a level, I suppose.
It's really all just playing semantics. I wouldn't mind if they labeled themselves a compiler or a transpiler. Doesn't really matter to me.