5 ms·
I've written quite a few containers that use interface{} like that...they don't really "lose all type safety", you write a typed container around it (usually a
by cle 5y ago
I've written quite a few containers that use interface{} like that...they don't really "lose all type safety", you write a typed container around it (usually a one line implementation) that does the type assertion in one spot, and that's it, you never deal with interface{} again. For all practical purposes, it's just as type safe.
I agree that lack of iterators is one area where there is permanent annoyance. Personally, I think that annoyance is a lot less than the other problems that come with generics (at least in other languages).
I'm not saying there aren't legitimate scenarios where generics simplify things. I'm completely convinced that there are. But holistically I don't think they outweigh all the other baggage that they come with.
- deleted 5y ago[deleted]
- moldavi 5y agoI've often wondered about this. Does this technique (a type safe wrapper around an interface{}ing class) kind of accomplish the same thing that generics do for Java? It would result in the same kind of type-erasure in the end, I'd assume. In a weird way, with this technique, did Go have "manual generics" all along?
- pharmakom 5y agoExcept you still have to write out the typed implementation - even if it is small. In Java this is not necessary.
- masklinn 5y ago> In a weird way, with this technique, did Go have "manual generics" all along? In the exact same way every langage without generics had generics all along: not in any meaningful way. You could also use codegen hook to instantiate your pseudo-generics after all: https://www.reddit.com/r/rust/comments/5penft/comment/dcsgk7n https://www.reddit.com/r/rust/comments/5penft/comment/dcsgk7...
- cratermoon 5y agoNot really, but aside from the functional aspect that tends to come with them, all generics are really saying is "this operation will performed on a type to be named at runtime", optionally with a constraint that says the type-to-be-named-later will adhere to a certain interface (contract).
- cben 5y agoOn a type to be named _separately_. To-be-named-at-runtime is simply dynamic typing. It's polymorphism without static typing. Generics based on type erasure, e.g. Java, wrap that with a type system hoping* to prove safety at compile time, yet compile to a single dynamicly typed implementation, that does not use this type info at runtime. Generics based on code generation / specialization, e.g. C++, generate distinct run-time implementations with the type hard-coded. (Though you can plug in dynamic typing by making the hard-coded type a pointer.) In C++ this is more than optimization, it's semantics — you can specify distinct behavior for specific types. JIT compilers can start from a single dynamic-dispatch implementation and generate specialized implemetations for some types, bridging the divide. But in any case, the common meaning of "generics" is not merely polymorphism, it's polymorphism plus a type system where you _name_ the type you're gonna use. * https://3fx.ch/typing-is-hard.html#java https://3fx.ch/typing-is-hard.html#java
- nicoburns 5y ago> I've written quite a few containers that use interface{} like that...they don't really "lose all type safety", you write a typed container around it (usually a one line implementation) that does the type assertion in one spot, and that's it, you never deal with interface{} again. For all practical purposes, it's just as type safe. At that point aren't you just writing out the generics by hand? Why would you not want a built in language feature for that which saves you the trouble while simultaneously ensuring the code is correct.
- deleted 5y ago[deleted]
- cle 5y agoYou're writing out the concretization by hand. Generics as a language feature are much more complicated than their concretizations, which is my point. Generics are to their concretizations as "-e^(iπ)" is to "1".
- nicoburns 5y agoIf you're writing generic code using interface{} and then wrapping that in concrete wrappers then you're actually doing both!
- deleted 5y ago[deleted]
- cle 5y agoI’m talking about formal generics, where there are type system mechanisms for specifying type parameters and constraints. I suppose there are really three things we’re considering here: the generic implementation that operates on some arbitrary type, the concretization that has only concrete types, and a generic type specification which is only required if the compiler emits the concretization instead of the programmer. (I'm ignoring interfaces as they aren't really relevant here, that I can see. And hopefully I'm using the right terminology here.) What I’m arguing is that for most cases, the implementation and concretization are so easy to write by hand, are safe enough, and perform well enough, that I don’t think the downsides of having the compiler emit the concretizations are worth it. The downsides being the new complex language primitives that have lots of consequences that trickle out to the compiler, runtime, and ecosystem.
- hajile 5y agoThat's just going back to dynamic typing.
- cle 5y agoIt's not anywhere close to that. There's a tiny expression where we override the type system, but everything else in the program is still statically typed, and we get to avoid all the complexity of generics.