Hacker News new | past | comments | ask | show | jobs | submit login
Anyprint: use any language's print statements in Python (github.com/kragniz)
113 points by ddevault on July 18, 2017 | hide | past | favorite | 72 comments



Why stop at print statements? After all if you find yourself successfully using the print statement from some other language, you might accidentally also use its if, for loop, file handling and class declaration constructs among many others. Who's looking out for those people? This is just the beginning!


Coming from Powershell, nobody told me JavaScript copies arrays by reference instead of by value. Why would anyone want to pass a reference?


In Object Oriented Programming it can be useful if you want to pass the reference as the argument instead of the value.


Ironically, what I miss most from Python is Python2's print, which for a language proud of getting rid of parenthesis, that is very contradictory....


Perhaps you'd enjoy Nim which supports both.

    echo "hello world"
    echo("hello world")
and as a bonus, also the following:

    "hello world".echo


I'm a primarily Python dev, have been for a long time. Lately I've been working in Javascript/typescript and there is no worse antifeature than having 3 different ways of doing the same thing.

You try to figure out how to do something, you see 3 different solutions and you ask yourself, what's the difference? What's more correct? Will I need one over the other? Are they compatible? Is one way better supported than the other?

The amount of time I've spent looking up differences between two APIs or two paradigms in Typescript is seriously ridiculous. And it feels really bad to not recognize something you've done before because it's written differently.

Common culprits: require() and imports, the countless ways of creating classes, the crazy amount of different ways to implement similar or identical workflows in webpack and pretty much the entire JS ecosystem in general.


>You try to figure out how to do something, you see 3 different solutions and you ask yourself, what's the difference? What's more correct?

Maybe I'm just bad programmer, but I whole heartedly embrace languages that let me express myself in a way I want to. Big part of my day is dealing/writing/converting stuff to Python and part of me wishes there wasn't "the Zen way" to do things, but instead I could express myself, but this kind a goes beyond Python in a sense that it doesn't have the syntax I would like to use.

I'm by no means saying that JavaScript is any better. So far my personal favorite language has been Ruby (and not the Rails way), for some reasons it feel like with Ruby I can just tell the code what to do instead of having to explicitly command it to do what I want step by step.


> You try to figure out how to do something, you see 3 different solutions and you ask yourself, what's the difference? What's more correct? Will I need one over the other? Are they compatible? Is one way better supported than the other?

I've always wondered this: would it be that bad, if you could easily guarantee that all those formats really are equivalent? (maybe by being able to check a unique identifier of the function to which the expression is going to be compiled).

In the case of this library, the semantics are simple and clear: I have a string object, and I want its contents to be poured on a predefined output device; maybe converting on-the-fly some escape characters in the string to the values of some parameters.

Provided that you don't deviate from this specified meaning, is it that bad that the language accepts any common syntax?

I understand the "being harder to recognize what it is doing", but I think that might be somewhat alleviated by the feature I said above of unambiguously resolving to a single entity in the programming language.


Python 3 now has 3 similar-but-different way to format strings. Python is definitely heading down a bad path.


As a primary js developer (about 10 years) who in the most recent two years has done more and more es6 work I will revel in the day I don't have to use it in my day to day. I toy with clojure in my free time and even python and just hate the way the JavaScript language has been taken over not just by trends but with what I think are poorly thought out syntax additions. JavaScript seems like a language that has no opinion on the best way to do a thing, no well thought out constructs to eliminate boilerplate, and just sits there and waits for a Bower, and mom, a lodash, or a Babel to come along and tell it hoe to be a proper language.


I also think we should write our programs as concise and simple as we can. There should really be one obvious way to do it.

I recently read the statement that "If you can solve parsing Perl, you solve the Halting Problem "(http://www.perlmonks.org/?node_id=663393). This is not a joke, it's serious.

Python and Go keep their promise to stay simple. However I believe, metaclasses, asynchronous programming and constructs like "yield from" and the whole itertools library could be better engineered. And lastly with new approved PEPs like concerning string interpolation etc., I believe Python is making compromises in its core ideology. In contrast, in go if you want to allocate something you just use make(), if you want your code to run concurrently you just use "go", if you want to send messages between threads, you just use channels. The complexity is well hidden in the language itself.

What I don't like in Java for example is that, as a general purpose language, in each version new features are added. And these new features add complexity, and complexity leads to mistakes.

Perl I understand, it was designed as the first postmodern programming language. Javascript was written in a very short time and intended to be a browser scripting language. But Typescript?, with Typescript there is no excuse. I guess, this is Microsoft's policy: Worse is better, make everyone (or at least revenue sources) happy. You want feature x, they add it, you want lambdas, they add it etc.

Maybe I'm a bit tired of hassling through chaos, but I want my codebase to be structured. If I don't like an API, I take my time and write a simpler abstraction. One programming advice stuck in my mind from the Art of Linux Programming: you should focus on data structures (a.k.a structuring).

I think this advice is true for all aspects of life. You need to set aside a place for your things, if you want to live/work in a tidy environment. You need to plan your day, if you don't want to fall apart. You need folders to organize your e-mail/documents. You need to structure your programs in meaningful abstractions into seperate modules/subroutines.


To be fair on typescript, I think it's inheriting most of these issues from wanting to give a better way to do things, but keeping (near-)full backwards compatibility with JS.

It's ES5, ES6 etc that is adding to it.


I feel you on the JS/TS front, but to be honest it's somehow less of an issue in Nim. Not sure why, but everyone does really follow some pretty simple conventions.


> [T]here is no worse antifeature than having 3 different ways of doing the same thing.

Ironically, this is touted as a strength of Powershell. Speaking of which, this code supports none of Powershell's Write-Host variants.


Lua does too, for literal tables and strings being sole argument you can omit parentheses. But to call method on a literal you need to add them.

> print("OK")

> print "OK"

> ("OK %d"):format(1)

I've seen some funky (ab)use of these, people using literal strings and tables and functions named class and similar to do:

> class "Something" {

> -- ...

> }


This is one of the reasons I love Lua. I'm constantly pleasantly surprised by Lua. It defines a few simple primitives, and allows you to do whatever you want with them, even to the absurd.

Hell, it even allows you to do this:

> somefunc "1string" "2string" "3string" > somefunc {} {} {}


>"hello world".echo

Okay I have to admit I love this one.


It gets better with chained function calls, e.g. (D-like pseudocode):

writeln(mul(add(x, 5), 30))

vs.

x.add(5).mul(30).writeln()


UFCS.

Also found in D.

And, frustratingly, did not get past the C++ committee.


Name resolution is already so insanely complicated in C++ it's hard for me to lament this too much.


Well, the works already been done so I don't care that much about language at this point.


> for a language proud of getting rid of parenthesis

Er… what?

Python doesn't have braces, it has plenty of parenthesis. In fact, Python 3 added more since it upgraded several keywords to functions (not just print but also exec, and some forms of re-raising)


Little known fact: The addition of `exec`-with-parenthesis actually long predates Python 3. Python 3 just removed the old, braceless version.

That this is so little known is why we have a complicated future.exec_, which is entirely needless! (https://stackoverflow.com/a/26098101/1763356)


> Little known fact: The addition of `exec`-with-parenthesis actually long predates Python 3. Python 3 just removed the old, braceless version.

That's not really true, although the syntactic compatibility does make for conveniently trivial cross-compatible code, Python 3 did not "remove the old, braceless version" it converted exec from a keyword (which could accept a single tuple parameter) to a builtin function (which takes up to 3 parameters). Which had the side-effect of requiring parenthesis.

Incidentally, the print-tuple-trick is cute, I hadn't considered it.


Yes, I explained badly. I appreciate the clarification.


print chevron in python2 is super awesome

    print 'hello'
    f = open(file, 'w')
    print>>f, 'world'
It just feels more "powerful" than Py3k's

    print(somestring, file=someopenfile)


> print chevron in python2 is super awesome

Print chevron is super awful, it's unreadable, hard to remember and difficult to search for.

The print function was a welcome improvement: it's not a statement (so can be used in a lambda, no need to fall back to sys.stdout.write), it doesn't use weird-ass syntax to redirect or suppress the final newline and it's more extensible (e.g. "end" or "flush" kwargs would have been… challenging to add to the keyword version)


> More powerful

But less obvious and readable, which is anti pythonic. If you want "power" over readability, there is ruby/perl.


I'm not going to discuss perl readability, but the fact is that I cannot simply 0%% to beginning of the block in "readable" python. ?:$<CR> does its job though.


Note that they say it feels more powerful, it's not like it is more powerful than the file kwarg.


If you want power you can

    fprint = lambda string: print(string, file=somefile)
and use fprint all over the place

that little chevron trick is bad imo


You'd like Perl:

  open my $file, '>', 'hello';
  print{$file} "Hello";



When I saw the title I thought to myself "this is going to be some elaborate troll about Python2 vs 3's print, isn't it?"


Same here. I will probably keep using Python 2 for as long as it works... simply because I don't have to type those parentheses.


As someone most at home in lisps--there's just no accounting for taste ;)


Is there a LISP with significant white space in place of parentheses? Our two groups could be united by the disgust of the rest of the programming community.


The Arc language wiki has this list of languages that make use of significant whitespace.

https://sites.google.com/site/arclanguagewiki/more/list-of-l...


See this: http://readable.sourceforge.net/

Works with both Scheme and Common Lisp, two most popular Lisps out there. Nobody uses it because paredit/parinfer is just too convenient, but the option is there.


Check out Dylan and Sweet Expressions.


Here's a nickel kid, buy yourself a decent editor. ;) Mine has snippets:

    pr<TAB>  --->  print('%cursor%', %cursor%)


Let's hope they also add

    (format t "hello ~a!" name)
for completeness...


To say nothing of vitally important format expressions like

  (format t "~{~a~^, ~}" list)


And of course the stuff necessary for word-wrap-in-`format`:

    (format t "~{~<~%~1,40:;~A~> ~}"
      '("these" "words" "will" "be" "wrapped" "to" "40" "characters"))
and the other `format` insanity in: http://cybertiggyr.com/fmt/fmt.pdf


Behold the mighty power of CL format!! I wonder if the format string language, aka "line noise", is turing complete...


They closed my issue for a clojure style

    (prn "hello world")
I was actually just looking into adding a hook for an automatic AST transformer so I could possibly call into Hylang.


Worth noting: the language's syntax must still be minimally compatible with Python -- this isn't some sort of magic parser hack, it's just adding functions and types with special behaviour (like having "cout" be an object that overrides __lshift__). Now, given that many Lisp and Lisp-likes support ridiculous parser hacks (Scheme/Racket come to mind), I bet you really could pull off "Anyprint" in one of those languages...


The Testimonials section cracked me up.


It looks like your testimonial has been added to the project, ha.


Makes all these valid in Python:

    printf("printf %d\n", 10);

    fmt.Println("hello")

    cout << "Hello, C++!" << endl;

    Print["Hello from Mathematica!"]

    console.log("yes");

    System.out.printf("java stuff\n");

    Ada.Text_IO.Put_Line("Ada is cool")

Really funny, including the testimonials:

> Anyprint has many glowing reviews from its many satisfied users: > > * "omg pls" > * "what is wrong with you" > * "That's stupid and not useful." > * "Please add my testimonial: "very accurate testimonials"." > * "kragniz, please stop writing questionable python metamodules :v"


> cout << "Hello, C++!" << endl;

For the love of god, please stop using endl. It performs a flush when "\n" is both valid and all that you ever want.

Also what happened to the std:: prefix?


Are you saying you never want to flush?

If flushing after every line is good enough for printf then it's gonna be good enough for me~


Buffering of Cs stdout is implementation defined. For Linux it is only line buffered in an interactive terminal session and fully buffered otherwise.

> Are you saying you never want to flush?

90% of the time not. The other ten percent include asking for user input, which causes an implicit flush since std::cin is linked to std::cout, and debugging an ugly heisenbug.


Lovely! The idea is very similar to NoFail ( https://github.com/laurentlb/NoFail), a language I've described, but not yet implemented.


How about Ruby, Perl or the Python 2 print statements?


This project is so wonderful it took down Github


Please add support for

    NSLog(@"Hello, %s and %s!", @"macOS", @"iOS");


Warning: Format specifies type 'char ' but the argument has type 'NSString '


Whoops! Should have been `%@`


Is Fortan's

  WRITE(*, *)
doable? How to handle the * isn't jumping out at me.


Please add support for:

    `0:"Hello from K.\n"


Ironically, it doesn't (and can't) support Python 2 print statements.


And by extension, QBasic's PRINT statement. 0/10.


In all seriousness, it never occurred to me before that because of access to "globals", an import statement can introduce (or alter the value of!) unexpected names.


Can I have a D style:

  "Your text here".writeln;



You can in PyPy, where we can enable monkeypatching str


Now implement printing to a string (sprintf, etc.)


All your testimonials are belong to us.


I already sent this to my co-founder


5


Now we just need a nice restrictive license to grab all the patents.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: