Live data from Hacker News

Making a Python interpreter in 1024 bytes

austinhenley.com

81–90 of 120 posts

Re: Making a Python interpreter in 1024 bytes

#81
post #64

Earlier quoted context omitted.

Surely tabs are only ambiguous if one considers the point of indentation to be to align things visually in relation to each other, as opposed to just being, y'know, indented. Besides, I'm sure many people would look at your Scheme snippet and argue that it's not really about indentation as much as alignment of the subforms, because in a Lisp those two things are basically equivalent, and that the distinction between…

> the use of "tabs for indentation, spaces for alignment" is fairly popular although I don't frankly know if many editors actually support that. It all works swimmingly until you introduce a nested scope (indentation, tabs) in the middle of an aligned scope (spaces). At that point it still works in the sense that everything is correctly aligned however depending on the editor the tabs might not all have the same widt…

The other problem I've personally seen with "tabs for indentation, spaces for alignment" is when your editor destroys your tab-space mix when it adjusts the indentation. I've personally seen an editor, I believe VS Code but I don't remember for certain (EDIT: on second thought it was probably Visual Studio, as my memory is placing me in an office I worked in around 2010 or 2011, before VS Code was created), turn a `...` line into `...` when I intended or dedented it as part of a code block. I.e., I added or removed an `if:`, highlighted a section of code, and pressed the Tab or Shift-Tab shortcuts. And boom, that section of code was no longer in correct "tabs for indentation, spaces for alignment" syntax: the editor had converted a certain number of alignment spaces into tabs.

That was one of the moments that made me move away from tab characters in all circumstances. Because the only way to prevent that sort of thing from happening would be either to fix the editor bug (which I don't have time to do), or to turn on visible whitespace and pay close attention to whitespace every time I make an indentation change, knowing that the editor will sometimes do the wrong thing. I don't want to have to pay close attention to whitespace, and the only way I've found not to have to pay close attention is to either never align things at all, or never use tab characters. Tabs for indentation and spaces for alignment works great in theory, but in practice I have found I can't trust major editors to handle it right.

Re: Making a Python interpreter in 1024 bytes

#82
post #51

Earlier quoted context omitted.

Got it. You're looking at the problem from the other direction. Yes, tabs are unambiguous if they're the only thing used for indentation. It's when some people use tabs and others use spaces that ambiguity arises. But there are other cases where the variable-width nature of tabs can create ambiguity all by itself. Take this example from R7RS small: (cond ((> 3 3) ’greater) (( If you write it like this, a smart editor…

> It's when some people use tabs and others use spaces that ambiguity arises. I don't think so? Assuming we're talking about significant whitespace here and assuming we're maintaining a consistent prefix within a given block then AFAICT there is never any ambiguity. To argue otherwise it seems to me that one of two things must be true. It could be that spaces are equally ambiguous because in theory you can use any nu…

The counterexample I've personally seen is multiple people editing the same file with different editors. The first person has his editor configured to indent with tab characters, and he writes Python code like this:

    def example():
    if True:
    do_something()
Now a second guy edits the file. His editor is configured to indent with spaces. He adds `do_something_else()`, and doesn't notice that the code block no longer has a consistent prefix:

    def example():
    if True:
    do_something()
            do_something_else()
Notice that because I've used five characters to type ``, it is already visually obvious that this is incorrectly indented. But that wasn't obvious to guy number two, because this is what he saw on his screen:

    def example():
        if True:
            do_something()
            do_something_else()
The compiler itself isn't per se concerning itself with how different editors have chosen to display tab characters. But in practice, it has to decide "is the do_something_else() line part of the `if True` block, or not?" And so it has to have some opinion on tab characters. Here, that opinion will be "Inconsistent mixing of tabs and spaces in same file, impossible to know programmer intent, refusing to guess; raise TabError exception here".

The use of .editorconfig files should, in theory, solve this. But just yesterday I had another file, thankfully one where whitespace was not significant. The .editorconfig file said "Indent with tab characters", so my editor, when I opened a new line, indented it with tab characters. But the file was actually indented with spaces, and nobody had fixed the .editorconfig file to say "indent with tab characters... except for this file which is indented with spaces".

Editor misconfiguration in both cases. Not strictly the couterexamples you were asking about. But the Python example, although made up, is reflective of actual situations I've seen. People with different editors editing a file, not paying attention to whitespace, and ending up with ambiguity where the width of a tab character would actually make a difference to whether a line visually appears lined up with its indentation block or a different one.

Tabs are great for indentation in theory. In practice, I've personally seen more pain than gain from files that used them.

Re: Making a Python interpreter in 1024 bytes

#83
post #30
post #24

The code makes me smile, because it's nasty . This isn't like C4, a tiny but complete C compiler which does error checking on its subset. Instead, this is worse than Sector C, which takes every shortcut and just plain assumes everything in the source is right. This "Python" just plain assumes for keywords: Any "f" is a "for [x] in range[y]" (exactly that, no other for's). Any "w" is a "while". Any "i" is an "if". Any…

If you are willing to sacrifice performance, you can implement dicts via linear lookup in much less code than a proper hash table.

Because Python dicts guarantee iteration order is the same as insertion order (https://docs.python.org/3.7/library/stdtypes.html#typesmappi...) Python dicts aren’t just proper hash tables.

Because of that it wouldn’t surprise me much if that sped up some standard benchmarks, for example ones parsing lots of small json objects into dictionaries.

Re: Making a Python interpreter in 1024 bytes

#84
post #67
post #24

The code makes me smile, because it's nasty . This isn't like C4, a tiny but complete C compiler which does error checking on its subset. Instead, this is worse than Sector C, which takes every shortcut and just plain assumes everything in the source is right. This "Python" just plain assumes for keywords: Any "f" is a "for [x] in range[y]" (exactly that, no other for's). Any "w" is a "while". Any "i" is an "if". Any…

As they say in TDD, write a test, then write the simplest code that will make it pass. Clearly supporting multiple functions starting with 'p' would be overengineering.

By that standard, this is totally over-engineered. Just hardcode it.

Re: Making a Python interpreter in 1024 bytes

#85
post #24

The code makes me smile, because it's nasty . This isn't like C4, a tiny but complete C compiler which does error checking on its subset. Instead, this is worse than Sector C, which takes every shortcut and just plain assumes everything in the source is right. This "Python" just plain assumes for keywords: Any "f" is a "for [x] in range[y]" (exactly that, no other for's). Any "w" is a "while". Any "i" is an "if". Any…

Reminds me of the good 'ol Apple II BASIC. You can name your variables whatever you want, but only the first two letters matter.

Re: Making a Python interpreter in 1024 bytes

#86
post #53

Earlier quoted context omitted.

Agreed... but see my Lisp example in https://news.ycombinator.com/item?id=49593406 for a place where tabs end up unavoidably ambiguous. Because in that `cond` example the tabs look like they're used for indentation, but they're actually being used for alignment, something that falls more under typesetting than under indentation. A smart editor that has read the Lisp code (note that I'm using "read" in its Lisp meanin…

The cond example commits a sin (see my other reply), in the F# example tabs (were they permitted) would introduce no ambiguity if used solely to communicate indentation, and the only change I would make to the F# example were I formatting it myself would be to also align the `=` characters. Actually that supposedly bad style is more or less exactly how I write nix expressions (as a matter of practicality I do not use…

I agree that the cond example is committing the sin of trying to align with tabs. I wrote it because I had misunderstood something you were saying. But also, I've personally seen situations like this. I was working in a team whose indentation convention was "one tab character per indent level", and I had written some C# code like this:

    var result = someObject.SomeMethod(param1, param2,
                                       param3, param4);
And then to my horror I noticed that the editor (earlier I said it was VS Code, but thinking back I think it was actually Visual Studio) had produced this monstrosity:

    var result = someObject.SomeMethod(param1, param2,
    param3, param4);
(Actual number of tabs was different, of course, and I believe it was followed at the end by a space or two, whereas my example happened to line up without needing an extra space character).

I know not to do that. The editor did it anyway, and if I hadn't been paying close attention to whitespace I might not have caught it.

The editor could have been smart enough to parse the code into an AST, notice that param3 and param4 were part of a parameter group, and said "I will use tab characters equal to the indentation of `var result`, then spaces thereafter". It didn't. I had to edit the call to look like this:

    var result = someObject.SomeMethod(
        param1, param2, param3, param4
    );
And then I was safe from the editor trying to align things with tab characters.

If my memory is right about which office I was working in when I saw the editor do that to my code, then it was more than a decade ago, probably around 2010 or 2011. It's possible that the modern version of that editor has improved its handling, and would have correctly aligned param3 with spaces. I haven't checked recently. Maybe at some point I will, and report my findings.

Re: Making a Python interpreter in 1024 bytes

#87
post #60
post #40

I don't understand the point of this. If they wanted to make a Python interpreter, why didn't they just ask an AI to do it?

Why do anything. Why even do the AI version of this. Probably curiosity. If there's an AI version of code golfing, I'd be curious to see it. Maybe they golf worse or much better than us meat bags.

Just ask your preferred AI tool if it can shrink the OP's code while keeping the same functionality; I suspect it could. At this point, LLMs are probably no worse than an average human at sizecoding or targeting resource-constrained platforms in general; https://news.ycombinator.com/item?id=49226923 is a recent example of how powerful they've become.

Re: Making a Python interpreter in 1024 bytes

#88
post #24

The code makes me smile, because it's nasty . This isn't like C4, a tiny but complete C compiler which does error checking on its subset. Instead, this is worse than Sector C, which takes every shortcut and just plain assumes everything in the source is right. This "Python" just plain assumes for keywords: Any "f" is a "for [x] in range[y]" (exactly that, no other for's). Any "w" is a "while". Any "i" is an "if". Any…

Reminds me of the good 'ol Apple II BASIC. You can name your variables whatever you want, but only the first two letters matter.

Two letters is luxury, when most BASIC interpreters in those days only recognised 1-letter variables.

Re: Making a Python interpreter in 1024 bytes

#90
But to be honest, I wonder what is the smallest interpretable and practical Turing Complete VM? I would argue that implementing a brainfuck that we lower Python interpreter to, or even say like an interpreter untyped lambda calculus or SKI combinator would be very useful, especially for the hardware bootstrapping.

I'm talking about things like SectorLisp https://justine.lol/sectorlisp/

Post reply on HN