5 ms·
As far as I can tell, conclusions are based on facts about the language as well as other languages. Maps, slices and channels are generics. I'd like to see cod
by spion 11y ago
As far as I can tell, conclusions are based on facts about the language as well as other languages.
Maps, slices and channels are generics. I'd like to see code in Go written without maps, slices or generics.
Go will never implement immutable data structures. Its impossible to write an immutable data structure library without generics.
Go will never implement Futures / Tasks / Observables. Its impossible to write Futures / Tasks without generics.
Here are some statistics: In Go its impossible to write 90% of the functions listed here: https://lodash.com/docs https://lodash.com/docs - because they take higher order functions, which use generics. The fact that JavaScript has loops that can be used instead, yet this is still the most popular JavaScript library cannot be reconciled otherwise than by acknowledging that generics are generally useful.
Its a damn shame that the language has such flaws: the standard library and tooling are superb. And just generics can single-handedly get rid of 80% of the problems of Go (errors can be modelled with a generic Result<T> which forces you to check for error and allows chaining, generics would enable immutable data structures which are much safer for concurrent programming...)
- AnimalMuppet 11y agoYou're coming from the same bias as the author of the article: Haskell and Rust are what a language should look like; Go doesn't look like that, therefore Go is bad. Take one of your points: > Go will never implement immutable data structures. Its impossible to write an immutable data structure library without generics. Fine; I won't argue whether your statement is correct. But so what? That only turns into something anyone should care about if you also assume that "immutable data structures are The Right Way". > Here are some statistics: In Go its impossible to write 90% of the functions listed here: https://lodash.com/docs https://lodash.com/docs - because they take higher order functions, which use generics. This proves that Go is not built to use higher order functions. It does not prove that Go is flawed (unless you also assume that FP is The Right Way). TL;DR: Go isn't trying to be a functional programming language. Some people think FP is the only way to go, and therefore think Go is bad. Those people need to realize that FP is not the only way to program, and to stop trying to force Go into their FP world.
- sanderjd 11y agoI agree with most of your "so what?" point, but I think the lodash / FP thing is interesting because javascript is also not trying to be a functional programming language, and nor are the many other languages that have popular higher-order-function libraries (eg. Java, C#, Ruby, Python). There's a long trend of pulling in the ideas from functional languages that have proven to be generally useful, like lodash / Java 8 Streams style collections functions, while ignoring the stuff that might be useful but is harder to implement or work with, like purity, immutability, laziness, or sophisticated type inference schemes. Go is definitely anachronistic in not following this particular trend. Of course, that's the prerogative of its designers! Note that Go doesn't need generics to have 100% of what lodash has, it would just have to be implemented in the compiler, similar to slice, range, map, etc. I have no problem accepting that FP is not the only way to program, but it sure would be convenient for me personally to have nicer ways to work with collections in Go.
- jshen 11y agoAs was mentioned before, you can absolutely do the same thing in Go that you see in lodash by giving up type-safety which javascript doesn't have anyway!.
- sanderjd 11y agoI actually saw that post right after I wrote the one you just responded to. While it's definitely true, what makes it more awkward in Go is the necessity to translate back and forth between the "traditionally typed" and "unityped" dialects of the language. I'm not (only) referring to performance here, but ergonomics. Because javascript is unityped everywhere, a unityped implementation of those sorts of functions is natural, but because Go is mostly type-based, it is less natural and more boilerplate-y to pass and return `interface{}` everywhere. Nonetheless, it's a good point.
- spion 11y agoOr you don't give up type safety. TypeScript compiles really fast and has generics.
- burntsushi 11y agoYou absolutely can implement those functions in Go, if you're willing to sacrifice both type safety and performance. e.g., https://godoc.org/github.com/BurntSushi/ty/fun https://godoc.org/github.com/BurntSushi/ty/fun Javascript is unityped, and you can certainly pretend Go is unityped too, by using `interface{}` everywhere. If you linked to a similar set of functions defined in, say, C++, then I'd agree that Go has no real way to achieve something similar. > (errors can be modelled with a generic Result<T> which forces you to check for error and allows chaining, generics would enable immutable data structures which are much safer for concurrent programming...) Generics isn't sufficient for that though. You also need sum types, which Go doesn't have. Lack of generics isn't objectively a flaw. It's a trade off. You may disagree with that trade off though!
- spion 11y agoYou don't need sum types, Result / Optional etc can be implemented in a language without them. I can implement those in TypeScript too. Its a fast compiler, has a type system, and it supports generics.
- burntsushi 11y agoSum types are how Result/Option/Maybe/Either are typically implemented. The type system guarantees that inhabitants of the type contain exactly one success value xor one error value, and that accessing the value requires handling both cases, which is checked at compile time.
- spion 11y agoSure, but you don't necessarily need sum types for Either. Its more tedious, but totally doable without them, e.g. just with higher order functions: let left = a => (l, r) => l(a) let right = b => (l, r) => r(b) its now impossible to consume result without passing functions to handle both the left and the right value. let mapRight = f => val => val(identity, right => right(f(val)))
- 11y ago