4 ms·
Do you have more examples? I’ll admit that Go is full of weird quirks, but nothing feels bolted on. Generics were agonized over for so long because they had to
by 2fast4you 4y ago
Do you have more examples? I’ll admit that Go is full of weird quirks, but nothing feels bolted on. Generics were agonized over for so long because they had to fit it within the existing language
- coddle-hark 4y agoHere’s one: The fact that contexts are used extensively in the standard library but that there’s still no way to cancel a write to an io.Writer. The only way to “cancel” a write on a TCP socket is to set the socket’s “deadline” to some time in the past from another goroutine.
- silisili 4y agoAgreed on that one. Contexts definitely feel bolted on and unnatural. The sql libs for example all have 'Do' and 'DoContext', where 'Do' is any one of the operations you'd typically use.
- ainar-g 4y agoI agree that this is a PITA, but this really is more of a growth pain than an initial design flaw. Contexts have appeared way after the Go 1.0, when the entire ecosystem has already gotten used to io.Reader and io.Writer. If you want a much more annoying example of inconsistency in the initial language design, look at the behaviour of nil and closed channels: - sending data to a nil channel blocks forever; - receiving data from a nil channel blocks forever; - sending data to a closed channel causes a panic; - receiving data from a closed channel is fine: you receive the zero value, forever. I can understand the logic behind the last two (sending to a closed channel is an error in program logic, and closing a channel is a common idiom for broadcasting completion of a task to several goroutines), but the first two are just a massive footgun, and, in my opinion, should cause panics instead.
- deleted 4y ago[deleted]
- throwawaymaths 4y agoJSON marshalling is a big one
- mariusor 4y agoIn which way?
- legerdemain 4y agoRust is full of weird quirks that defenders explain by saying that "the compiler isn't smart enough yet." They often seem like consequences of a "compiler-defined" implementation. One random example -- this compiles and runs: #![allow(unused)] pub fn main() { let mut x = vec![1, 2, 3]; let y = &mut x; let z: &mut _ = y; println!("{:?}", y) } This does not: #![allow(unused)] pub fn main() { let mut x = vec![1, 2, 3]; let y = &mut x; let z = y; println!("{:?}", y) }
- afdbcreid 4y agoIn my experience, this quirks don't appear in real life (at least unless you do bunch of trait metaprogramming). One exception is async code, since it stretches the type system you are far more likely to enter some obfuscated lifetime or trait error. That being said, I was quite surprised this doesn't compile... (I understand why, but I expected the compiler to have all required information to perform reborrowing).