3 ms·
Non-exported struct fields are a way of preventing your library from being composable. Checking if a value implements an interface is a way of writing surprisin
by anonymoushn 6y ago
Non-exported struct fields are a way of preventing your library from being composable. Checking if a value implements an interface is a way of writing surprising bugs. The standard library uses both of these features extensively, to give users bugs and prevent itself from being composable.
Checking that the user uses all values bound to variables but letting them discard errors by not binding them to a variable is a weird choice. Channels panicking instead of returning an error is a weird choice.
It's ok and I would like to to use it instead of Java.
- closeparen 6y agoCan you elaborate on private struct fields? The same criticism would apply for any OO language with access control / visibility of fields right?
- pjmlp 6y agoI guess is the typical critic of people used to monkey patch libraries in dynamic languages.
- anonymoushn 6y agoThe particular combination of things is, some library includes some method signatures that accept and return a specific struct (not a specific interface). Then, also, there is no exported way to make one of that struct, or to set its fields. Now you cannot write a library that wraps the original library and exposes the same API (unless you use unsafe and reflection). In the OO languages I have encountered there seems to be a stronger convention toward using interfaces instead of struct or class types in this sort of situation, but people are certainly free in Java to use a final class type as the type of their parameters and return values if they want to make their library less composable.
- closeparen 6y agoIs this a different problem from private constructors / setters in OO world?
- anonymoushn 6y agoNo, but it's a more prevalent problem in the actual standard library of Go. The Java standard library does not regularly use final classes with private constructors and setters as the parameter and return types in its APIs (which would also prevent people from implementing those APIs). It uses interfaces.
- mook 6y agoRelated complaint, the standard library taking structs as input is kind of annoying. I'm specifically thinking of net.Dialer having a net.Resolver, where that's a struct and not an interface, so it's difficult to sub in custom logic there (but still possible, at least, with some contortions). Single-binary deployment and (these days) good dependency tracking (downloading multiple versions of a library) is great; I don't worry about trying to get somebody else's source code built I do the way when I get python packages. The python side is largely because setting up a venv is error-prone (at least, for me, somehow) and leaky. I still think having the version baked into the import path is kind of dumb, but I suspect that's really just because the documentation failed to explain the reasoning and good workflows (I understand just changing the path in go.mod may be enough). I wish they had things like generics, but I fear that an incompatible version break would cause too much strife, much in the same way of python 3 / perl 6. Given how the vendoring tools story went, I'm not yet confident the core team can manage the community very well. On the positive side, the error handling has been decent for me so far; an error interface is easy to understand, compared to rust (where I think you can use Box<dyn Error> but they don't actually say that in the basic documentation). I also like the decently sized standard library, again in comparison to rust where things are too minimal. I think ruby has a decent compromise, where the standard library is (mostly) also available as downloadable packages if you need a newer version. Somehow I've had worse experience with ruby gems compared to go modules, though; I think that's because the bundler documentation is rather bad — it feels more like an essay rather than a reference. Not having a central repository of packages is a definite plus in my book for go; it leads to less of a problem with people taking the good package names (since most names are bad anyway). Less worries about cutely named libraries like devise (ruby, for auth) or hyper (rust, HTTP). IMHO, libraries should be plainly named, apps can have weird names if they want.
- lizmat 6y ago> incompatible version break would cause too much strife, much in the same way of python 3 / perl 6. The Perl world has solved this by renaming Perl 6 to Raku (https://raku.org https://raku.org using the #rakulang tag on social media).