Go may "feel" like Python, but it's almost nothing like Python in actual practice. It's not dynamic (and doesn't even have generics), and its error handling is dramatically different.
It _is_ like Python in practice (I use both languages all the time). That’s largely why you see it used in many of the same places as Python. It has dynamic features by way of interface{}, which is every bit as “generic” as what Python has to offer. :) But yes, the error handling is different—values vs exceptions.
I am of the view that interface{} is the worst of both worlds with regards to static/dynamic typing. Dynamically typed languages typically have type coercion and structures that make dealing with vars with unknown types easy.
However golang doesn't have that. So you get the danger of a dynamic language without the features that make powerful.
Go has those features in the reflect package (so as far as I know, Go is just as powerful as Python), but you’re right that they aren’t easy to use. If you do use them, it’s quite clear, and will be addressed in code review so you don’t have nearly as many dynamic typing bugs as Python—it’s not anywhere close.
Very dynamic code shouldn’t be easy; the happy path should encourage clear, simple code. By encouraging people to stay on the happy path, their code is more performant, maintainable, etc and it keeps the average code quality quite high across the ecosystem.
It is rare that I have had problems with dynamic typing errors in P* languages. I am of the view that that dynamic code should be one of two things.
1) Super easy. That way doing it right is trivial.
2) Impossiblely difficult so the only people who are doing it can be trusted to do it right.
To me go falls between those two. It’s real easy to say interface{} (indeed it is more difficult to make a non empty interface) but doing it in a way that is safe isn’t easy.
I don’t think expressive power is the point here. As they are both compleate languages. More it is an issue of what trade offs and comprises have been made.
I'm not sure (1) exists, probably by definition. And I certainly don't agree that Python makes it easy to "do it correctly". Our Python app has daily 500s due to typing errors. We also suffered for years because we would build magical things that we thought would work in every scenario but ended up being untestable and/or failed to consider numerous edge cases ("what happens if someone inherits from my magical class?") and/or which failed to extend properly ("oops, someone renamed this attribute and now all of our hasattr checks are broken, and the tests didn't catch it because they passed mocks"). Eventually we built a culture that mostly discourages magic/gratuitous dynamism, but it took years and we're still suffering from that legacy code.
These problems simply don't crop up in Go, or at least they're in a different ballpark in terms of frequency and severity. So yeah, Go lacks typesafe generics, but I'll make that tradeoff all day every day in exchange for the maintainability, performance, tooling, distribution, etc improvements that Go offers today. No contest.
Go has generic types the same way Python has macros, or the same way C++ templates is a functional programming language.
C has void *, writing generic code using it is hell. Enough so that people went through a lot of trouble creating C++ and later Rust to escape it.
I'd say the type casting from interface{} to whatever you assume is in there qualifies as different.
Pretty much every single aspect of these languages is different from what I can see, the only thing they have in common is included batteries, the rest is growing popularity and consequences thereof.
Yeah, I get it. It’s a little disingenuous of me to say that interface{} qualifies as generics, but I can’t quite put my finger on why it is different than Python. Neither are typesafe (although mypy supports generics, but has many other issues), but in any case typesafe generics would I think improve Go.