[HN Gopher] Adding C-style for loops to Python for fun
       ___________________________________________________________________
        
       Adding C-style for loops to Python for fun
        
       Author : RojerGS
       Score  : 96 points
       Date   : 2023-02-03 16:54 UTC (6 hours ago)
        
 (HTM) web link (sadh.life)
 (TXT) w3m dump (sadh.life)
        
       | traverseda wrote:
       | Anyone looking to do this kind of thing, the macropy library
       | makes it a fair bit easier:
       | https://macropy3.readthedocs.io/en/latest/
       | 
       | You really do need to be modifying the AST and not just applying
       | a regex to the source code text. This can be a challenge if you
       | want to modify python syntax as you first need to get an AST you
       | can modify, personally I recommend starting with the LARK library
       | and modifying the python syntax grammer it includes.
       | 
       | https://lark-parser.readthedocs.io/en/latest/examples/advanc...
       | 
       | I use similar techniques to transpile openscad code into a python
       | AST in my "pySdfScad" project, while still theoretically getting
       | the benefits of fancy tracebacks and debugging and the like.
       | Probably should have gone with a simple parser instead, but what
       | can you do.
       | 
       | I think they should have stopped at the "cursed way" and not the
       | "truly cursed way", if they really wanted the syntax changes than
       | having your own python parser like the LARK implementation I
       | mention above is a must.
        
       | epr wrote:
       | Some people have a lot of time on their hands.
       | (defmacro cfor [initialize condition advance #* body]        `(do
       | ~initialize             (while ~condition (do ~@body ~advance))))
       | (cfor (setv i 0) (< i 10) (+= i 1)         (print i))
       | 
       | This runs on the python vm with hy right now. Took about 2 mins
       | to have it up and running after noticing this post on hn.
       | Couldn't pass it up.
        
         | [deleted]
        
         | ihatepython wrote:
         | I don't understand, this gives C style for loops with C syntax?
        
           | __jem wrote:
           | looks like it to me                 cfor(setv(i, 0), i < 10,
           | i += 1) {         print(i)          }
        
             | ihatepython wrote:
             | Do the brackets actually work or do you still have to get
             | the indentation right?
        
               | __jem wrote:
               | no, just saying you can trivially convert any lisp code
               | to c style syntax by moving the function call parenthesis
               | to the right and converting wrapping parens into curly
               | braces.
        
           | epr wrote:
           | This adds c style for loops to hy, which runs on the normal
           | cpython vm, and therefore can make use of the thousands of
           | open source python libraries available.
           | 
           | My reply to the post was tongue in cheek. The point is that
           | you can add on arbitrary language features to python using hy
           | (any lisp, really). The syntax in question is normally
           | referred to as an s-expression.
        
       | hot_gril wrote:
       | "It is recognized that you have a funny sense of fun."
        
       | akkartik wrote:
       | Just from the description I think this doesn't handle _continue_.
        
       | mixmastamyk wrote:
       | The range builtin already gives 98% of the functionality, just
       | need to put "i in range" before it.
        
       | chriskw wrote:
       | I did something similar to option 3 to make the builtin numeric
       | types "callable", since the dunder __call__ methods can't be
       | overwritten for builtins. For example, in regular arithmetic
       | notation, something like 6(7+8) could be read as 6*(7+8), but
       | trying to do this in Python gives you `SyntaxWarning: 'int'
       | object is not callable;`, since you're essentially trying to do a
       | function call on the literal 6. The workaround was to use a
       | custom codec to wrap all integer literals to give them the
       | expected call behavior.
       | 
       | Repo if anyone is interested: https://github.com/ckw017/blursed
       | 
       | This was inspired by a way less silly usecase, future f-strings,
       | which added f-string support to older versions of Python in a
       | similar way using codecs: https://github.com/asottile-
       | archive/future-fstrings
        
       | atorodius wrote:
       | Thanks for this wild ride, it went way further than I anticipated
       | ..
        
       | winterqt wrote:
       | (2022)
        
       | ur-whale wrote:
       | Didn't know about codecs ...
       | 
       | The idea of using (abusing in fact) codecs to pre-process python
       | code before it gets to the actual python interpreter is just
       | fantastic!
       | 
       | I'm starting to think of all the terrible things I'm going to be
       | able to do with this to work around things that have annoyed me
       | for years in python.
       | 
       | [EDIT]: I'm thinking one can probably plug the C preprocessor in
       | python now ... oh the sheer joy :D
        
         | com2kid wrote:
         | > The idea of using (abusing in fact) codecs to pre-process
         | python code before it gets to the actual python interpreter is
         | just fantastic!
         | 
         | Coming from Javascript which has Babel, this is kind of an
         | everyday occurance. Through the magic of source code transforms
         | You can easily add whatever experimental new JS features you
         | want to your project!
        
       | ___kaukas___ wrote:
       | A long time ago I stumbled upon (and contributed to)
       | https://github.com/delfick/nose-of-yeti. The most delightful bit
       | of cursed Python I've seen!
        
       | masklinn wrote:
       | > Or alternatively: How I made the most cursed Python package of
       | all time.
       | 
       | Beg your pardon, http://entrian.com/goto/ exists.
        
         | [deleted]
        
       | albertzeyer wrote:
       | I don't understand the reasoning why the transformation directly
       | on the source code is better than on the AST level?
       | 
       | Because you can use coding and then it's somewhat automatic?
       | 
       | But you can do sth similar on AST level, namely installing a meta
       | path finder, i.e. an import module hook which does the AST
       | transformation automatically
       | (https://docs.python.org/3/library/sys.html#sys.meta_path).
       | 
       | Then, there is also the new frame evaluation API
       | (https://peps.python.org/pep-0523/), which allows you to
       | dynamically rewrite bytecode. This has been used by PyTorch 2.0
       | for torch.compile.
        
         | adrianmonk wrote:
         | In part 1, they say, "I wanted it to look like a regular for-
         | loop from C as much as possible."
         | 
         | The AST method seems to require you to write "with _for"
         | instead of "for".
         | 
         | The method in part 3 allows you to write "for", which is
         | closer.
         | 
         | So presumably it's better because it gets closer to the
         | objective, although at quite a cost of course.
        
         | traverseda wrote:
         | That only work in an import statement, not when you run the
         | code directly.
        
         | [deleted]
        
       | benrutter wrote:
       | There really is nothing greater than an completely idiotic idea
       | implemented with pure genius - this was immense reading and I
       | learnt a lot!
        
         | nothrowaways wrote:
         | it is like a sitcom.
        
       | mjburgess wrote:
       | So it seems you can register a source transformer with python
       | which will trigger when a `# coding: ...` header is used (to
       | signal character encoding).
       | 
       | This seems like an interesting avenue for static analysis tools,
       | code generators, (etc.) to explore. Is it a viable approach?
       | 
       | I'd be interested in some analysis on this as a mechanism:
       | performance, maintability, etc. wise.
       | 
       | The "dont do this" argument writes itself; nevertheless, its
       | worth exploring.
        
         | ktpsns wrote:
         | Funnily this reminds me of how racket defines a language
         | (https://beautifulracket.com/explainer/lang-line.html). Or how
         | basically a shebang line does the same for any kind of script
         | (https://en.wikipedia.org/wiki/Shebang_(Unix)).
        
         | leethargo wrote:
         | True, but I think that source transformation on import are
         | already supported in Python ("officially") based on importlib
         | [0-1].
         | 
         | Here's an example use cases where the author is trying to
         | create a Python enum from Thrift specs: [2]. The issue here is
         | that the spec code is not necessarily valid Python, but can be
         | fixed easily with some search & replace operations.
         | 
         | [0] https://docs.python.org/3/reference/import.html [1]
         | https://docs.python.org/3/library/modules.html [2]
         | http://wakandan.github.io/2018/06/07/python3-import-hook.htm...
        
           | leethargo wrote:
           | One of the benefits of implementing your own module finder
           | and loader is that you could use a separate file extension to
           | avoid confusion with actual Python code.
        
       ___________________________________________________________________
       (page generated 2023-02-03 23:00 UTC)