Like the author, I find myself going more for cross-platform Python one-offs and personal scripts for both work and home and ditching Go. I just wish Python typechecking weren't the shitshow it is. Looking forward to ty, pyrefly, etc. to improve the situation a bit
Speed is one thing, the type system itself is another thing, you are basically guaranteed to hit like 5-10 issues with python's weird type system before you start grasping some of the oddities
I wouldn't describe Python type checking as a shit-show. pyright is pretty much perfect. One nit against it perhaps is that it doesn't support non-standard typing constructs like mypy does (for Django etc). That's an intentional decision on the maintainer's part. And I'm glad he made that decision because that spurned efforts to make the standard typing constructs more expressive.
I'm also looking forward to the maturity of Rust-based type checkers, but solely because one can almost always benefit from an order of magnitude improvement in speed of type checking, not because Python type-checking is a "shit show".
I do grant you that for outsiders, the fact that the type checker from the Python organization itself is actually a second rate type checker (except for when one uses Django, etc, and then it becomes first-rate) is confusing.
I've never particularly liked go for cross platform code anyway. I've always found it pretty tightly wedded to Unix. Python has its fair share of issues on windows aswell though, I've been stuck debugging weird .DLL issues with libraries for far too long in my life.
Strangely, I've found myself building personal cross platform apps in game engines because of that.
I do hope the community will converge on one type checker like ty. The fact that multiple type checkers exist is really hindering to the language as a whole.
I have the same issue plus unnecessary refactorings (that break functionality). it doesn't matter if I write a whole paragraph in the chat or the prompt explaining I don't want it to change anything else apart from what is required to fulfill my very specific request. It will just go rogue and massacre the entirety of the file.
This has also been my biggest gripe with Gemini 2.5 Pro. While it is fantastic at one-shotting major new features, when wanting to make smaller iterative changes, it always does big refactors at the same time. I haven't found a way to change that behavior through changes in my prompts.
Claude 3.7 Sonnet is much more restrained and does smaller changes.
This exact problem is something I’m hoping to fix with a tool that parses the source to AST and then has the LLM write code to modify the AST (which you then run to get your changes) rather than output code directly.
I’ve started in a narrow niche of python/flask webapps and constrained to that stack for now, but if you’re interested I’ve just opened it for signups: https://codeplusequalsai.com
Would love feedback! Especially if you see promising results in not getting huge refactors out of small change requests!
Interesting idea. But LLMs are trained on vast amount of "code as text" and tiny fraction of "code as AST"; wouldn't that significantly hurt the result quality?
Thanks and yeah that is a concern; however I have been getting quite good results from this AST approach, at least for building medium-complexity webapps. On the other hand though, this wasn't always true...the only OpenAI model that really works well is o3 series. Older models do write AST code but fail to do a good job because of the exact issue you mention, I suspect!
Having the LLM modify the AST seems like a great idea. Constraining an LLM to only generate valid code would be super interesting too. Hope this works out!
Asking it explicitly once (not necessarily every new prompt in context) to keep output minimal and strive to do nothing more than it is told works for me.
Really? I haven't tried Gemini 2.5 yet, but my main complaint with Claude 3.7 is this exact behavior - creating 200+ line diffs when I asked it to fix one function.
This is generally controllable with prompting. I usually include something like, “be excessively cautious and conservative in refactoring, only implementing the desired changes” to avoid.
I've used it via Google's own AI studio and via my own library/program using the API and finally via Aider. All of them lead to the same outcome, large chunks of changes to a lot of unrelated things ("helpful" refactors that I didn't ask for) and tons of unnecessary comments everywhere (like those comments you ask junior devs to stop making). No amount of prompting seems to address either problems.
If anyone wants to experiment with this lib + yaegi interpreter I put up a trivial example at [1]. Composing scripts with LSP support and such might be doable with a proper abstraction, in the example a main package with a main function is required. Interpreting might break some functionality for `script` so perhaps rerunning their test suite with yaegi is a good idea if you get serious about this.
My current approach has been setting GOBIN to a local project bin via direnv and go installing bins there. install commands themselves are cached by me with a naive checksum check for the install script itself when I run my commands. Therefore all `go install`s run in parallel if I edit the install script, and go decides what to reinstall or not. At this point I don't feel it's worth migrating to `go tool` having this setup, we'll see when it's stable
if "pallets of H100s shipping that were worth 100s of millions each pallet." and "12+ months of back orders with Nvidia alone" are not public information, then in my mind that is insider trading, especially those backorders.
This hasn't been the case since go modules exist, if I understand your issue correctly: https://go.dev/blog/using-go-modules. You can additionally vendor each project's dependencies
I love dbeaver, but there's a thing that bugs me every single time. I constantly recreate databases during development, so I have to disconnect databases, then connect, then go dig inside the database tree to where I was before recreating. Am I missing some feature I don't know about?
On the other hand, I advise you NOT to use this kind of library and write simple, fast go code most of the time, with the occasional generics helper. Why the hell would I clutter my code with, for example: https://github.com/samber/lo?tab=readme-ov-file#fromentries-...
I've had many cases in the past (not in go) where I've had to make use of that exact same function (in typescript, in F#, and in C#). it is actually quite useful when doing any amount of data manipulation (map/filter/reduce chain that often ends up into a list of key-value pairs, which then get turned into a map/dictionary of sorts).
At least in my job(s over the years), turning a flat list of db records into a more complex, nested (potentially on multiple levels) data structure before handing it off to the front-end is a very common. I've seen it done with "simple, fast code" (although not in go specifically, but in other languages), but it very quickly turned into huge messes of of long nested for loops and was very difficult to read. LINQ, Lodash, java's streams... I sincerely can't understand how go developers live without them. They make me a lot more productive both at reading and writing the code.
Part of the issue is that Go has a variety of design choices / limitations that conspire to produce different design patterns in this area than what you might see with e.g. Java.
For example: let's say we want to implement something akin to Java's Comparator interface.
Java allows interfaces to be extended with default implementations. It also allows methods to specify their own generics separate from the entire interface / class.
Thus the "comparing()" method can take in a Function<T, U> that extracts a value of type U from T that is used for comparison purposes. The return type is Comparator<T>.
(Generics simplified a bit, there are other overloads, etc.)
There's also thenComparing(), which allows chaining Comparator instances and / or chaining Function<T, U>.
As a consequence, one can use .thenComparing() to build up a Comparator from the fields on a class pretty quickly. Especially with lambda syntax.
Go doesn't support methods having different type parameters than the overall interface / struct.
Go also doesn't have default implementations. It doesn't allow function or method overloading.
Go does have first class functions, however.
To build the equivalent capability, you'd most likely build everything around a comparison function (func[T any](a, b T) int) and write a bunch of functions to glue them together / handle useful operations.
That impacts the readability of a long chain of calls, especially since Go doesn't have a lambda syntax to make things a bit tighter.
Getting rid of the limitation on method-level generics would make this _significantly_ more ergonomic.
You wouldn't write that exact function. You'd have some complicated pipeline that ended up in a map; and it might be easier to follow the logic using map / filter / fromentries.
I strongly agree. Map / filter isn't included, but a fair number of the various utilities are included in the standard library in the `slices` and `maps` packages.
`context` also helps solve a bunch of the channel related use cases in a more elegant (IMO) way.
There are only a handful of things in that package I wish were included, such as "Keys()" on a map.
Funny how I get the opposite result with google, which ignores my quoted text and tries to feed me whatever it believes I want to look up, instead of the exact matches. Especially annoying for code searches.
Looks like someone working more than one job. However, it's weird that they're doing nothing from the get-go. Don't you have probation in your company?
reply