The amount of perl (5) that relies on 'eval', and invoking the interpreter and compiler at runtime (in various degrees), is . . . . massive.
To claim that switching to a "traditional" compiled language would resolve those issues in the language that is perhaps the most comfortable with lapsing into "well, I can't metaprogram it, so just take this string/block/function-like of code and interpret/run it, tell me if it works, and give me the result" is hubristic to say the least.
None of that should be taken as condemning that tendency in Perl. I think that its tight interpreter/runtime coupling and feedback loop is what makes it uniquely powerful in many cases.
Yeah but then how do you achieve what perl 11 sets out to be then?
I'm not really trying to push this perl->rust transpilation idea (it was just a silly thought, people seem to have taken is very very seriously), but maybe v0.1 can just not support eval, and then see where they go from there?
Either way it seems like perl 11 is going to have to solve this issue of whether or not they have to bring interpreter & runtime with them as well if they want to support C/C++ speed and `eval`.
eval is not evil per se. eval is mostly a necessary feature to do macros, i.e. compile-time evaluation in proper syntax. (called BEGIN blocks in perl). The only problem with eval is it's internal slow implementation, compared to a proper language. Two big stacks of structs (~10 words) on the heap, compared to one word on the stack. longjmp for exceptions. For perl being a 20x slower scripting language it's fine though.
rust on the other hand is an even more hype driven language than perl6. Their documentation is full of hype and lies. perl6 is at least honest about its limitations, but rust is hyping about its safeties and performance while there's none. rust has no type safety (unsafe keyword), memory safety (refcounting. only stack or external heap allocations, both are unsafe) and fearless concurrency safety (requiring manual locks. dangerous and unsafe). perl6 is much safer than this, and parrot had even proper lockless concurrency and safety. rust is a nice language, I use it also, but never trust liars and hype-driven development.
For proper performance and safeties use pony. ATS is also fine, and there some new parallel languages cropping up. For slow and safety alone there are also many nice copying languages around, like Go, Erlang, Scala, Akka or Lisp.
c/c++ speed is an explicit non-goal for perl 11. We have no chance to catch up to javascript, only to php7. But even this is not easy because the perl5 API is as fucked up as the ruby and python API, exposing its bloated inner structs instead of functions only. You only get proper performance by optimizing those fat structs to single words, "unboxing" data, slimming down the code and runloop. With an exposed API like that based on structs you are doomed to be 10x slower.
Additionally there are so many exposed globals in the API, that proper threading is almost impossible.
gperl has no eval and was about 200x faster. The goal of gperl was to add proper eval but it's not easy, and he already went away from perl5 to go and java, as most asians did recently. There's spvm though, a new asian perl5 attempt to create a proper VM.
The goal of perl11 is simply to add most perl6 features to the perl5 codebase without breaking backcompat. This is what perl5 should have done, but refused to do and is not able to do.
One beast will rise from the desert, the other from the sea. When they meet, they will fuse to form the prophesied CamelCrab, and you will know the end is nigh.
Could you though? I mean the semantics are so different that the code you generate is probably going to need to be the equivalent of Perl's VM at that point anyway.
I think you could -- you'd have to just translate all those semantics down to rust as well. I can't think of any perl semantics/sugar that can't be compiled out. Even the famous default variable ($_) could be naively transpiled out with just a variable binding.
Also, if I'm understanding the original post right, they want the VM itself to be swappable -- that with the desire to reach C speed makes me think that they want to make it optional all-together.
Your reasoning is kind of like saying we only need a 6502 and a large bank of ram because, hey, that is turing equivalent, and a modern x86 with the same amount of ram is turing equivalent, so it should be complete.
Imagine a perl program which asks the user for input. Based on the user's input, the perl program does "do a.pl" or "do b.pl". Hell, maybe the user's input is actually executable code that is thrown in the mix too.
Then the original program does "print $a + $b;". What should the rust transpiler do? Are they floats? Are they ints? Or strings? Do they have values already?
Yes, you could create a transpiled version that used hashes to look up symbols, and based on what the hash returned it would execute code to add two (boxed) ints, or floats, or float and int, or throw an error, but then what you've done is rewritten the perl interpreter in rust.
> Your reasoning is kind of like saying we only need a 6502 and a large bank of ram because, hey, that is turing equivalent, and a modern x86 with the same amount of ram is turing equivalent, so it should be complete.
Yes, this is literally the case, I didn't say it would be easy or that it should be done. Maybe I should have been more clear, but it was just a silly joke, lighten up.
Also, analogging perl and c/c++ style languages to the modern x86 and 6502 is a bit hyperbolic.
If I'm understanding your point correctly, you're saying that dynamic interpretation (via code loading or `eval`) is an important perl feature you want to retain. In a world in which someone was crazy enough to write a perl->rust transpiler, they could just not support eval for v0.1, and figure out how they want to deal with it in the future. One option is to compile in a runtime + interpreter that could be used if the code being built uses eval.
Any other difficulties you can forsee? or areas where there's a 6502-x86 style feature disparity?
That doesn't make sense, the cost incurred by dynamic languages is not just due to the interpreter (otherwise that would be easy to solve with a JIT or, as you point out, static compilation). Rather the problem is that since these languages are by nature dynamic you can't make many of the assumptions that you do it static languages. You can not know what a value passed as parameter is going to hold until the function is actually called, you cannot inline method calls because they could be redefined dynamically etc...
For this reason JIT actually makes more sense that static compilation since at least then you'll potentially be able to use dynamic runtime information to better optimize the code.
perl6, cperl, rperl are all gradually typed, and if so compile to native unboxed ints and floats. If untyped the cperl jit will observe run-time types and switch to the unboxed variant or the whole basic block then, if profitable. moar (perl6) ditto.
Same with the object system. A native class has the same layout as a C struct. No costly refcounting and indirections, just a word with the data or pointer. Single op assignments, reads and stores. Easy to ffi back and forth. Fast objects.
You can inline method calls on the tracing jit when it's called often enough with the right types. Static methods can be inlined at compile-time already, but that's not merged yet. A few bits are still missing in the inliner.
The static compiler benefits greatly from types also, but the type inference is not that bad also, just a bit unstable (B::CC). Many modules cannot be compiled statically with this optimizing compiler yet. The normal static compiler (B::C) is stable though and used in production for decades. cperl just adds many memory optimization for that use case.
If you properly type your sigs and vars, the static compiler will fly. If not, the jit has more work to do. The biggest problem is only the non-cooperation from p5p. They explicitly disabled types in sigs (~4 lines of code) in their part, so nobody can use it because it breaks code. python, ruby, java went with annotations as comment. But this is lame. perl5 had the chance to do it properly when they introduced sigs (using the perl6 syntax or the syntax from its cpan modules) but blew it on purpose.
True -- I thought rust just because it's what I write in lately (and some of it's benefits over raw C) but this would be equally true, C/C++ would make just as much sense.
BTW over in the land of things-that-maybe-shouldn't-be-things:
RPerl is a Perl 5 transpiler. We started with a low-magic subset of Perl 5, and are now slowly moving into the medium-magic parts of Perl 5 like regular expressions and Moo(se) and databases etc.
See B::C and B::CC, the compilers to static C. Also called the perl-compiler.
B::C just jumps into the libperl run-time, but B::CC even tries to optimize away many slow run-time functions, because it knows much more about the code and data.
perlcc compiles your perl code into native code and runs it. It's very stable, because I'm maintaining it, and it's used in production.