3 ms·
1. Static linking. I'm astonished by how many languages expect the end user to install dependencies/runtime themselves, and something about it feels very impure
by bheadmaster 4y ago
1. Static linking. I'm astonished by how many languages expect the end user to install dependencies/runtime themselves, and something about it feels very impure.
2. The "go" keyword (and the whole goroutine system underneath it). Threads are clunky, somewhat unportable and generally unscalable. Goroutines just feel right.
3. Ability to use multiple major versions of a library. Diamond dependencies are an unsolved problem in many languages I've worked with, but with Go you don't ever even think about them.
4. Implicit interfaces. Having to write "implements X" just to be able to use a type always felt wrong. Implicit interfaces just make sense.
5. The gopher mascot. I just love that little guy.
- jalino23 4y ago1. Static linking. I agree with this, coming from JS to learning C, and having difficult time compiling things. 3. Implicit interfaces. I'm in love with this idea when I learned of it. however it wasnt obvious that this should be a thing. if you learned interface from other languages first
- Winsaucerer 4y agoGood list. Regarding (4) Implicit interfaces -- to me, it's implicit interfaces that feel wrong :) Something having a method with a particular signature doesn't seem to me to be any kind of promise that it's intended to be used for the interface that expects that method. 'implements X', is a clear statement that yes, this method is made just for that specific interface. But this is just academic. I've never actually hit a situation yet where something just happens to implement an interface by chance, and does something completely unexpected.
- deleted 4y ago[deleted]
- liampulles 4y agoHere's what I do: ``` type Doer interface { Do() error } type CanDoer struct{} var _ Doer = &CanDoer{} // This ``` If CanDoer does not implement Doer, it will fail to compile, and you can quickly see what you need to do to fix.
- bheadmaster 4y agoI think the question is more in lines of "How do I know that CanDoer does what I expect of Doer to do, semantically?". In which case, it's impossible to know for sure. For example, I could create a type with a `Read([]byte) (int, error)` method that doesn't conform to the `io.Reader` expected behavior (e.g. reads from the byte array and returns an int if byte array contains a numeric string), yet I'd be able to pass it as an argument to a function that accepts `io.Reader` - the type system won't stop me, but the behavior will be broken. However, in practice, writing erroneous implementations of common interfaces is uncommon. Naming conventions are really important in Go, so the only way to abuse type system in this way is to abuse the naming conventions, which is already considered bad practice in any sane programming language.
- Winsaucerer 4y agoYep, this is exactly what I had in mind.
- thwarted 4y agoHow do you ensure that a language with explicit interfaces implements what the expected behavior is?
- pjmlp 4y agoIt is a kind of honour system, the developer has explicitly stated, yes I want to comply to interface XYZ, instead of doing it by accident and due to copy-paste error passing the wrong one, ensuring a couple of debugging hours tracking down where the error lies in code that compiles without any issues. Typical debugging problem in dynamic languages.
- bheadmaster 4y ago> the developer has explicitly stated, yes I want to comply to interface XYZ, instead of doing it by accident To be honest, it's pretty hard to implement an interface by accident. You'd have to specifically implement methods with specific names and type signatures. If method names + type signatures don't intuitively specify how should implementation behave, then it's either a bad interface or a trivial one.