It seems modern statically-typed and even dynamically-typed languages all adopted this idea, except Go, where they decided zero values represent valid states always (or mostly).
A sincere question to Go programmers – what's your take on "Parse, Don't Validate"?
Go was written for programmers with little to no Computer Science knowledge, a fair bit of C/C++ experience, and zero tolerance for learning abstractions that take more than 30 seconds to explain. If you have opinions about type systems, you are not the target demographic for Go.
In larger codebases, I've noticed an emergent phenomenon that usually the T{} itself (bypassing NewT constructor) tends to be unusable anyway, hence the constructor will enforce "parse, don't validate" just well enough. Only very trivial T{} won't have a nilable private field, such as a pointer, func, or chan.
I'd say that "making zero a meaningful value" does not scale well when codebase grows.
Not speaking for all Go programmers, but I think there is a lot of merit in the idea of "making zero a meaningful value". Zero Is Initialization (ZII) is a whole philosophy that uses this idea. Also, "nil-punning" in Clojure is worth looking at. Basically, if you make "zero" a valid state for all types (the number 0, an empty array, a null pointer) then you can avoid wrapping values in Option types and design your code for the case where a block of memory is initialized to zero or zeroed out.
Only if you ignore the billion cases where it doesn't work, such that half the standard library explodes if you try to use it with zero values because they make no sense[0], special mention to reflect.Value's
> Panic: call of reflect.Value.IsZero on zero Value
And the "cool" stuff like database/sql's plethora of Null* for every single type it can support. So you're not really avoiding "wrapping values in Option types", you're instead copy/pasting ad-hoc ones all over, and have to deal with zero values in places where they have no reason to be, forced upon you by the language.
And then of course it looks even worse because... not having universal default values doesn't preclude having opt-in default values. So when that's useful and sensible your type gets a default value, and when it's not it doesn't, and that avoids having to add a check in every single method so your code doesn't go off the rail when it encounters a nonsensical zero value.
[0] or even when you might think it does, like a nil Logger or Handler
That's exactly the problem. Thanks for describing! What I find is people using linters to ensure all struct fields are initialized explicitly (e.g. https://github.com/GaijinEntertainment/go-exhaustruct), which is uhh...
I mean, yeah, you can avoid wrapping things that are optional in Option, but that doesn't make that the result is semantically meaningful. If you have a User struct with "age: 0" does that mean:
1. The user being referred to is a newborn, or:
2. Some other code, locally or on a server you're reading a response from, broke something and forgot to set the age field.
It's not just Rust that gets this (in my opinion) right, Kotlin and Swift also do this well at both a language and serialization library (kotlinx-serialization and Codable) level, but this quote from this article comparing Go and Rust is generally how I think about it:
> If you’re looking to reduce the whole discourse to “X vs Y”, let it be “serde vs crossing your fingers and hoping user input is well-formed”. It is one of the better reductions of the problem: it really is “specifying behavior that should be allowed (and rejecting everything else)” vs “manually checking that everything is fine in a thousand tiny steps”, which inevitably results in missed combinations because the human brain is not designed to hold graphs that big.
Super cool! It recommended me Scalene Python profiler (https://github.com/plasma-umass/scalene), which looks very interesting – I haven't heard about it before..
Yes! I also got bitten by format_on_save when working with legacy projects with inconsistent formatting. Given another discussion I saw, the maintainers didn't think about this use case much, i.e. "why don't you want to have a proper formatting?". It can be turned off now, so not sure if they'll change the default.
It's like Excel changing .csv files after opening them so a simple load/save cycle can corrupt the file and your original copy is nowhere to be found.
I imagine the damage is smaller in case of auto-formatter but still - not something I would expect a program to do to my file in a simple "open file - close the program" cycle.
Hmm, I found Zed to consume battery less than VScode on my M1 MBP. It's ~100 vs ~200 12h power consumption on average according to Activity Monitor. Do you compare it to VSCode?
It's unlikely that anyone will see this but I tried using Zed again after not using it for a while and the power draw is significantly lower! So I don't think it is related to those issues after all. I don't see much of a difference between Zed and VSCode in the amount of energy they use, but Zed is noticeably snappier (and not owned by MSFT)
That's a good idea. I considered VSCodium but the issue is that I used VSCode's proprietary extensions such as Pylance. So it would require to switch to OSS replacements at which point I decided why wouldn't give Zed a try – it has a better feeling by not being an Electron app.
I think VSCodium is a good option if you need extensions not available in Zed.
If you are good with a slightly jank option, I have had success with just moving the extension directory from VSCode to the VSCodium directory. Works for the Oracle SQL Developer plugin I use often. It might go against the terms in the extension, but I don’t care about that.
That doesn't help with Pylance and similar extensions. Microsoft implemented checks to verify the extension is running in VS Code, you have to manually patch them out of the bundled extension code (e.g. like this[0], though that probably doesn't work for the current versions anymore).
Basedpyright is really good. I've been using it in neovim for a while. I'm currently evaluating ty. It is definitely not as good, but it is also really new.
I appreciate that we have good alternatives to pylance. While it is good, it being closed source is a travesty.
I've been using vscodium with basedpyright as I've thought it was supposed to be a open source version of pylance. I've got to say it's annoying about type errors and after changing it's setting to be less strict it still annoys me and I've even started littering my code with the their # ignore _____ .
I'm really glad the article mentioned ty as I'm going to try that today.
On zed I tried it but the font rendering hurt my eyes and UI seems to be glitchy and also doesn't support the drag and drop to insert links in markdown feature * I use all the time.
Hi, I'm the author of the post. I hope it resonates with many who got tired of VSCode and found Zed.
I'd also like to add there are many small features I miss in Zed that I don't go over in the post, e.g. autodetect and respect file's indentation (https://github.com/zed-industries/zed/issues/4681). But I see Zed is actively shipping the missing features, so I believe they'll improve significantly over the next year.
Have you tried using vim? Or rather nvim? If tinkering is your thing, feel free to completely do your own setup but out of the box lazyvim is pretty sane and you may not need much to get it to your liking.
But it’s very nice to easily able to extend or modify to fit your workflow. I’m just curious what people are getting out of zed that seems like vim has available.
I use both zed and vim, but the former for 'big' work because of:
a) file tree - I really like being able to 'root' the view at a directory, explore the hierarchy, and easily open any file within it
b) LSP - Zed's auto-formatting is it's best feature, for me
I generally like a whole bunch of things the gui gives me, but I would probably drop zed if I could get these two features working as well (or, at least, almost as well) in vi.
+1 for lazyvim. I tried multiple times to switch to nvim from vscode, but lazyvim finally made it painless. love lazygit too. debugging in nvim also works like a charm.
I use it like this: If a PR is LLM-generated, you as a maintainer either merge it if it's good or close if it's not. If it's human-written, you may spend some time reviewing the code and iterating on the PR as you used to.
Saves your time without discarding LLM PRs completely.
But what does LLM-generated mean? What if I use CoPilot for completions? Is that considered "AI generated"? What if I grab the code from Claude, and update greater than 50%. Am I now taking ownership of it as my code?
A sincere question to Go programmers – what's your take on "Parse, Don't Validate"?