4 ms·
This is the kind of shit why they probably didn't want generics in the language. This is like building a very crude general-ish DSL inside the language. Becaus
by torginus 2mo ago
This is the kind of shit why they probably didn't want generics in the language.
This is like building a very crude general-ish DSL inside the language. Because the tools are intentionally limited (as to limit the scope of the feature), the result looks ugly. Also, like with C++ templates, people find exploits to do what the designers didn't want them to, with even more elaborate workarounds.
I liked Go before generics. It had a clear identity. If you wanted to get cute, you could use go generate and generate code. They should've made that much more convenient and ergonomic, if they wanted to make the language more powerful (and the nice thing is that it still sits outside of the language).
I think the point Go was making is that these complex things generally have little use in application code, and 99% of the time they're there for people who want to show how smart they are, at the expense of code readability, and accessibility.
- sirsinsalot 2mo agoI think you're right and it is sad to see. I think had they stuck to their guns, the language might not feel like it has lost the point.
- mrkaye97 2mo agoAs a bit of a counterpoint, I help maintain SDKs for Hatchet in multiple languages (largely Python and TS, but also contribute to Go a bit too) that benefit heavily from generics. It's especially useful for things where users of the SDK provide e.g. return types from functions they register, and we want those to be strongly-typed elsewhere in the codebase. A simple Python example is: @hatchet.task() async def my_task(...) -> SomeOutputType: return SomeOutputType(...) ## imagine this is an API handler: @api_handler("/some/path") async def handle() -> ...: result = await my_task.run(...) # we now know `result` is of type `SomeOutputType` without any sort of type assertion, etc. Admittedly, I'm not a Go expert, nor am I a programming languages expert. But I do feel that this type of behavior is really only possible (with nice ergonomics) with generics, and it's always been upsetting to me that somehow Python's type system feels more complete than Go's in this arena, or at least it has until more recently. Maybe this falls into the 1% of cases, but I'd suspect this sort of thing is more common than that. Edit: I should have mentioned - in the Python example above, `@hatchet.task` is generic with the output type of the task it wraps.
- torginus 2mo agoAnd I'm not a python expert, so I might be wrong here, but: My understanding is that this decorator generates some class in the background that wraps the function into some remotely executable container thing, and handles the networking? Since python is a dynamic language, and go is not, this would be impossible without codegen, generics or not, but go does have codegen facilities. And the more immediate implication, that many OOP languages do (and seems to be going on in here) is that they handle asynchrony via some generic Awaitable[T] pattern. Go does not do this, generally the way you handle asynchrony and abstract typed results is by using channels. You don't await on 'smart' objects, you read from channels (which are 'generic' in a way, but they are the few exceptions where go used to allow this behavior).
- mrkaye97 2mo agoAh yep! I should’ve given a Go example. In Python we use decorators because it’s what’s in fashion, but in Go and TypeScript you just create a `NewTask()` e.g. where you pass a function (as well as other args), and it returns something with e.g. a `Result` method. And that result method, which is generic, is the thing that’s really nice to have typed. Agreed codegen works fine here too by the way, but it feels kind of clunky to me (it’s something I don’t love about Go, although I know it’s also an important part of the ecosystem and is popular).
- torginus 2mo agoI'm just saying that this Task[T] pattern is completely alien to Go. If you want to have one-off ansynchrony, then just write it synchronously and start your work on a goroutine. If you wanna do batch processing, use channels. For all intents and purposes, I would say 90% of IRL usage of generics is either this Task[T] pattern, collections or map() style array processing functions. Go had a solution for all 3 of these, that didn't involve generics. I'm in a fortunate position that I get to pick the language I work in for a lot of my work (from a reasonable selection). So if I want to write Go, I'll rather do it idiomatically, otherwise I'd pick something else. Which should be the case for everyone, and language designers should take heed. The 'we want the Java/Python/Go/JS audience' sentiment has ruined many a language, as they've turned themselves into the same mediocre language that has all the features everyone else has.
- JyB 2mo agoYou are unfortunately right. I am a bit relieved because it seem generics don't seem that over-used in the community. But still, the language lost a lot with this change that felt super-forced and unnecessary. Biggest downside of the language by far.