4 ms·
Implicit interfaces are one of the defining features of the language that make it so great, I love them. Calling them borderline insane without any supporting a
by cube2222 4y ago
Implicit interfaces are one of the defining features of the language that make it so great, I love them. Calling them borderline insane without any supporting arguments does make me question whether you ever gave idiomatic Go a chance. What do you dislike about them?
Re error handling, I've been looking at the proposals and haven't yet seen a satisfying one.
Sure, the current error handling is a bit verbose (three lines after each erroring function call), but it's a completely irrelevant problem to me in my day to day, and I much prefer it to exceptions as it makes you think about each error and makes people wrap errors with helpful context everywhere.
In general, I like the approach of the Go team of only accepting proposals that are good and actually widely requested, as opposed to accepting "something" because "our story for this isn't great to some".
- Smaug123 4y ago> I much prefer it to exceptions as it makes you think about each error and makes people wrap errors with helpful context everywhere… This would be absolutely fine, for the reasons you state, if Go made you deal with the error. But because it will silently allow you to completely ignore the error, your statement that it "makes you think about each error" is quite optimistic. In an exceptionful language, the runtime will let you know loudly and fatally when you've got garbage; in a language with a type system that admits a Result type, the compiler will forbid compilation unless you note that you're throwing away the error (which might be a single character of syntactic sugar, it need not be verbose!). But Golang and C and friends are the languages where you silently get garbage if you forget to do the due diligence that machines are perfectly capable of doing for you, and it makes me extremely sad every time I see a bug of this nature.
- cube2222 4y agoThat is a fair point and it's why I use errcheck[0]. [0]: https://github.com/kisielk/errcheck https://github.com/kisielk/errcheck
- Smaug123 4y agoMagic! I just checked, and this found the bug in a Go tool I use that bit me a couple of months ago, which I'm still smarting from. Thanks!
- cube2222 4y agoGlad I could help! In general, I recommend using golangci-lint[0], which aggregates a ton of useful linters like this one. [0]: https://github.com/golangci/golangci-lint https://github.com/golangci/golangci-lint
- cjglo 4y agoI don’t like Go error handling, but exceptions are terrible and not better. Rust/Zig/Swift approach is definitely the best.
- kaba0 4y agoExceptions are much better, especially checked ones (which are analogous to Rust-style result types).
- cjglo 4y agoNot analogous. Rust-style result types continue the normal control flow. Any exception thrown deep into a function can be very hard to debug. The normal line of execution is stopped, even without a return, and if it’s a checked exception it can “bubble up” to higher functions despite nothing signifying a return, just a marker saying somewhere this can throw an exception. Exceptions are terrible.
- kaba0 4y agoThis is literally the exact same thing. Exceptions are not gotos. They bubble up one method at a time, and can be handled at any level you want. Matching on a result type is literally the same thing as putting in inside a try-catch block. Putting a ? macro at the end is literally the default behavior. You can handle it on as tight/wide scope as you wish, plus you also get a must-have stacktrace — so your debugging is just looking at where the exception originated from.
- p-e-w 4y ago> What do you dislike about them [implicit interfaces]? Implicitly implemented interfaces can lead to problems where you're "implementing" an interface because your methods happen to be named the same, but the functionality doesn't adhere to the contract the interface is supposed to represent. Not every contract can be described by the type system, especially not by a type system as limited as Go's. Method names like "Write", "Get", or "Execute" are very common, yet in Go you have to be careful because suddenly you're implementing an interface that is intended for things that have nothing to do with what your code actually does. Simply put, it's an enormous weakening of contract safety, for essentially zero benefit. After all, spelling out that your type implements a certain interface really isn't a lot of work.
- cube2222 4y agoYou call it an "enormous weakening of contract safety", I call it an issue I've never once had happen in practice. Sometimes you can't spell out that your type implements a certain interface, because it's not a type controlled by you. Moreover, this completely kills the use-case of "define your own small interface with the subset that you actually require, instead of accepting the whole thing", which is a big part of the value-add. See my other comment[0]. [0]: https://news.ycombinator.com/item?id=33943352 https://news.ycombinator.com/item?id=33943352
- Someone 4y ago> Sometimes you can't spell out that your type implements a certain interface, because it's not a type controlled by you. Dynamically inferred interfaces only help there if function names and arguments happen to exactly match those of the interface. So if, for example, a method is called ‘Run’ rather than ‘Execute’, or you have ‘Run(string, int)’ and ‘Run(int, string)’ methods, that won’t work. Some languages that require explicit interfaces (and, I think, most modern ones) allow you to specify that mapping at run time, and also allow you to retroactively make all code (including third party code) that implements FatInterface implement your SmallInterface that’s a subset of it. Golang chooses to not require programmers to do such work and, I think, hopes programmers will keep names and argument type order identical for common methods, so that those problems occur less often. I don’t think that will work in large code bases, but then, I don’t have experience with large golang code bases.