5

It would be nice if there existed a program that automatically transforms Perl code to Python code, making the resultant Python program as readable and maintainable as the original one, let alone working the same way.

The most obvious solution would just invoke perl via Python utils:

#!/usr/bin/python
os.exec("tail -n -2 "+__file__+" | perl -")
...the rest of file is the original perl program...

However, the resultant code is hardly a Python code, it's essentially a Perl code. The potential converter should convert Perl constructs and idioms to easy-to-read Python code, it should retain variable and subroutine names (i.e. the result should not look obfuscated) and should not shatter the wrokflow too much.

Such a conversion is obviously very hard. The hardness of the conversion depends on the number of Perl features and syntactical constructs, which do not have easy-to-read, unobfuscated Python equivalents. I believe that the large amount of such features renders such automatic conversion impossible practically (while theoretical possibility exists).

So, could you please name Perl idioms and syntax features that can't be expressed in Python as concise as in the original Perl code?

Edit: some people linked Python-to-Perl conventers and deduced, on this basis, that it should be easy to write Perl-to-Python as well. However, I'm sure that converting to Python is in greater demand; still this converter is not yet written--while the reverse has already been! Which only makes my confidence in impossibility of writing a good converter to Python more solid.

kirogasa
  • 627
  • 5
  • 19
P Shved
  • 96,026
  • 17
  • 121
  • 165
  • 26
    Get a Perl to Python converter. They also go by the name of programmers :) – Brian Rasmussen Aug 03 '10 at 18:53
  • This is a loaded question. Have you **proved** it is not possible? – John La Rooy Aug 03 '10 at 19:21
  • 1
    @gnibbler, we're trying to construct the proof on this page, right there, below. – P Shved Aug 03 '10 at 19:24
  • 4
    @Pavel Shved: It's not impossible. By definition. Both are "Turing Complete" languages. Translation is theoretically possible. The issues are complexity and practicality. – S.Lott Aug 03 '10 at 19:27
  • @Brian: and that kind of converter is so cool, it even runs on coffee and pizza :) – Ether Aug 03 '10 at 19:29
  • @Lott, I'm aware that it's theoretically possible; I even sketched a "solution" in the question. The gist is indeed complexity and practicality. Your answer is actually the kind I'm looking for: it contains Perl features that badly map on Python ones. – P Shved Aug 03 '10 at 19:34
  • @Pavel Shved: "And I am sure that it's impossible to write such a converter" "I'm aware that it's theoretically possible". I don't understand what you're saying. Please clarify by **updating** your question. – S.Lott Aug 03 '10 at 19:37
  • @Lott, the irony is that you did understand what I'm asking. I updated my post, but with these edits this legitimate question will be closed as subjective within minutes. – P Shved Aug 03 '10 at 19:45
  • @Pavel Shved: This isn't an answer to what you are looking for, hence why I added it as a commpent. I advocate trying it, and seeing what works from your scripts. The more scripts you put through it, the more you will know is missing, and you will get a better idea of why this is difficult. Obviously the first order of business is to write a complete perl compiler/interpreter. – Merlyn Morgan-Graham Aug 03 '10 at 19:48
  • Why not port 'legacy perl' to 'modern perl'. Oh and before trying to figure out how to automagically port perl to python maybe you aught to write a python 2 -> 3 converter ;) – xenoterracide Aug 03 '10 at 19:50
  • 3
    @Pavel Shved: Your question is still "Why is it not possible" when it's clearly *possible*. I still don't understand what you're asking. – S.Lott Aug 03 '10 at 19:50
  • @Pavel Shved: And my problem with this question is it amounts to research that you should be conducting yourself, if you are serious about doing this work. You should read the entirety of the perl and python specs, for one, then attempt to collect a set of well-known perl idioms that exist in your environment. Or, possibly, you could simply manually convert your scripts, a few at a time. If you are migrating to a new technology, you'll have to ramp up your programmers on python, anyhow. – Merlyn Morgan-Graham Aug 03 '10 at 19:51
  • 1
    @Merlyn, I don't think all Stack Overflow questions should be easy, and here I'm not asking you to do my job. I also don't require any of the answerers to do a complete research. One stacker outlines one feature which is hard to convert, another stacker outlines another feature, and this page becomes a collective research (CW?). Isn't it cool?.. – P Shved Aug 03 '10 at 20:05
  • @Pavel Shved: I agree that they shouldn't all be easy :) Much of computer science isn't easy. However, this seems like a poll rather than a question that someone could answer. Maybe this is what a community wiki is for? – Merlyn Morgan-Graham Aug 03 '10 at 20:21
  • 1
    @Merlyn, I can't qualify it as a poll; it's a collective work, not a "poll". Anyway, CW is not the reason why I didn't get answers, is it? Perhaps, I just failed to communicate to humans, which is more complex than talking to computers. – P Shved Aug 03 '10 at 20:35
  • 1
    Why limit the question to `perl` and `python`?? You could replace either or both in your question with just about any programming language and have nearly as meaningless a discussion. Programming languages, like natural languages, have their own adopted and required idioms. *Idiomatically* translating from one to another is almost always a difficult problem to automate. This is hardly news. What do you expect to accomplish here? – Ned Deily Aug 03 '10 at 20:45
  • @Ned, I don't want a meaningless discussion. I expect a list "In Perl we have *such* construct (`sample`), and in Python this construct would look *that* awful (`awful sample`)". – P Shved Aug 03 '10 at 20:56
  • When two languages start with and are practiced with very different design principles, it's not going to be that simple, I'm afraid. – Ned Deily Aug 03 '10 at 21:20
  • 1
    @Ned: Because it's often easier to deal with questions like this with some specifics. Much of what has been said here would be perfectly applicable to a C-to-C# translator, but I don't think we would have gotten the same level of discourse without names. – David Thornley Aug 03 '10 at 21:21
  • 3
    @David: Discourse is fine but it's still not clear what the point of all this is. Clearly, at face value, the question as stated is not correct: it *is* possible to create such a translator, at *some* level. But to what end? If the end result desired is *idiomatic* translation, then the discussion devolves to how language x is different from (or better than) language y and, particularly for values of x = perl and y = python, that discussion has been carried out over and over again in countless forums. And with good reason as there is no useful simple nor completely correct answer. – Ned Deily Aug 03 '10 at 21:42
  • @Pavel Read my updated answer – NullUserException Aug 11 '10 at 04:45
  • @Pavel Shved => see my answer (the paragraphs below the list) for an informal proof showing that it is impossible to ever create a fully functional (let alone idiomatic) Perl --> Python converter. – Eric Strom Aug 12 '10 at 20:25
  • @Ned Deily: if these answers don't convince you, I don't know what will. Instead of being subjective, or argumentative, they list a very informative array of language feature differences between Perl and Python that will be useful to any programmer who will ever have to deal with the two. – reinierpost Dec 13 '10 at 00:11
  • @reinerpost: I'm not sure what you refer to: convince me of what? Note this quote from the accepted answer: "The list goes on an on, and someone could try to create a mapping between all of the analogous constructs, but in the end it will be a failure for one simple reason." If you want to write idiomatic Python, learn to do so. If you want to write idiomatic Perl, learn to do so. Most importantly, learn how to understand and express algorithms. One's time is better spent on those pursuits rather than worrying about how to autotranslate code from one language to another. – Ned Deily Dec 13 '10 at 07:32
  • @Ned, what if what I want is to convert a log of legacy (though working) code to a newer language? Rewriting it from scratch (even if I have a full understanding of both Perl and Python) would be too hard, because a lot of tiny bugs will emerge inevitably. Could *this* aim be achieved? (Or, phrased as the question: *why exactly* couldn't it?) – P Shved Dec 13 '10 at 23:18

12 Answers12

36

Your best Perl to Python converter is probably 23 years old, just graduated university and is looking for a job.

corsiKa
  • 81,495
  • 25
  • 153
  • 204
  • 11
    Without a useful contribution, you're turning a serious question into a novel joke. – Evan Carroll Aug 12 '10 at 22:58
  • 4
    @Evan: It's probably true, though. – Paul Nathan Aug 14 '10 at 03:07
  • @Downvoter 7 months later, care to comment? You may think of this as a joke, but I know four recent college grads off the top of my head bagging groceries/living at home who would jump at even the most boring conversion job (for a lot less salary than they're worth.) – corsiKa Apr 18 '11 at 16:48
25

Why Perl is not Python.

  1. Perl has statements which Python more-or-less totally lacks. While you can probably contrive matching statements, the syntax will be so utterly unlike Perl as to make it difficult to call it a "translation". You'd really have to cook up some fancy Python stuff to make it as terse as the original Perl.

  2. Perl has run-time semantics which are so unlike Python as to make translation very challenging. We'll look at just one example below.

  3. Perl has data structures which are enough different from Python that translation is hard.

  4. Perl threads don't share data by default. Only selected data elements can be shared. Python threads have more common "shared everything" data.

One example of #2 should be enough.

Perl:

do_something || die()

Where do_something is any statement of any kind.

To automagically translate this into Python you'd have to wrap every || die() statement in

try:
   python_version_of_do_something
except OrdinaryStatementFailure, e:
   die()
   sys.exit()

Where the more common formulation

Perl

do_something

Would become this using simple -- unthinking -- translation of the source

try:
   python_version_of_do_something
except OrdinaryStatementFailure, e:
   pass

And, of course,

Perl

do_this || do_that || die()

Is even more complex to translate into Python.

And

Perl

do_this && do_that || die()

really push the envelope. My Perl is rusty, so I can't recall the precise semantics of this kind of thing. But you have to totally understand the semantics to work out a Pythonic implementation.

The Python examples are not good Python. To write good Python requires "thinking", something an automatic translated can't do.

And every Perl construct would have to be "wrapped" like that in order to get the original Perl semantics into a Pythonic form.

Now, do a similar analysis for every feature of Perl.

S.Lott
  • 384,516
  • 81
  • 508
  • 779
  • 16
    Straw man, anyone? Python is easy to read. It's just not easy to read Python that's been written in Perl. – nmichaels Aug 03 '10 at 20:01
  • 3
    @DVK: You missed the point entirely. So I revised the answer to attempt to clarify it. **Unthinking**, **automatic** translation of Perl to Python leads to problems. With a tiny scrap of actual human **thinking**, a better, clearer Pythonic statement is possible. But the question is not about **thinking**, human translation. It's about **unthinking**, **automated** translation. – S.Lott Aug 03 '10 at 21:26
  • 2
    Even with a few tries you're not dying the perl way: Outside an eval, prints the value of LIST to STDERR and exits with the current value of $!. If $! is 0 , exits with the value of ($?>> 8). If ($?>> 8) is 0 , exits with 255 . Inside an eval(), the error message is stuffed into $@ and the eval is terminated with the undefined value. If the last element of LIST does not end in a newline, the current script line number and input line number (if any) are also printed, and a newline is supplied. If the output is empty and $@ already contains a value that value is reused after appending. – SiggyF Aug 03 '10 at 21:36
  • @Nathon, It's *still* Python, though. So if the argument is that in order to do what somebody calling a Perl function expects, Python gets ugly, it *is* Python that's the "problem". Whether this is a pseudo-problem or not, is left to the reader. – Axeman Aug 03 '10 at 22:15
  • 1
    @S.Lott - I was trying to be funny (obviously, unsuccessfully). My comment was not really related to the substance of your answer. – DVK Aug 03 '10 at 22:24
  • Sure, Axeman. Python is not good at doing what Perl programmers expect Perl functions to do. That may or may not be a shortcoming, depending on your perspective. Like any language, Python code must be written in Python in order to appear sane. The same case can be made for C or Lisp code written for the Python interpereter. My point is that syntactic Python is not the same as idiomatic Python, which is the desired output of the OP's program. – nmichaels Aug 04 '10 at 10:28
  • @Nathon: Agreed. And idiomatically "correct" translation requires **understanding**. Which requires deducing the **intent** behind some random block of code. Rather hard to do for any random block of code in any language. – S.Lott Aug 04 '10 at 11:32
19

Just to expand on some of the other lists here, these are a few Perl constructs that are probably very clumsy in python (if possible).

  • dynamic scope (via the local keyword)
  • typeglob manipulation (multiple variables with the same name)
  • formats (they have a syntax all their own)
  • closures over mutable variables
  • pragmas
  • lvalue subroutines (mysub() = 5; type code)
  • source filters
  • context (list vs scalar, and the way that called code can inspect this with wantarray)
  • type coercion / dynamic typing
  • any program that uses string eval

The list goes on an on, and someone could try to create a mapping between all of the analogous constructs, but in the end it will be a failure for one simple reason.

Perl can not be statically parsed. The definitions in Perl code (particularly those in BEGIN blocks) change the way the compiler is going to interpret the remaining code. So for non-trivial programs, conversion from Perl => Python suffers from the halting problem.

There is no way to know exactly how all of the program will be compiled until the program has finished running, and it is theoretically possible to create a Perl program that will compile differently every time it is run. Meaning that one Perl program could map to an infinite number of Python programs, the correct of which is only know after running the original program in the perl interpreter.

Eric Strom
  • 39,821
  • 2
  • 80
  • 152
  • Good points, also with a lack of formal semantics it is not possible to know exactly what a Perl program does let alone recreate that functionality in another language. – Andrew Aug 03 '10 at 21:28
  • 3
    XS is another tricky spot, though that blurs the line about whether or not it's really "Perl". – Michael Carman Aug 03 '10 at 21:30
  • Thank you for your answer, it was even the accepted one (before I made the question CW). Your proof of impossibility is correct, but it's not *practical*. For most non-trivial programs I saw, `BEGIN` blocks are nevertheless not very complex, and affect the rest of the code in such a way that they can be transformed. So, this point does belong to the list, but can't replace it. – P Shved Aug 12 '10 at 22:56
  • 3
    @Pavel => I think you're underestimating the scope of the issue. While the thought exercise in my answer is admittedly an edge case, every single `sub ... {}` definition in a Perl program has an implicit `BEGIN` block around it. As does every `use` statement. The simple example of `BEGIN {*{(caller)."::$_"} = sub {...} for qw(list of names)}` defies any sort of static parsing (and that pattern is fairly common practice (exporting of subroutines from modules is done this way)). And each of these declarations could completely change the way the following code is parsed. – Eric Strom Aug 13 '10 at 00:04
  • @Eric, it's unnecessary to look at `sub`-s as at `BEGIN` blocks--we can converts them as `sub`-s instead. Also, Python has `import`, which can be used instead `use Sometihng qw(a b c)`. Python is also capable of creating class methods dynamically (see [here](http://stackoverflow.com/questions/533382/dynamic-runtime-method-creation-code-generation-in-python)) which can be used to change what subroutines can be called from a module dynamically. And, if Perl code uses `Exporter`, it's an idiom that can be converted, no expanding into `BEGIN` required! – P Shved Aug 13 '10 at 06:07
  • 1
    @Eric, I mean, "while each of these declarations could completely change the way the following code is parsed", they most likely do not: they just play around with symbol tables. Yes, tricky, yes, sometimes impossible, but this is just the same impediment as the rest of the list we're gathering here. – P Shved Aug 13 '10 at 06:14
  • 3
    @Pavel => consider trying to parse the following statement `my @result = foo bar 1, 2, 3;`. if `foo` has a `(@)` prototype, and `bar` has a `($)` prototype, the statement will parse like this `my @result = foo( bar(1), 2, 3)`. However, if `foo` has a `($)` prototype, it would be like this `(my @result = foo(bar(1))), 2, 3;`, and if they both had `(@)` prototypes, `my @result = foo(bar(1, 2, 3));`. As you can see, just the prototypes here can completely change the way the line their bareword is in gets parsed. and these parsing rules can change back and forth as more prototypes are added. – Eric Strom Aug 13 '10 at 12:57
  • 2
    ... and if it turns out that the prototyped subs are added programatically (which is not unheard of, there is no one way to export subs in Perl, you could use Exporter, or write your own methods), there is no way to statically determine what they will be, and thus no way to accurately continue with the parse beyond the BEGIN block that introduced them. This problem of self mutating parser rules is one of the primary barriers to automatic code conversion, because it gives truth to the statement "only perl can parse Perl" (little p being the interpreter binary). – Eric Strom Aug 13 '10 at 13:14
7

It is not impossible, it would just take a lot of work.

By the way, there is Perthon, a Python-to-Perl translator. It just seems like nobody is willing to make one that goes the other way.

EDIT: I think I might I've found the reason why a Python to Perl translator is much easier to implement. It's because Python lets you fiddle with a script's AST. See parser module.

NullUserException
  • 83,810
  • 28
  • 209
  • 234
  • 1
    Your answer is not helpful. A helpful answer would contain elaboration *why* this would take a lot of work. And your edits doesn't make it more clear. – P Shved Aug 03 '10 at 18:55
  • 9
    The same reason why it takes a lot of work to write a program that translates from English to Chinese. – NullUserException Aug 03 '10 at 18:56
  • 2
    @NullUser, *why* the same? It's not clear how natural language translation relates to processing of formal languages. – P Shved Aug 03 '10 at 18:58
  • @Pavel The easiest way would be try and write a converter/translator yourself, then you'd be way better qualified to answer that question than I am :) – NullUserException Aug 03 '10 at 19:01
  • 4
    @Pavel: Natural languages should technically be *easier* to translate than formal languages, because formal languages are not required to have any fundamental similarities, while natural languages are, or, at least in practice, do. – Jon Purdy Aug 03 '10 at 19:11
  • 1
    @Jon Purdy - I'm no expert, but it seems that natural languages have more "long range" structure requirements. That is, you could translate a function one statement at a time, but text needs to be translated sentences or paragraphs at a time for even cursory success. Wouldn't that make it more difficult? – detly Aug 11 '10 at 04:58
  • @detly: It's not so much that the *structure* of natural language is complex. I think you're inadvertently referring to the difficulty of capturing the *sense* of a text, which admittedly in formal languages *is* significantly easier because the meaning is formally specified, whereas in natural language it's more ill-defined. Arguably, no translation is complete without understanding, and current computers are much better at understanding the precise than the fuzzy. – Jon Purdy Aug 11 '10 at 11:23
5

Perl can experimentally be built to collect additional information (for instance, comments) during compilation of perl code and even emit the results as XML. There doesn't appear to be any documentation of this outside the source, except for: http://search.cpan.org/perldoc/perl5100delta#MAD

This should be helpful in building a translator. I'd expect you to get 80% of the way there fairly easily, 95% with great difficulty, and never much better than that. There are too many things that don't map well.

ysth
  • 96,171
  • 6
  • 121
  • 214
  • "too many things that don't map well" - could you slightly mention a couple of them? Just to be less abstract... – P Shved Aug 03 '10 at 19:30
  • 3
    a few: pack and unpack, formats, lvalue substrings, closures, local() – ysth Aug 03 '10 at 19:52
  • 1
    I see assertions that python has closures, but the examples then given are essentially just function pointers with no closing happening. So I'm probably wrong about that. – ysth Aug 14 '10 at 02:48
5

Fundamentally, these are two different languages. Converting from one to another and have the result be mostly readable would mean that the software would have to be able to recognize and generate code idioms, and be able to do some static analysis.

The meaning of a program may be exactly defined by the language definition, but the programmer did not necessarily require all the details. A C programmer testing if the value a printf() returned is negative is checking for an error condition, and doesn't typically care about the exact value. if (printf("%s","...") < 0) exit(); can be translated into Perl as print "..." or die();. These statements may not mean exactly the same thing, but they'll typically be what the programmer means, and to create idiomatic C or Perl code from idiomatic Perl or C code the translator must take this into account.

Since different computer languages tend to have different slightly semantics for similar things, it's typically impossible to translate one language into another and come up with the exact same meaning in readable form. To create readable code, the translator needs to understand what the programmer was intending to do, and that's real difficult.

In addition, it would be easier to translate from Python to Perl rather than Perl to Python. Python is intended as a straightforward language with clear standard ways to do things, while Perl is an unduly complex language with the motto "There's More Than One Way To Do It." Translating a Python expression into one of the innumerable corresponding Perl expressions is easier than figuring out what the Perl programmer meant and expressing it in Python.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
3
  • Python scope and namespace are different from Perl.

  • In Python, everything is an object. In Perl, everything under the hood seems to be a list/hash/scalar/reference/function. This induces different design approaches and idioms.

  • Perl has anonymous code blocks and can generate closures on the fly with some branches. I am pretty sure that is not a python feature.

I do think that a very smart chap could statically analyze the bulk of Perl and produce a program that takes small Perl programs and output Python programs that do the same job.

I am much more doubtful about the feasibility of large and/or gnarly Perl translation. Some of us write some really funky code at times.... :)

Paul Nathan
  • 39,638
  • 28
  • 112
  • 212
  • 1
    AFAIK, in Python object is a dict - same in Perl, because it was copied from Python :) – Alexandr Ciornii Aug 04 '10 at 09:43
  • @Alex: not exactly, I don't *think*. My introspections into types and objects in Python suggest to me that there is a fundamental difference - although fields do get stored in the local dict. – Paul Nathan Aug 04 '10 at 14:14
  • 2
    @Alexandr Ciornii: err, what are you claiming Perl copied from Python? You might want to check the relevant dates... – ysth Aug 14 '10 at 02:51
  • @Alexandr Ciornii, untrue. Most user objects are dict-like, but some are not (i.e. anything that isn't a blessed hash) – Mark Canlas Aug 13 '12 at 18:44
2

This is impossible just because you can't even properly parse perl code. See Perl Cannot Be Parsed: A Formal Proof for more details.

Hynek -Pichi- Vychodil
  • 26,174
  • 5
  • 52
  • 73
  • 1
    Arguably, though, a *reasonably large size* of Perl can be parsed. – Paul Nathan Aug 14 '10 at 03:07
  • How is it possible to write an interpreter for a language without a parser? – Anderson Green Aug 23 '16 at 22:41
  • @AndersonGreen: Reread my answer carefully, I haven't stated anywhere there is not a parser. The problem is the parser is Turing complete and you have to rewrite complete Perl parser including complete Perl interpreter to parse Perl code correctly. There is not a shortcut. – Hynek -Pichi- Vychodil Aug 24 '16 at 18:55
1

The B set of modules by Malcolm Beattie would be the only sane starting point for something like this, though I'm with other answers in that this would be a difficult problem to solve. In general, translating the sense of one high-level language into another high-level language requires a high-level translator, and, for the time being, that can mean only a human.

The difficulty of this problem, for any pair of languages, is due to fundamental differences in the nature of the languages in question, such as runtime semantics and common idioms, not to mention libraries.

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 1
    Libraries may be of help, rather than an obstacle. A translation of a library call may be another library call, which we can implement. While the translation of a built-in feature as a library call doesn't look that nice. – P Shved Aug 03 '10 at 19:28
1

The reason it is close to impossible to create a generic translator from one high-level language to another, is that the program only describe HOW and not WHY (this is the reason for comments in the source code).

In order to create a meaningful program in another highlevel language you (or the translator program) needs to know WHY to be able to create the best possible program. If you cannot do that, all you can do is essentially to create a Python interpreter for the compiled version of the Perl program.

In other words, to do this properly you need to go outside the box, and this is very hard for a computer.

Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347
0

NullUserException basically summed it up - it certainly can be done; it would just be an enormous amount of effort to do so. Some language conversion utilities I've seen compile to an intermediate language (such as .NET's CIL) and then decompile that to the desired language. I have not seen any for Perl to Python. You can, however, find a Python to Perl converter here, though that's likely of little use to you unless you're trying to create your own, in which case it may provide some helpful reference.

Edit: if you just need the exact functionality in a Python script, PyPerl may be of some use to you.

Ryan M
  • 18,333
  • 31
  • 67
  • 74
  • The approach of using intermediate languages and decompilation usually involves dramatic decrease of readability and loss of the structure of the program. And Python-to-Perl converter is a completely different task, and it doesn't shed any light on the reverse. – P Shved Aug 03 '10 at 19:01
  • @Pavel I believe use of an intermediate language is the preferred technique. As for readability, it is the job of the intermediate-to-Python converter to generate well formed and readable Python code. As for structure, Python and Perl programs are structured differently so I don't think you would really want a Python program that was structured like Perl, if that were the case just use Perl! Basically, after you have a reasonable Perl-to-intermediate converter, you can focus all your development effort on generating a good intermediate-to-Python converter. – Fredrick Pennachi Aug 03 '10 at 21:54
0

Try my version of the Pythonizer: http://github.com/snoopyjc/pythonizer - it does a decent job

snoopyjc
  • 621
  • 4
  • 11