Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Somehow, Go managed to not break old code and also fix the problem.

I think this is a good case of Python not fixing things, given that a fix exists that solves both problems.




> To ensure backwards compatibility with existing code, the new semantics will only apply in packages contained in modules that declare go 1.22 or later in their go.mod files.


Python could very easily have a similar mechanism. Hell even CMake manages to do this right, and they got "if" wrong.

The Python devs sometimes seem stubbornly attached to bugs. Another one: to reliably get Python 3 on Linux and Mac you have to run `python3`. But on Windows there's no `python3.exe`.

Will they add one? Hell no. It might confuse people or something.

Except... if you install Python from the Microsoft Store it does have `python3.exe`.


> Except... if you install Python from the Microsoft Store it does have `python3.exe`.

It's worse. If you don't install Python from the Microsoft Store there will still be a `python3.exe`. But running it just opens Microsoft Store.

Imagine how confused one could be when someone typed `python3 a.py` over a SSH session and nothing happened.


I’ve not run “python3” in years on my Mac, and I’m almost certain I never type it into Linux machines either; either I’m losing my mind, or there are some ludicrous takes in this thread.


You are surely losing your mind then. Python3 isn't something esoteric.


Entirely possible, but my point was I just type “python” and Python 3 happens. Do modern OS even come with Python 2 anymore?

I’m not claiming any mystery about Python, just disputing how the modern version is invoked.


Just tried "python" and "python3" on various Linux distros, which output respectively:

On an Ubuntu 20.04 desktop VM:

  python  => Python 2.7.18 (default, Jul  1 2022, 12:27:04)
  python3 => Python 3.8.10 (default, May 26 2023, 14:05:08)
On an Ubuntu 19.04 server:

  python  => -bash: python: command not found
  python3 => Python 3.7.5 (default, Apr 19 2020, 20:18:17)
On an Ubuntu 20.10 server:

  python  => -bash: python: command not found
  python3 => Python 3.8.10 (default, Jun  2 2021, 10:49:15)
I no longer have access to some RHEL7 and RHEL8 machines used for work recently, but if I recall correctly they do this by default:

Red Hat Enterprise Linux 7:

  python  => Some version of Python 2
  python3 => Some version of Python 3
Red Hat Enterprise Linux 8:

  python  => -bash: python: command not found # (use "python2" for Python 2)
  python3 => Some version of Python 3
You can change the default behaviour of unversioned "python" to version 2 or 3 on all the above systems, I think, so if you're running a Linux distro when "python" gets you Python 3, that configuration might have been done already.

MacOS 10.15 (Catalina) does something interesting:

  python  => WARNING: Python 2.7 is not recommended.
             This version is included in macOS for compatibility with legacy software.
             Future versions of macOS will not include Python 2.7.
             Instead, it is recommended that you transition to using 'python3' from within Terminal.
             Python 2.7.16 (default, Jun  5 2020, 22:59:21)
  python3 => Python 3.8.2 (default, Jul 14 2020, 05:39:05)


To be fair, few of these would qualify as "modern". Ubuntu 19.04 and 20.10, macOS 10.15 are all out of support, and RHEL 7 is almost ten years old and nearing the end of its support.


> I just type “python” and Python 3 happens.

That was the old way. Python now recommends against installing Python3 in a way that does that, and most modern *nix don't.


13.5.2 has /usr/bin/python3 (it’s 3.9.6) but not python2 or just python. Not sure when they changed, and YMMV with Homebrew.


I suspect my confusion stemmed from mostly invoking `ipython` which doesn't include the 3 suffix (ok, part of the confusion may've been pub-related too :D).


Depending on the package manager / distribution, 'python' might be symlinked to either Python 2 or Python 3. If you don't have Python 3 installed, it might very well point to Python 2. These days it will almost certainly prefer Python 3, but I am also in the habit of actually typing 'python3' instead of 'python' because of what I assume are issues I've had in the past.


> to reliably get Python 3 on Linux and Mac you have to run `python3`.

This is not true on my Fedora 38 system, same with current Kali linux. Although, it is the case with Ubuntu 22.04.3.


_reliably_, as in on the vast majority of machines.


Is that really python’s fault? It seems like it’s the distro making a design decision.


Well, no, not python's fault -- clearly the distros', and they probably should be blamed. But a PEP saying python2 and python3 should invoke the correct interpreter would help motivate the distributions.

(This is isomorphic to the usual victim-blaming discussion. Fault and blame vs some ability to make a difference; it's a shame that correctly pointing out a better strategy is both used to attack victims and attacked for attacking victims in the cases when that wasn't intended.)


In fact there is a PEP: https://peps.python.org/pep-0394/


What do you mean? Fedora 38 doesn't have `python3`? Are you sure?


Right, and Go has the luxury of being a compiler that generates reasonably portable binaries, while Python requires the presence of an interpreter on the system at run time.


> Python requires the presence of an interpreter on the system at run time.

A runtime interpreter does not prevent Perl to do similar things via `use 5.13`

Python has `from future` with similar abilities, it would absolutely be possible to do the same as Perl and Go and fix what needs to be fixed without breaking old code. One could design a `import 3.22` and `from 3.22 import unbroken_for` and achieve the same thing.


The same trick would work with python just as well. There’s nothing about Python’s status as an interpreter which would stop them from adding a python semantic version somewhere in each python program - either in a comment at the top of each source file or in an adjacent config file. The comment could specify the version of python’s semantics to use, which would allow people to opt in to new syntax (or opt out of changes which may break the code in the future).

Eg # py 3.4


Yeah, it would just mean that the interpreter - just like the Go compiler - would need to have the equivalent of "if version > 3.4 do this, else do that". Which is fine for a while, but I can imagine it adds a lot of complexity and edge cases to the interpreter / compiler.

Which makes me think that a Go 2.0 or Python 4 will mainly be about removing branches and edge cases from the compiler more than making backwards-incompatible language changes.


This is the direction multiple languages are moving in. Go and Rust both have something like this. (In Rust they're called "editions"). I think its inevitable that compilers get larger over time. I hope most of the time they aren't too onerous to maintain - there aren't that many spec breaking changes between versions. But if need be, I could also imagine the compiler eventually deprecating old versions if it becomes too much of an issue.

Arguably C & C++ compilers do the same thing via -std=c99 and similar flags at compile time.

Anyway, nothing about this is special or different with python. I bet the transition to python 3 would have been much smoother if scripts could have opted in (or opted out) of the new syntax without breaking compatibility.


Python probably could change this with a from __future__ import, i.e. in the same way.


By letting you specify a language version requirement? Not exactly backwards compatible (because it is explicitly not, as per the article).

Python doesn’t make breaking changes in non-major versions, so as mentioned by the upthread comment the appropriate place for this change would be in Python 4.

Given the above, I’m really not sure what point you think you’re making in that final paragraph.


This seems weird to given the number of breakages and standard library changes I seem to run into every version.


Really? I find that surprising. I don’t write as much code as I used to but I’ve been writing Python for a long time and the only standard library breakages that come to mind were during the infamous 2 -> 3 days.

What sort of problems are have you faced upgrading minor versions?


The docs are full of remarks like "removed in 3.0 and reintroduced in 3.4" or "deprecated in 3.10", etc. A big one is the removal of the loop parameter in asyncio, but a lot of asyncio internals are (still?) undergoing significant changes, as getting the shutdown behavior correct is surprisingly difficult. Personally it's never cause me any issues - I'm always on board with the changes.


Asyncio was explicitly marked as provisional for years and most of the incompatible changes happened during that time. Same goes for typing. The rest of the language is very very stable.



They do and have made relatively small ones, e.g. promoting __future__ features to default, etc.


If the change /doesn't/ break old code, it's also poorly justified.

It means code doesn't care about the issue being addressed.

The feature is only justified if it changes existing code, such that bugs you didn't even know about are fixed.

I.e. people read about the issue, investigate their code bases and go, oh hey, we actually have a latent bug here which the change will fix.


There's a second motivation in my opinion. Code might work today without the change, but it could be because the author originally wrote buggy code, caught it in testing, and had to waste time tracking it down and understanding nuances that don't need to be there. Once they figured that out, they implemented an ugly workaround (adding an extra function parameter to a goroutine or shadowing the loop variable with n := n).

Good language designers want to avoid both wasting developer's time and requiring ugly workarounds. Making a change that does both, especially if it doesn't break old code, is great imo.


Whichever way you implement the semantics of the loop variable, the developer has to understand the nuances, don't you think? And those nuances have to be there; all you can do is replace them with other nuances.

If a fresh variable i is bound for each iteration, then an i++ statement in the body will not have the intended effect of generating an extra increment that skips an iteration.

If you want the other semantics, whichever one that is, the workaround is ugly.


I think you can choose nuances that minimize unexpected behavior in practice, and I think the go team did a good job here.


New code written today will use the new version and have the correct behavior from day 1.

Old code that is maintained will eventually be upgraded, which yes does come with work sometimes where you realize your code works on version X but not version X+10 and you do a combination of tests and reading patch notes to see what changed.


There is no "correct" behavior here; either one is a valid choice that can be documented and that programs can rely on and exploit.

Code doesn't care about when it's written, only what you run it on, and with what compatibility options.

E.g. one possibility is that ten-year-old code that wrongly assumed the opposite behavior, and has a bug, will start to work correctly on the altered implementation.




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: