4 ms·
https://lwn.net/Articles/548560/ https://lwn.net/Articles/548560/ I really enjoyed the article above, which I read many years ago (before Rust 1.0!) which disc
by nickm12 5y ago
https://lwn.net/Articles/548560/ https://lwn.net/Articles/548560/
I really enjoyed the article above, which I read many years ago (before Rust 1.0!) which discusses how Golang and Rust handle polymorphism and code-reuse without classic object inheritance. My current thinking is that software objects are a general-purpose tool, but classic object inheritance should rarely be used as it is a solution to a narrow problem—classes should be "final" by default, and if not the inheritance pattern should be completely designed up front.
Java had the misfortune to be designed at a time when OOP was the new craze and the design decision to force all code into an object hierarchy has not held up well. I'd rather use languages designed either before or after Java, where you can use objects when they are appropriate and ignore them when they aren't.
- naasking 5y agoArguably, subtyping in am OO language should either be signatures/interfaces only, or you should go full blown multiple inheritance for everything, as with the Fortress language.
- klibertp 5y agoIs Fortress the same language that required exponential time constraint solving for its type system?
- naasking 5y agoType checking is not exponential last I checked. However, languages with global type inference have exponential behaviour when inferring types for some pathological programs.
- zaphirplane 5y agoGolang ide struggle with answering what implements this interface. The compiler obviously handles that fine It makes it difficult to jump into an unfamiliar project Assuming that’s what you mean by signature/ interfaces
- cies 5y agoBut this is an issue with tooling. IntelliJ with Java/Kotlin does a great job here.
- zaphirplane 5y agoUnsolved AFAIK, Reducing the ergonomics of the language which is an important point
- jcelerier 5y agoC++ is much more complicated than go in that regards and my IDE generally does not have trouble with it
- baq 5y agoI mostly agree, but there's one place where it does make a lot of sense to keep the hierarchy open: exceptions. Ability raise a specific error and catch it in a generic handler is very useful.
- nickm12 5y agoAgreed. Exceptions tend to trivially respect the Liskov substitution principle and generally hold little state besides a debugging string. It's when you subclass an object as a method of code reuse that you start running into problems.
- snovv_crash 5y agoInterfaces would work fine here as well.
- klabb3 5y agoAs someone who is greatly in favor of composition over inheritance, I don't agree - or at least my experiences don't point that way. Both Rust and Go have had medium sized warts and/or boilerplate around errors, especially if you need control flow to depend on the error. In Python I've never felt that way. Not sure I can put my finger on it, because any trivial example would be fine in either paradigm. I think it has to do with the forced/unnatural upfront decision "is this error a type or an interface" that may change later on, as a type might need to be refactored to an interface. There's probably one or two other reasons I can't think of right now.
- jatone 5y agoflow control is always impacted by errors. rust and go just don't hide that on you with a giant 'go to random location in the stack' capability.
- Zababa 5y agoStandard ML and OCaml have both sum types (like in Rust) and exceptions. I feel like both have their value, and both are important. A nice thing is that you can match on exceptions: match number_of_lines_of_a_file() with | x -> x [ exception File_not_found -> 0 This makes it really easy to create alternative versions of functions, using exceptions or option types: match number_of_lines_of_a_file_opt() with | Some x -> x | None -> raise File_not_found match number_of_lines_of_a_file_exc() with | x -> Some x | exception File_not_found -> None