Settings

Theme

Show HN: Python with do..end in place of strict indentation

github.com

12 points by humility a year ago · 70 comments

Reader

driggs a year ago

Anyone who can't see past Python's indentation-based syntax is a person who doesn't understand Python.

(Both literally and figuratively!)

When "significant whitespace" is at the top of someone's complaints about Python, I'm immediately done hearing about their superficial criticism of the language.

  • mkl a year ago

    Agreed. I find such complaints very strange, as most people already follow Python-like indentation rules quite strictly in most other languages, but need to add delimiters as well. Indentation is the clearest indication of code structure, so when it's not significant it still looks significant, leading to bugs like:

      if(condition)
          do_thing1();
          do_thing2(); //not in the if!
      do_thing3();
  • dariusj18 a year ago

    My problem with indentation as significant is when I paste a chunk of code inside some chunk that is indented differently. Some may say that a good text editor will deal with that for you, but it's rarely been the case for me. The most is when the code is longer than my screen height and I have to scroll down and figure out where the pasted chunk ends and indentation it all who knows how many times without scrolling back up to the top of the chunk.

    • smitelli a year ago

      Speaking only as myself, usually when I find myself having the scrolling problem the function/method is crying out to be broken down and refactored anyway.

  • wwfn a year ago

    Literate programming tools that weave/tangle code and documentation don't play well with significant whitespace. Not a problem for me, but I think it's on a valid line of complaints.

    • Jtsummers a year ago

      Which ones? Org mode's babel works fine with it. If you do something like this (loose, not precise babel syntax):

        <<body>>=
          if 1 == 1:
              print('1 == 1, shocking!')
      
        <<function>>=
          def foo():
            <<body>>
      
      It will generate properly indented code when tangled as in:

        def foo():
          if 1 == 1
              print('1 == 1, shocking!')
      
      Note that it puts in precisely two extra spaces for each line in the tangled `body`, which is the amount used in the block named `function` where it references `body`. If you used 4 spaces of indentation, it would use 4 in the tangled output. I've also used noweb and don't recall this being an issue, however that was not with Python so it's possible I just didn't notice a problem with it.
      • wwfn a year ago

        I stand corrected! I'm guessing my own bad formatting lead me astray at some point. I tried to come up with a pathological example that'd break with noweb just now and had no luck.

    • driggs a year ago

      I very strongly disagree. The most successful implementation of literate programming is the Jupyter Notebook, formerly called iPython Notebook. Even when you write it as raw markdown, there's no issue mixing documentation with triple-backtick code blocks.

      Maybe you're thinking of mixing Python with HTML? Python based HTML templating can be ugly, and the significant indentation of Python is a very poor mix for replacing Javascript in whitespace-agnostic HTML.

      • wwfn a year ago

        I thought tools like jupyter and rmarkdown are better described as narratives[0] (lab notebooks and report generators) separate from and almost antagonistic to literate programming[1]. At least as I've been exposed to them, notebooks don't easily facilitate code reuse -- libraries aren't written in notebooks but could be written with literate programming tools.

        [0]: https://khinsen.wordpress.com/2015/09/03/beyond-jupyter-what... [1]: http://www.literateprogramming.com/

      • tommiegannert a year ago

        > there's no issue mixing documentation with triple-backtick code blocks.

        Your argument became: By adding delimiters, even Python can play well with other languages. /s

    • nomel a year ago

      Technically comments are considered blank lines, so indentation can be arbitrary. This is against PEP8/linters, but it's not a formatting error.

      Triple quoted docstrings just require that the initial marker (""" or ''') is indented properly (since they are not considered blank lines). All contained text, and the closing marker, can be at any indentation level. This is the cleanest way to include a page of free form documentation, mid anywhere.

  • dgfitz a year ago

    I agree. I think it’s only an issue because we as a collective didn’t sort out a tabs-vs-spaces debate and new people to the language struggle with that bit.

    • Yizahi a year ago

      The problem is that in the year 2024 there are no real technical arguments against tabs. I suspect very few people saw any tab mangling system ever in their lives or even at all. We are like monkeys from the anecdote about bananas and waterhose. All the population has been replaced multiple times and waterhosse is long dead, but we are still afraid to touch the forbidden fruit.

      • diggan a year ago

        > The problem is that in the year 2024 there are no real technical arguments against tabs.

        Since you added "real" in there, no argument really matters. But regardless, it's funny you say that, as Python current style guide (https://peps.python.org/pep-0008/) outlines 4 spaces as the one and only correct way of writing Python code.

        • Yizahi a year ago

          The emphasis was on the word technical. The only technical argument I've ever heard against using tabs for indentation only, was that some software text editor a long time ago mangled tabs. In my anecdotal experience with computers plus working with some embedded telco hardware dating back to 2000 and some even earlier, some with rather old or non mainstream OS, I've never ever seen a text editor which mangled tabs. Nor I've never met anyone who seen that happen. Maybe it happened in the mainframe age, but I suspect even that software has been upgraded over time.

          Sure, PEP8 an other standards prescribe spaces, and I of course always use industry standards myself too. I'm just saying that there is no technical merit for that demand. The water pipe in the monkey cage has long been shut down. The only reason to demand spaces for indent now is circular - that other standard is demanding them, therefore we need to do the same, and that other standard uses the same circular logic himself.

      • xigoi a year ago

        Technical argument against tabs: they don’t play well with auto-formatters that enforce a specific line width.

        • Yizahi a year ago

          Valid concern, thanks. Though I'm interested how such automatic formatting works with spaces.

    • maleldil a year ago

      PEP-8 says 4 spaces. No one should be using tabs.

  • jokoon a year ago

    Personally I started making a language that uses it

  • everyone a year ago

    I dont think it's superficial. Having characters that are invisible affect your code is weird and bad.

    Which is a shame, cus otherwise Python is good imo.. I feel like its creator just had a weird whitespace fetish or something.

    • sanderjd a year ago

      It's weird and fine.

      I always find this take funny, because I have lots of problems with python, but this one has always struck me as the most superficial of the common criticisms.

    • xigoi a year ago

      Indentation is very much visible.

  • Sohcahtoa82 a year ago

    When I hear someone complain about the whitespace thing, it sends a message to me that they do not format their code well and just go willy-nilly on their indentation.

    If you're properly indenting code, then it always works as intended. Proper indentation doesn't come from a desire to make the code work, it comes from a desire to make it readable. It just happens that readable means correct in Python's case.

    It literally takes me zero thought to get indentation right. If you can't tell when to start or end indentation level, then I'd question if you know when you need to use an open/close brace in other languages.

    I mean, yeah, sometimes copy/pasting code doesn't work precisely as intended, but all you have to do is select the code, hit Tab or Shift-Tab, and any sane editor will add/subtract an indentation level to the code.

    • HexDecOctBin a year ago

      I just translated all my build scripts written in Python to straight C due to indentation issues. Not because I don't format my code properly, but because any time I refactored my code, I ended up with dozens of subtle indentation related bugs that took hours to find and fix.

      If your language requires an IDE, then you have become Java.

      • sanderjd a year ago

        I don't relate to this at all. I don't understand how you refactor, in either python or C or anything else, without fixing indentation after you move code around. Yes, in C you don't have to fix the indentation in order to get it to compile and run, but that doesn't mean you don't have to fix the indentation! You can't just leave it inconsistent, that's insanity.

        • wakamoleguy a year ago

          Of course you can leave it inconsistent! If whitespace is insignificant, you can move things around however you want and use (frequent) runs of a code formatter to clean things up for you. If whitespace is significant, it must be fixed manually line by line.

          • sanderjd a year ago

            Code formatters work just fine in python. If you're running a code formatter frequently, that is not "leaving it inconsistent".

            • wakamoleguy a year ago

              If we’re talking about pasted code not having the proper indentation, that’s a major difference between languages with and without significant whitespace. A formatter can fix that in C, but not in Python. Additionally, manual fixing of the indentation is required first.

              • sanderjd a year ago

                I just don't think this is really a problem. My editor doesn't actually have trouble putting pasted code at the right indentation level...

      • kstrauser a year ago

        Python doesn't require an IDE, but you'll definitely want to use a programmer's editor with it. I don't know what you're using that doesn't handle its indentation correctly because I haven't seen anything like that in at least a decade, but you may wish to upgrade to at least a newer vim or emacs.

      • dgfitz a year ago

        Hours? And C was a better option for scripting than python?

        I’ll give you the benefit of the doubt, this sounds very curious.

        • HexDecOctBin a year ago

          Pretty much. Partly because I have developed a pretty robust C standard library that I allows for writing code that is not too dissimilar from the kind of Python I was writing. And one shot processes mean that I can simply allocate memory without having to free it (and use arenas for one script that is a long-lived file-watcher).

      • gunian a year ago

        why? black automatically formats code

      • simonw a year ago

        What text editor do you use?

    • tbrownaw a year ago

      > When I hear someone complain about the whitespace thing, it sends a message to me that they do not format their code well and just go willy-nilly on their indentation.

      That's quite the assumption.

    • cma a year ago

      Not being able to nest multiline lambdas into function arguments where they are called makes you have to read a lot of code backwards.

      • kstrauser a year ago

        I do wish it had lambdas. That's largely mitigated by the fact you can define functions pretty much anywhere. Instead of:

          def my_func():
              another_func(lambda: ...)
        
        you can write

          def my_func():
              def inner(): ...
              another_func(inner)
        
        Sure, it's creating a function, naming it, then immediately throwing it away, but gets the job done with minimal extra boilerplate.
        • cma a year ago

          That's what I meant by backwards though. Especially in UI OnClick code etc., I'd rather know the context that this happens on click of whichever object it is, but instead I have to write the clicked code before the code that registers it with the object, whose name has more relevant info, and then I end up having to name an extra thing too and keep the name in sync

          • kstrauser a year ago

            But you can use a named function anywhere you'd use a lambda, in exactly the same way, just literally one line above where you'd pass the lambda to another function. It's not like you have to write the named function up at the top of the file. You can define it right there where it's going to be called. Truly, it's so easy and cheap to make a named function that I've never really missed having lambdas.

            • cma a year ago

              Its backwards when you read it and redundant.

                  def do_on_click(): # What's being clicked? 
                      foo()
                      bar()
              
                  backup_system_panel.reset_button.bind(on_click=do_on_click())
              
              Oh it's the backup system, maybe I should have named it that. Now I have to worry about reading backwards or keeping names in sync. Having to give it a descriptive name is like uneccessary comments. Giving it a temp name is ok but then you are reading bottom to top to know what is going on like you are programming in reverse polish notation or something. It can be multiple lines and scrolled off the screen before you know the context it is used in, instead of just being able to read top to bottom and get everything. Most other languages let you just stick it in line where it is used. It's error prone like C variables when they had to be declared up top.

              Sometimes in other contexts it does make sense to do, but with other languages you can choose to pre-declare and name it or not. In python often you see code with all the error handling lambdas up top before you even know what is going on, when exceptions aren't a good fit.

          • int_19h a year ago

            One trick for this is to use the decorator syntax, e.g.:

               @foo.on_click
               def foo_clicked(): ...
            
            Of course, for this, foo.on_click needs to be a callable function rather than a property.
        • sanderjd a year ago

          Yep, I find python's lambda syntax to be probably its worst conceived feature. But just defining a named inner function works great for all the same use cases.

      • xigoi a year ago

        That has nothing to do with significant indentation. Other languages with significant indentation (Nim, CoffeeScript) support multi-line function literals.

        • cb321 a year ago

          Because of Python's prominence and the divisiveness of significant indents, there is a large amount of misattribution of "whatever Python's syntax choices are" to "must be needed by significant indentation". E.g., whenever I go from Nim back to Python, I get annoyed that `t = 0; for e in x: t += e` is illegal in Python (Yes, I know `sum()` exists - it's just another easy syntax example to amplify your lambdas one.)

      • dgfitz a year ago

        It also makes hard-to-maintain code. Trade-offs.

    • tom_ a year ago

      Python forces you to properly indent your code because the language is designed in a way that means the computer can't do it for you.

      Once I'd become accustomed to languages where automatic formatting is feasible, having to do any of this sort of thing by hand started to feel like a real imposition. I didn't object to this aspect of Python when I first learned it, because it didn't feel much different from writing my C code, but now, after years of clang-format (and Visual Studio's auto format, and gofmt on the occasions I've been forced to use Google Go...) I just can't be bothered. How dare it make me press return. How dare it make me press tab. I have better things to do with my life than what I can only describe as this. fucking. shit.

      • xigoi a year ago

        You have to press return instead of a semicolon, which is the same amount of keystrokes, and tab instead of a curly brace, which is fewer keystrokes. What problem do you have with that?

        Also, Python has a great auto-formatter, Black.

  • ahartmetz a year ago

    Yeah. It avoids the problem of indentation disagreeing with code structure and reduces visual clutter and... that's it.

    • tacticus a year ago

      you can solve that with a formatter. and then you'd get consistent outputs that work reliably as you move code.

animal_spirits a year ago

> I built this to learn more about python/interpreter language syntax in general, but not interested in pursuing this further.

Good job trying something new out! There is always room for experimentation, if any reason to try to learn something new.

  • joshdavham a year ago

    Yeah I think it’s a cool idea but also a little funny to see that the project is archived after clicking on it for the first time haha

gus_massa a year ago

Sorry, I have to ask...

Does it support also braces? :)

IIUC the source is writen as a long heresting and then executed.

Does it have the same speed than normal Python?

Does it suppont numpy, numba and other similar packages that use jit?

Can a function inside the modified code call a function outside? (It may be helpful for porting conde one function at a time.)

Is it possible to do something similar with a decorator instead of a herestring?

  • zahlman a year ago

    (This sort of thing has been done before, and of course it will never make its way into the official Python distribution; but it's always fun to see.)

    >Is it possible to do something similar with a decorator instead of a herestring?

    No, this is a fundamental change to Python syntax. To apply a decorator to existing Python code, the decorated code has to compile first, creating a Python object (generally either a function object or "type" i.e. class object) which is passed to the decorator (which is really just a higher-order function with special syntactic support).

    But of course, you could write the code to preprocess in a separate file with a different extension, and then have actual Python code which reads and preprocesses it and then evals the result. (The internals could also be written differently, in terms of AST manipulations using the "compiler services" part of the standard library. But this way is probably easier.)

    On Linux, you could also have a top-level script which does those steps for a specified input filename, and then specify that script in the shebang line for the Dopy code file.

  • humilityOP a year ago

    > Does it also support braces? No :)

    > the source is written as a long herestring and then executed that's correct but only for single file modules. you can actually have a python like structure comprising entirely of dopy files and it will be compiled in place or in temp dir and executed as a normal python package with distributed source

    > Does it have the same speed than normal Python It's just a transpiler so the code is actually executed by the python interpreter itself. So same speed as python with an extra build step

    > Does it support numpy, numba, other packages that use jit? Not now

    > Can a function inside the modified... Certainly

    > Is it possible to do something similar with a decorator instead of a herestring? Could you explain?

airstrike a year ago

I used to code in Python for everything in the late aughts and loved meaningful whitespace. Whenever I used a language with braces like JavaScript, for instance, I felt like I was still indenting code meaningfully but now I had the extra hurdle of also caring about the braces. It felt unnecessary and stone-agey.

But back then I was just using vim with a nicely configured .vimrc. Linters weren't really a thing, or at least not neatly integrated into my editing experience.

Nowadays I write Rust in vscode and I love braces. Rustfmt just formats my code every time anyway, so I don't have to care about indentation and braces are placed where they should be. I spend zero time caring about code formatting, outside of configuring rustfmt.toml once per project or the occasional #[rustfmt::skip] for codeblocks which I really want to format in a specific way outside of the linter's configured rules. I also have the benefit of the compiler screaming at me if I forget a brace, pointing to the exact error including telling me when indentation is suggesting a brace is missing! :O

Moreover, I'm much more proficient in vim, and the single hotkey % is reason enough to want to favor braces. Coupled with how often I paste code into Claude, V$%,y has become muscle memory (visually select this whole line, go to the end of the line, then expand the selection to the line matching the closing delimiter under the cursor, then yank everything into the system clipboard with <leader>y)...

On occasion, I go back to Python for some side project and the whole experience feels... weird. If braces before LSPs and linters was the stone age, then Python feels like the iron age and I'm living in the future with a compiler that is incredibly talkative and helpful. I'm never going back.

  • sanderjd a year ago

    I feel like your conclusion is backwards based on your argument...

    > I also have the benefit of the compiler screaming at me if I forget a brace, pointing to the exact error including telling me when indentation is suggesting a brace is missing!

    What the compiler is telling you here is that the braces are superfluous, because the indentation is already describing the structure correctly. So why bother?

    My take is that in the (amazing!) new world with near universal usage of standardized linters, this whole debate is stale, it just doesn't matter either way. Everything is indented properly, whether or not it is necessary for correctness. So whether there is a bit of additional bracing or not, who cares?

    • airstrike a year ago

      It's much easier to navigate to the end of a codeblock in the editor with vim. I can't do the same without braces. I admit this is an irrelevant argument if you're outside the vim echo chamber...but it's a pretty big echo chamber

      • sanderjd a year ago

        I use vim, and yes, this is a very specific annoyance. But I just go to the beginning of the next block.

  • kstrauser a year ago

    I feel the same way with my editor running Ruff on save. I still have to get the indentation right (which the editor handles for me), but that's about it. Once I hit cmd-s, everything subtly shifts to where it's supposed to be.

  • maleldil a year ago

    Regarding your Claude copying flow, there's a Python-compatible alternative. In nvim, you can use treesitter selections to select a block, and treesitter is aware of the indentation.

scotty79 a year ago

Seeing code blocks as braced or meaningfully indented should be a switch in your IDE.

  • sanderjd a year ago

    Yeah I once saw a great talk at a functional programming conference by a Scala compiler developer, making the point that programming language semantics should be specified at the AST level, with syntax entirely up to the user's whim.

    I consider this to be both totally sensible and completely impractical :)

    • scotty79 a year ago

      I tried using Idea for Scala 3 where indents are meaningful. I prefer size 4 tabs for indents. There were four knobs for adjusting indents and until I adjusted all of them the IDE was messing up my indents in subtle ways. If leading editors have trouble abstracting indentation from its textual representation I have zero hopes for them being able abstract even such simple element of AST as a block.

      • sanderjd a year ago

        Agreed. I think it would require a lot of work on tooling to make this idea work, for fairly little gain. I still think it's an elegant idea though.

        • scotty79 a year ago

          I think we might get it implemented some day but it's gonna be approached from the side of visual programming. Those systems just need to relax a bit and allow some structure inside their little rectangles. Then the internal structure will be able to easily have multiple views and editors.

kazinator a year ago

Please make the corner/base cases more prominent. For instance, the question obviously arises: can we have this:

  def function(x) do
  end
without writing "pass"?
1oooqooq a year ago

i imagine the thought process went "oh, indentation is much inferior to braces. i know, let me use the second worst option to braces."

relyks a year ago

Make Python look like Ruby

  • actionfromafar a year ago

    Too late for those trains, but imagine a world where GIMP would have copied the UI of Photoshop and Python the syntax of Ruby. A happy world.

  • scotty79 a year ago

    It is and it's .dopy

Keyboard Shortcuts

j
Next item
k
Previous item
o / Enter
Open selected item
?
Show this help
Esc
Close modal / clear selection