Learning Go as a Python Developer: The Good and the Bad
new.pythonforengineers.com
new.pythonforengineers.com
wat? Pretty sure you can use == in requirements.txt
Also, its very possible, and quite easy to just include the code for the library in your package, which effectively "locks in" the version. We did this all the time when building AWS lambda deployments.
Sounds like this guy needs to finish learning Python before he learns something else.
From what you suggested, to containerizing things with something like Docker, there are ways to make Python more easily distributable.
packageA==1.0.0 depends itself on packageB
Therefore, you can find yourself with a different set of deps. Had a bug like this once.
I never could get poetry to work right; it's configs are sort of messy. pip freeze > requirements is built in. The only thing it doesn't pin is the python version itself.
Bad non-solutions being built in are a bad thing.
SciPy is a bastard on macs for example.
You can do you want you suggest, but it's an operational pain in the ass. You need to maintain two files, the actual requirements.txt and the `pip freeze` one that locks the environment. And you better never `pip install` anything by hand or you'll capture random packages in your frozen file, or else always take care to create your frozen file in a fresh virtualenv. And if you don't want to install your dev packages into the production environment, then you need to maintain two requirements.txt and two of those frozen files.
The author mentions Poetry which does solve these issues with a nice interface.
Virtual Environment gets on my way. Looking at you Jupyter notebook.
The whole point of GP is that python lacks a native sane packaging system, which I agree.
I agree that it makes life more confusing for newbies, though.
something like poetry's approach is the right one here; you need a list of core dependencies (not derived ones), you need a solver for when anything changes to find a new set of viable versions, and you need a lock file of some sort to uniquely & reproducible construct an environment.
I haven’t had to use pip in a long time. Just like I haven’t had to use `go get` in a while.
I mean it’s not the most rock solid abstraction, but introducing sane package management in an OSS environment with a decade plus of history is very hard. Against that background, they are doing pretty well, IMO.
This only works if installing on exactly the same os and architecture. It can also make the installer for your quick little command line tool hundreds of megabytes.
That being said packing up the python interpreter and all dependencies is the approach I ended up using when shipping non-trivial python applications in the past.
- poetry
- "Just pin the dependencies and use Docker"
- pip freeze
- Vendoring in dependency code
- pipreqs
- virtualenv
This is simply a mess and it's handled much better in other languages. I manage a small agency team and there are some weeks where I feel like we need a full-time devops person to just help resolve environment issues with Python projects around the team.
Solving environment |
Solving environment /
Solving environment -
Solving environment \
Solving environment |
...
One day it takes 10 seconds, next month it takes 10 minutes, and the month after that it takes 30 minutes and then fails entirely.Since you specifically mentioned 2021 instead of 2022, I half suspect you had the same experience.
To answer your question: yes, we were using conda-forge, and then when it stopped building we moved to a mix of conda and a critical subchannel, and then a major GIS library broke on conda and stayed that way for months so we threw in the towel and just used pip + a few touch-up scripts. Now that everyone else has followed suit, pip is the place where things "just work" so now we just use pip, no touchups required.
After an few hours or so of not making much progress in AOC day 1 I just gave up and never continued learning Go.
Of course the answer to these questions could be anything but to me it feels like attacks on Python's package management are usually cheap shots on a much much more complicated problem domain than the "complainers" are typically aware of.
¯\_(ツ)_/¯
Your comment hints that you are feeling personally attacked when Python is criticized. Friendly unsolicited advice: don't do that, it's not healthy for you.
Python is a relic. Its popularity and integration with super-strong C/C++ libraries has been carrying it for at least the last 5 years, if not 10. There's no mystery: it's a network effect. Quality is irrelevant when something is popular.
And yes I used Python. Hated it every time. I guess I have to thank Python for learning bash scripting well. I still ended up wasting less time.
Use Python if it's useful for you, obviously. To me though the writing is on the wall -- it's on its loooong and painful (due to people being in denial) way out.
EDIT: I don't "hate"; it was a figure of speech. Our work has no place for such emotions. I simply get "sick of" (read: become weary of) something being preached as good when it clearly is not, at least in purely technical terms. And the "hate" is not at all unfounded. Choosing to ignore what doesn't conform to your view is not an argument.
I am not feeling personally attacked (I am not married to Python), I am mostly just tired of reading the same unproductive type of complaints over and over again. This attitude is not unique to Python's situation, but actually is typical to our industry. It makes me want to find a different job, on some days.
The community is trying to improve the situation but there is no way to erase Python's history. So it's always going to continue to look messy if you keep looking back. The complaint is unproductive, or in other words, not constructive.
You might not be married to Python but it sure looks that way for many others. I switched main languages no less than 4 times in my career and each time it was an objective improvement.
The thing that kind of makes me look down on other programmers is them refusing to move on.
I still dabble in all of them. Who knows when I will move on to the next. Rust looks nice. I tried go.
But they do not yet provide any of the tools/libraries I need for my work. That's how I've always selected my programming language.
So I would first need to invent the universe before I can create valuable things. Instead I will just wait until their ecosystems mature a little more.
I will end the discussion here though. Thanks for the response!
As a rule elixir devs don't do system level dependencies, probably because of lessons learned from the hell scape that is python (and Ruby)
Yesterday I onboarded a coworker onto the elixir project, he instinctively put it into a docker container. I laughed and just told him to run it bare (he runs macos, I run Linux). There were 0 problems out of the box except I forgot the npm incantations to load up the frontend libraries.
- Can you resolve precompiled GPU dependencies with system managed CUDA driver versions?
- Are there packages that can convert PDF to PNG without system dependencies?
- Can you run a Qt GUI app on CI without needing to do any additional system setup?
With regards to cross compilation tools like burrito, that's neat! But Python is not a compiled language.
2) not that I can find for that specific task but the typical strategy is to download (or compile) a binary, drop it into a {project-dependency}[0]-local "private assets" directory, and call out the binary. This is for example how I embed zig pl into elixir (see "zigler") without system-level dependencies. Setting this up is about 40 lines of code.
3) wx is preferred in the ecosystem over qt, but this (and openssl) are the two biggies in terms of "needs system deps", though it's possible to run without wx.
For native graphics, elixir is treading towards glfw, which doesn't have widgets, but from what I hear there are very few if any gotchas in terms of using it.
I bring up cross-compilation, because burrito allows you to cross-compile natively implemented code, e.g. bcrypt that's in a library. So libraries that need c-FFI typically don't ship binaries, they compile at build time. Burrito binds "the correct" architecture into the c-flags and enables you to cross compile c-FFI stuff, so you don't have a system level dependency.
[0] not that this has happened, but two dependencies in the same project could download different versions of the same binary and not collide with each other.
Granted, you don't get a nice executable, but it's still miles ahead of C++ (people literally put their code into header files so you don't have to link to a library), and even modern languages like rust (stuff is always broken, or I have some incompatible version, even when it builds it doesn't work)
By the way if you're a Python user, Nim is worth checking out. It's compiled, fast and very low fuss kind of language that looks a lot like Python.
Been working on and off with Rust for the last 3 years, never happened to me once -- with the exception of the Tokio async runtime that has breaking changes between versions. Everything else always worked on the first try (checked with tests, too).
Comparing Python with C++ doesn't make do argument any favours, and neither does stretching a single Rust accident to mean the ecosystem is bad.
For crates that don't follow semver (which I'm fairly certain I've encountered zero times) you can pin a specific exact version.
I have rarely encountered issues in rust. Most rust crates stick to semver so you know when there will be a breaking change. My rust experience with Cargo can only be described as problem free(though I only develop for x86 linux).
As for pip freeze and virtualenv things start to fall apart especially quickly when you require various C/C++ dependencies (which in various parts of the ecosystem is a lot) as well as different python versions (if you are supporting any kind of legacy software). This is also assuming other people working on the same project have the same python yadda yadda the list goes on, its not great.
Yes 100 times. That can be incredibly frustrating. During the last year I've used a large (and rapidly evolving) C++ project (with many foss C/C++ dependencies) with Python bindings. We've collectively wasted sooo many hours on dependency issues in the team.
Long compilation times contribute considerably to slow down the feedback loop when debugging the issues.
I will say, though, that this only accounts for times where you’re not upgrading dependencies. Where I’ve always run into issues in Python was when I decided to upgrade a dependency and eventually trigger some impossible mess.
If A and B both depend on different versions of C, then both versions of C are installed and A/B see the version they want.
I can't see a reason why Go would be different.
In Elixir I can do `mix hex.outdated` in any project, no matter who wrote it, and it'll tell me very quickly what's safe to update and link to a diff of all the code changes. It's night and day.
Thankfully, it's getting gradually better with poetry, but it's still quite clunky compared to what you get elsewhere. I noticed lately for instance that the silent flag is broken, and there's apparently no way to prevent it from spamming 10k lines of progress bars in the CI logs. There's an issue on Github, lost in a sea of 916 other open issues...
It's a very good argument.
This Fortran vs Python example is worth reading: https://cerfacs.fr/coop/fortran-vs-python
- Pip freeze just pins all dependencies at once to requirements.txt
- I don't know what "vendoring in dependency code" means
- I've never used pipreqs in my life (and 80% of my work has been in Python)
- Virtualenvs are just a convenient way to keep project runtimes separated
And for 90% of Python projects in existence the following is sufficient (assuming Python3 is installed):
- python -m venv .venv
- source .venv/bin/activate
- pip install -r requirements.txt
That's it. And all of that requires a single dependency: Python. Could it be better? Sure. But to call that a "mess" is an exaggeration.
pyenv install 3.9.47
pyenv virtualenv 3.9.47 my app
git clone …/myapp
cd …/myapp
pyenv local myapp
pip install -r requirements.txt
Is it annoying, maybe, but I normally don’t trust system deps for anything.>- source .venv/bin/activate
If those two steps were automatic like in node.js we'd literally have 99% less problems.
What you described are multiple tools that also target different areas:
> - poetry
from what you listed this seems like the only tool that actually takes care of dependency management
> - "Just pin the dependencies and use Docker"
this is standard fallback for all languages when people are lazy and don't want to figure out how to handle the dependencies
> - pip freeze
all this does it just lists currently installed packages in a form that can be automatically read by pip
> - Vendoring in dependency code
this again is just a way that applies to all languages, and it is still necessary even if there's a robust dependency management as there are some cases where bundling everything together is preferred
> - pipreqs
this is just a tool that scans your code and tells you what dependencies you are using. You are really lost if you need a tool to tell you what packages is your application is using, but I suppose it can be useful for one offs if you inherit some python code that wasn't using any dependence management.
> - virtualenv
this is just a method to have dependencies installed locally in project directory instead per system. This was created especially for development (although it can be used for deployment as well) as people started working on multiple services with different dependencies. It's now included in python so it's more like a feature of the language.
Package management is pretty much a solved problem, no matter how old is your language. It smells to an outsider like me like a lot of bike-shedding and not enough pragmatism is going on in Python land over this issue. Has a new BDFL stepped up after Guido left?
Not sure anyone was asking for that, unlike a fix for packaging issues.
And worse, effects code maintainability - if you need that assignment higher up, you're now editing the if statement, adding an assignment, plus whatever your interstitial code is.
Python doesn't have block scoping so the argument for it is weak.
> And worse, effects code maintainability - if you need that assignment higher up, you're now editing the if statement, adding an assignment, plus whatever your interstitial code is.
How is that different than variables declared without the walrus operator? If you declare a variable with the walrus operator and decide to move its declaration you can still continue to reference that variable in the same spot, just like any other variable. Do you have an example you can share to demonstrate this? I'm not sure I understand what you mean.
> Python doesn't have block scoping so the argument for it is weak.
The walrus operator another way to define variables, not change how they behave. It's just another addition to the "pythonic" way of coding. It's helped me to write more concise and even clearer code. I suggest reading the Effective Python link I provided for some examples of how you can benefit from it.
# some other code
if determined_value := some_function_call():
do_action(determined_value)
and then I change it to this: # some other code
determined_value = some_function_call()
logger.info("Determined value was %s", determined_value)
validate(determined_value)
if determined_value:
do_action(determined_value)
and determined_value is a reasonably expensive operation (at the very least I would never want to redundantly do it twice) - then in this case my diff for this looks like: --- <unnamed>
+++ <unnamed>
@@ -1,5 +1,8 @@
-
# some other code
-if determined_value := some_function_call():
+determined_value = some_function_call()
+logger.info("Determined value was %s", determined_value)
+validate(determined_value)
+
+if determined_value:
do_action(determined_value)
whereas if I wrote it without walrus originally: --- <unnamed>
+++ <unnamed>
@@ -1,5 +1,8 @@
# some other code
determined_value = some_function_call()
+logger.info("Determined value was %s", determined_value)
+validate(determined_value)
+
if determined_value:
do_action(determined_value)
then the diff is easier to read, and the intent is clearer because diff can simply infer that what's happening is the semantic addition of two lines.Code is read more then it's written, and changed more then originally created, and making the change case clearer makes sense.
This is such a pedantic, non-issue I don't even know why I'm bothering acknowledging it.
while (n := s.read(buffer)) != 0:
#do something with first n bytes of buffer
Without the walrus operator you either have to duplicate the read operation before the loop and at the end of the loop, or use while True with a break if n is zero. Both of which are ugly IMO.I think also a lot of issues with packaging is ironically because of PyPA that supposed to work on a standard, but in reality instead of embracing and promoting something that works they just pushes half-assed solutions because author is one of the members. Kind of like they were pushing failed Pipenv "for humans". Seems like Poetry is generally popular and devs are happy with it, so of course PyPA started pushing their own Hatch project, because python packaging was finally getting too straight forward.
I think Python would benefit as a whole if PyPA was just dissolved.
STRONG agree. And I hate the cult of personality that was previously (still?) strong.
Reading the comment thread it's not immediately clear what the answer is - it seems implied that the proper way is using Poetry, is that the case?
See https://imgs.xkcd.com/comics/python_environment_2x.png
Or sometime the computer is haunted and my colleague had problems installing tensorflow. To this day he has no working tensorflow.
Please note I never used tensorflow on that computer in fact I never used tensorflow, but this is my experience: https://gist.github.com/takeda/89ec29501b6e8641415668f22f3e9...
It succeeded after first try.
I do see that in their repo[1] they use a non standard way to build the package. They use Bazel, but that's Google for you. They never do things everyone else is doing. I'm not sure why this is Python problem rather than package problem.
They have tons of open issues around building: [2]
[1] https://github.com/tensorflow/tensorflow
[2] https://github.com/tensorflow/tensorflow/labels/type%3Abuild...
It works fine for me.
Not for him. Same package, nearly identical laptops, different outcomes.
And I as newcomer to Python, there are like four (pip, venv, brew, conda) cli APIs that I had to learn just to get working on some Python file.
> all this does it just lists currently installed packages in a form that can be automatically read by pip
Are you referring to version specifiers[1] being optional or is there something more to versions that I don't understand? PEP 440 is a wall of text, maybe I should get around to reading it sometime.
[1] https://packaging.python.org/en/latest/glossary/#term-Versio...
I tried to say that from mentioned tools only poetry can be called as a dependency management.
The other tools are used for different purposes, but perhaps could be used as a piece of package management in some way. The mentioned docker and vendoring is irrelevant to Python and it even applies to Go.
These are two different things, because they do two different jobs.
It's really very simple.
if you could import numpy==3.2 it'd solve many problems.
A depends on B, C
B depends on D==1.24
C depends on D==2.02
There should in an super ideal world be no problem with this. You would just have a “linker” that inserts itself in the module loader that presents different module objects when deps ask for “D” but it hasn’t happened yet.I don't agree.
The problem is simply that Python encompasses a MUCH larger space with "package management" than most languages. It also has been around long enough to generate fairly deep dependency chains.
As a counterexample, try using rust-analyzer or rust-skia on a Beaglebone Black. Good luck. Whereas, my Python stuff runs flawlessly.
What many newer languages do is precompile the happy paths(x86, x86-64, and arm64) and then hang you out to dry if that's not what you are on.
Coming to that from hearing stories that there was supposed to be one way to do everything disenchanted me quickly.
The code itself was okay, but everything around it was a train wreck compared to every other language I’d been using (Go, Java, Ruby, Elixir, even Perl).
I attempted to get into it based on good things I’d heard online, but in the end it just wasn’t my cup of tea.
It's not automatically a problem but it certainly can become one.
You can, but one of those packages that you depend on will have a loose version spec for one of its dependencies, making your `pip install -r requirements.txt` non-deterministic.
Poetry and Pipenv solve this, though, by pinning all dependencies in a lock file.
As I understand the post, the author is saying "It sure is nice to be able to just hand off a go executable and be done with it." And I think we can agree that the Python runtime situation is far from this.
I largely control my work environment, so this isn't a huge issue for me. But I'm right at this very moment converting a "python" to "python3" in a wrapper script because the underlying code got converted to py3 and can't "import configparser". (Actually, I'm removing "python" entirely and adding a shebamg).
I've been looking at writing a small tool in Python and then porting it to Go (I don't know go, so seems like a reasonable way to approach it), because the main target of the app is my developers, who probably don't have the right Python environment set up, and I just want them to be able to use it, not give them a chore.
Pinning a dependency in requirements.txt does not pin its transitive dependencies.
This does NOT mean you should pip freeze everything into requirements.txt, because then how do you distinguish top level dependencies from transitive?
The correct answer is to use lock file. No third party tools needed (1). In Python they named it constraints and requires an extra flag to use. pip freeze > constraints.txt. Then next time pip install -r requirements.txt -c constraints.txt.
Oh, and always always always use a venv for each project. Globally installed packages is a recipe for disaster.
(1) Poetry and Pipenv are still nice additions, with nicer project declarations in pyproject.toml and to save you from remembering pip flags or forgetting activation of venvs. But they are not strictly necessary and it’s honestly just 2 commands extra without them.
the verbosity of go is the biggest hurdle for a pythonista. the thought of giving up context managers, decorators, iterators, comprehensions, exceptions, coroutines, it’s unthinkable. in comparison go is ugly. your aesthetic mind screams in protest.
write go full time. dive in. as months pass, not only will those aesthetic objections fade, your mental model from python cleanly transforms to go. go is what mypy tried to be. the cost was aesthetic changes. the benefit is worth it.
the zen of python says if it’s easy to explain it might be a good idea. this is go, and it is.
i rebuilt a reasonably sized project from python[1] to go[2] over the last few years. i also have a system that i maintain both python[3] and go[4] implementations for, sharing a test suite in python. squint at the implementations. consciously ignore aesthetic objections. they are basically the same, not very different from a python codebase with and without type annotations.
go, like python, is fantastic. use both in whatever amount works for you. don’t read about them, build with them. you won’t regret it.
1. https://github.com/nathants/cli-aws/tree/bb78e529e7d1d3f95ac...
2. https://github.com/nathants/libaws
1. https://pkg.go.dev/io#WriteCloser
i sincerely apologize to any who have been harmed, even slightly, by my oddity.
One of the things that go is really good for is the amount you can get done without having to deviate that far from the standard library. A lot of churn in updating code can be alleviated if you try to select small, well-written, well-maintained libraries in ANY language but in go this just feels way easier, I find myself thinking how to solve it using stdlib instead of trying to find out what package would suit my needs and boom everything is there already don't need to mess around too hard looking on whose shoulders to stand on only to have them walk away and do something else with their time down the line. The worst ecosystem for that is easily nodejs, blows my mind what front-end dev often looks like these days... like it being normal for a project's node_modules to hit like 500mb is just incredible to me. I'm extremely allergic to that mentality. Someone hit me up like hey I have a linux problem when i run webpack it crashes my whole system... like yo how does some corky javascript thing to minify stuff cause semaphore exhaustion to a point where your entire system goes down when you run it on a sufficiently large project, that's just horrifyingly bad. Found out if he was to continue using that tool that he had to install some graceful filesystem package for it to work. I think I managed to convince him to switch to esbuild, written of course in go. [1]
i enjoy refactoring with type safety and using gopls and ide completion instead of external docs. i used to constantly read boto3 docs in a browser, now i use gopls in my ide.
frontend dev can be sane[1] too! my default setup is a go lambda with an spa frontend inlined into an html file.
the lambda zip contains two files:
- ./main
- ./index.html.gz
These do get addressed over time but also seems to break in a new way at least a couple times a year.
But some people behave like that. They think it is someone else's job to chase down bugs in their code after they have knowingly submitted code with defects rather than deal with it immediately.
Classifying something as an error rather than a warning makes zero difference to programmers who take care not to knowingly ship defects. It only makes a difference to people who were going to ignore it and let someone else take up their slack. And to be frank: why on earth would you want to accomodate them?
Basically, the point of no-unused-imports is to reduce compilation time at scale. In the C++ ecosystem, there are lots of redundant and unused #includes. This means that a lot of the bytes sent to the C++ compiler are just thrown away. If you can guarantee that the compiler will never need to look at a source file it does not need to, you can cut down on the compilation time. For small projects, this doesn't matter much. For large projects, it does. Go was designed for large projects.
Unused imports or variables being errors is the most idiotic and overrated paper cut ever implemented in compilers. In no universe it is a good idea.
I posit there are actually no or very few bugs it catches, and in exchange it ruins people's iterative development, flow and hyperfocus states when experimenting, because poor compiler can't deal with an unused import, fix it now or else. Now we need an IDE setup to deal with this? And why the hell isn't this a feature that can be turned off?
If only I could throw the person that invented this crap into the flaming sun.
Recently, there was a bug in a second order dependency, and the version that fixed this bug was after a version that moved a function into a submodule.
So I had to make a local patch to my dependency that changed all of the imports.
Was the new interface more consistent? Yes, but could they have left a shim for backwards compatibility, or just lived with the old slightly less consistent interface? Seems to me like they could.
For instance: there is now a really cool operator that lets you do expressions where you assign a value and evaluate the result in one line. So you can write the C equivalent of something like while(buf = recv(...)) ... and it will work. Well, any program that uses this new feature won't run on anything but the most bleeding edge Python versions. Despite a program only needing a small fix to remove such expressions. It wouldn't run at all.
I think the Python interpreter needs to be 'smarter' and add the capability to automatically install parallel Python versions if it detects a package using a more recent interpreter. Would honestly solve so many issues.
I think your issue is mostly with library authors who drop older versions just so they can use a slightly more convenient syntax.
The complaint about aws-sdk-go (presumably v1) is legitimate, it seems to me that code was generated and therefore the repo can be less than ideal w/ Go. I suspect that is improved/ing in v2.
using goimports as your formatter solves the complaint about unused imports
There was a significant portion of time where python 2.x and earlier releases of Go overlapped, and finding UTF-8 safe python libraries was non-trivial. Go makes utf-8 the default. As I understand it many companies still have python2 w/o a EoL plan.
One thing I really miss about working with python is list/dict comprehensions and lambdas
In Go, the first thing you run into when making an API call is figuring out how to handle the errors, and the aws-sdk-go docs still don't give you much help there --you have to still dive into the official REST docs, or worse, the Java docs via google, and sort of guess how each exception/error code gets mapped into what Go error.
Jumping into the library code works for most Go libraries, but with the autogenerated REST bindings that is the AWS SDK, it usually isn't much more illuminating.
In Go you can at least get pretty far with a totally flat namespace and there's nothing wrong with that, up to at least 50kloc or so. That's less true in any language where files become a unit of modularization.
Not necessary anymore since Python 3.3 (released in 2012).
Code organization: https://go.dev/doc/code
Pretty much everything else you should know: https://go.dev/doc/effective_go
There's one thing I think that people getting started with this language should know and that's in the pursuit of getting the stuff you mentioned right, is making sure the reference material (blog post, book, whatever it is) you're reading is something written within the past two or three years. The official site really has enough that you need to know in order to have good knowledge coverage, but the module system beyond version 1.16 especially is something you need to get right and which a ton of old information is out of date on:
I have to say that a lot of programming paradigms are different in golang, a few parts are annoying, and some parts are "getting there" with generics.
The most annoying part if you do a lot of parsing is the golang mandated rule of what is public and what is private in a package. If you want to parse lots of JSON into a struct, mess is on you, always have to implement a custom marshal/unmarshal for it.
If you always have to implement a custom JSON marshalling method, and abuse annotations for mapping upper/lowercase properties...why was the uppercase rule mandated in the first place?
I wish golang had gone for an export keyword instead. Structs would have been so much cleaner.
The second issue I have with golang is that struct properties (as all data types) aren't nullable except via pointers, which makes consuming JSON APIs a fustercluck to deal with some times. I wish there was a nullable string data type instead of having to use dozens of helper functions.
The last issue is lack of functional ideas (as of now) but they are coming. lo is a lodash inspired library that makes a lot of things easier. [1] I hope that a lot of these helpers will at some point be part of the core libraries, so that datatypes can be easily mapped, casted and filtered.
This affected me recently, so I have sympathy for the author. Trying to upgrade an older project I had to the module system meant trying to find out how to import modules which don't have reachable URLs and were only on the GOPATH. At I hate how it forces to you create a module everytime. some point programming in Go stopped being for fun.
This seems like a compelling enough reason to stick with Python
What would be fascinating is to see some HN links to articles where the journeyman programmer went backwards in time, e.g. "Learning Fortran as a Python developer" or something like that.
Huh, Go has some of the best autodoc features of any language. Also the library assertion is insane to me. I switch back and forth from Go to Python all day and generally Go has more stable better maintained libs
On documentation, I've never seen a language community that comes with so little examples most of the time. Take any random Python library RTD, it's full of it. You can skim through said examples to understand the overall features and capabilities before you dive into the API reference. No such luck in Go: here is the bare-bones godoc, good luck!
No, it's not.
> Python needs the examples because most of the libraries have no types so you would have no idea whats happening without examples
That’s not the main reason examples and narrative explanations in documentation are useful, but if the false belief that it is has helpe to fuel the Python documentation culture, I’m not going to complain too much.
Great library indeed :D
Well here's your problem. Type safety helps you avoid avoidable bugs. Try Haskell or Scala next.
I think on Hacker News it's really fashionable to criticize Go, and this has led to a culture where Go gets significantly more negativity than it deserves.
As technologists, one of our most important jobs is to see through such fashions and judge languages/tools/technologies based on their actual merit.
While gauging sentiment about things on a forum like Hacker News is generally really helpful, it should not be the main basis of our decisions.
Java complaints go down, Go complaints go up.
- Bjarne Stroustrup
People are complaining because they care, but also because it's not good, or it's not as good as it should be.
You've got people who argue against explicit error checking and people who don't understand the important role of nil pointers and people who don't see the massive net win of garbage collection in concurrent programs, and so on.
Endlessly.
It feels like a waste of time defending the language when the people criticizing it seem to hold such a vastly different point of view. It's like trying to convince people that Natural Born Killers is a good movie or that Primus makes good music. There's an unbridgeable chasm between you and the people you're trying to convince.
... I guess you're right; I really do not understand
Go gets used for two main reasons that I've been able to observe:
1) a desire for a very specific type of concurrency 2) a desire for a fast compiled language with a minimalistic feature set that scales well to large teams.
Switching to Go from one of those languages is very much giving up a kitchen sink for a purpose-built tool. It may be the right decision under lots of different circumstances, but it doesn't directly compete with any of the languages you've mentioned because of how minimalistic it tries to be.
Overall, in fact, I think Go does something far more interesting: it's legitimately an attempt to carve out a whole separate niche for software development. Whether it's ultimately been successful there is for a different comment thread, though. :)
Very few people rewrite projects. Most change happens by new projects adopting one language over another. The fact that I hear of Python rewrites to Go is honestly amazing.
We should have a beer sometime!
I think it’s more akin to trying to talk to people about Quentin Tarantino movies. Lots of people enjoy them, many critics like his stuff, and then there’s a relatively small group of people that disparage everything he does because he isn’t ascribed to any artistic school of filmmaking and under a lot of such critical analysis his films are pop fodder. It’s not like he ever makes his movies to please critics is the thing, he’s basically a super fan that just winged it all. Many fairly sane and measured, learned critics “get” Tarantino and appreciate him for what he tries to do and all is fine there. But it won’t matter what Tarantino does going forward with the other crowd - it’s because they have diametrically opposed ideas of wtf movies even are supposed to be.
Some thoughts:
- Go singlecore is actually slower than Python (nb Stackless[0] [still stands], but not only that: graalpython/loom is even faster, much faster)
- Prototyping is always slower in most AoT-compiled languages, obviously. I'd be more convinced to try Go if it had something like Cling[1].
- CSP is (in my opinion) less palatable than Actors and makes Go feel somewhat... dated? Matter of taste?
- Go doesn't use libc which can be awkward at times.
[0] https://entitycrisis.blogspot.com/2009/11/go-vs-stackless.ht...
This is news to me. Do you have something newer then a 13 year old blog post that shows this?