Watching the ~11 years of Python 2 to 3 adoption has been somewhat painful, and many libraries have had to offer support for both across much of that time. (And I believe at time of writing Google isn't even 100% ported to 3 yet - please correct this if I'm wrong).
I couldn't be happier that Python 3 is finally king though, and major projects like Django are able to go entirely to 3 now.
Breaking changes in languages can be important and good, but they really can affect adoption of the new version by existing users, which is tough as often major users hold some sway in the ecosystem.
JavaScript has the no breaking changes problem even worse, because you have to support (within reason) all major interpreters existing in the wild, and cannot easily change the code, so "transpiling" has become the normal.
Microsofts support lifetime for IE11 also means this isn't changing soon. Lots of old browsers in the wild (even though it has improved dramatically over last few years).
Backwards compatibility for a language means that old source code still works without having to update it, even if you can do so automatically.
Also worth pointing out that C++ has broken backwards compatibility in a very small number of cases, e.g. the `auto` keyword has changed meaning. Nobody ever used it before so it wasn't a problem in practice.
this portrayal of the python 2 to 3 migration does not represent the majority of the community! and yet we keep hearing it over and over because "large" codebases were not migrated on time.
this migration was a software engineering problem. i hope by now, people have learned to write dumb code and avoid clever tricks whenever they can. performance and clever tricks get tied to languages, OSes, & hardware versions. python is no exception!
not saying don't do them. just saying know what you are getting into.
again, the issue is not entirely due to breaking changes. but python made it too easy. c++ for example would have given people such a hard time that they wouldn't have even bothered. python's was too permissive.
i have seen the python 2.7 codebase that shipped with the original appengine. it always felt like traveling to a different world whenever the debugger gets into their code...
This led to all manner of playing fast and loose with str as byte[] usage. I've seen inline asm and even machine code in python.
Now it's the new millenium and oh look, ascii-char won't cut it as your language implementation of strings.
There's also a lot of new syntax though, which does have high costs in cases like generators, and shipping the regenerator runtime because you need your code to run everywhere.
To my knowledge they have extended syntax and added modes, but not actually made any breaking changes.
A mode was a way to avoid making breaking changes.
What I missed from my comment is not just about the engines in use, but also that all old spec confirming JavaScript should still run, in all new environments.
That is backwards compatibility.
But there's so much poorly written JS on the web that there is a chance!
Modern browsers will say 12, old browsers (IE 8 and down) will say 10.
They also changed to (at least more) deterministic ordering of object keys and I wonder how much code worked
They also changed to a (more) deterministic ordering of object keys and I wonder how much software behaved differently / broke as a consequence...
My "favourite" JS quirk is some of the IE versions where it would break if you called console.log without the console open, as it was undefined.
So many quirks, I think I may have slightly overstated the compatibility element.
They've just been careful to try to minimize the impact.
- automatically done
- isolated within a module
As long as these are true, the issues caused by breaking compatability are minimal.
It's really the Python model where it's all-or-nothing and you de-facto need to remain compatible with two releases as everyone transitions that's the problem.
This only exists in fairy land. In practice, mixing code from different versions is always the root of subtle bugs and ABI/API mess. For me in front of a big chunk of legacy code, I'd rather wrap them in a separate process and communicate with the remaining part through RPCs if possible.
That's why people have a love/hate relationship with it. The language is full of BS but the path of least resistance is to learn the ins and outs of the BS rather than to do a full rewrite of your huge codebase in a sane language. Learning the ins and outs of C++ is a one time hit, after that you can use it quite happily. So new projects get started in C++ and the cycle repeats.
I think the "we're working on it, but it's going to take a lot of time before we get something good enough" current position is the perfect middleground.
It's just that they've been convinced that generics are justified. And they have concrete proposed solutions under evaluation.
[1] https://github.com/golang/proposal/blob/master/go2-language-...
I wonder if anybody’s actually changed their mind on this, or whether the opinion of the Go team has shifted simply because it’s made up of different people now.
"Generics may well be added at some point. We don't feel an urgency for them [...] we continue to think about it. [...] The topic remains open."
These sentences have been in the FAQ since Go 1.0. Maybe people should start to believe them.
They have gathered experience with the current language, their generics design drafts have improved over the years, and now they feel like they have something that might fit.
From this blog post[1] from last year from the core Go team:
We’ve been thinking about generics since work on Go began, and we wrote and rejected our first concrete design in 2010. We wrote and rejected three more designs by the end of 2013. Four abandoned experiments, but not failed experiments, We learned from them, like we learned from check and try. Each time, we learned that the path to Go 2 is not in that exact direction, and we noticed other directions that might be interesting to explore. But by 2013 we had decided that we needed to focus on other concerns, so we put the entire topic aside for a few years.
Last year we started exploring and experimenting again, and we presented a new design, based on the idea of a contract, at Gophercon last summer. We’ve continued to experiment and simplify, and we’ve been working with programming language theory experts to understand the design better.
Overall, I am hopeful that we’re headed in a good direction
My understanding not just from the FAQ but also from reading conversation in the forums, was that they thought the feature itself had such a high potential of being misused as a crutch for bad designs that they thought not having generics was actually a feature.
And to be honest i almost agree 100% with that perception. The problem is that it leads to archaism and copy pasting that make a few lines of codes here and there look just gross (although perfectly understandable).
Plus, history has taught us that retrofitting generics to existing languages with their ecosystems can be difficult and painful (see Java and to some extend C++).
But out of curiosity what's difficult/painful about C++'s "retrofitted" generics (templates)? There's a lot to not like about templates, but as far as I know they've remained relatively unchanged and have always been just as difficult and painful (and powerful) as they are now. Are you referring to the decision to make SFINAE a de-facto way to constrain parameters?
I believe that C# also had retrofitted generics, but the reputation there doesn't seem nearly as bad. But I believe the generic containers there were intentionally not compatible with the original non-generic version.
Having used both I would take the CLR implementation any day.
https://mattwarren.org/2018/03/02/How-generics-were-added-to...
i usually see monsters when you combine generics with objects and inheritence, but you're right that since go also doesn't provide those...
i think when talking about generics in go we also mean struct accepting generic components. Not just functions
It would be very tempting with proper generic support to try to have every function work with the topmost types, just because we assume it provides more type safety. I could imagine a struct representing a "User" byte array, or other atrocities.
For the longest time the answer about generics was "There are no plans for generics. I said we're going to leave the language; we're done"
And the people who have been advocating for generics understand that have downsides. That trade of different forms and placement of complexity (the lack of generics creates complex code in duplicate code for write arounds).
I think the problem is that those features are an uphill battle with the crowd that wants performance above anything else, given the implicit allocations that they might need.
(I think join is not too tough to write, but I don't really know how you'd write split in a generic enough way for everyone to be satisfied.)
I'd like to see the Interface system more powerful. You can already do some very un-gothonic things with map[string]interface{}. I'd like to be able to compose functions already based on an interface, to implicitly implement other types, rather than spelling out each function (maybe you can already, I'm still only a few months in to Go).
I liked the concept of "try" but I agree with the peanut gallery, the syntax needs work. But many gophers (it seems) agree there should be a shorthand for "I got an error, bubble it up to the caller" aka "if err != nil {return nil, err}"
Or maybe not. In some ways, the verbosity of err != nil everywhere makes me look for ways to solve problems with less error returning.
I won't ask for any new feature for today or tomorrow. But for day after tommorow, within a longer time research horizon, I wonder whether compiled and distributed Go applications can be made to interact along the lines of interfaces within an application now. May be its my struggle with Kubernates (as a newbie) that makes me want: Can there be secure language mechanisms supporting clustering, scheduling etc in a distributed enviroment with an external agent armed only with prior package interface definitions of a deployed Go application.
Please don't sacrifice performance, and fast compilation times. That module system is looking good!
Please don't do it.
That direction of conversion, if done right, requires respecting locale which string(int) is fully unaware.
Makes sense then.
But I think it's still better than ad hoc "RTFC" standards or BFDLs.
Too network/tools oriented is also a reason. Porting C/C++ gfx libraries is not an easy job, especially multiple C/C++ gfx libraries are involved. And the performance is not high as C/C++ even if the porting is done.
This sounds like you're fighting against the language. I think a lot of developers do this. I think one should either embrace the language or find another (you did mention moving to C++).