News for hackers. Stuff that matters.
Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @01:00AM (#27299570)
I seem to be a bit of an outlier, but I am not looking forward to generics in Go. I don't like the kinds of discussions it attracts...vague hand-wavy arguments about "expressiveness" and "purity". Expressiveness to me means more arguing in code reviews, and nothing is stopping us from writing pure functions now, I do it all the time.

I maintain a few large Go codebases, tens of thousands of LoC each, and not having generics in practice is way, way down on my list of challenges. Equivalent Java codebases that I've maintained are usually harder to maintain because of generics, with over-eager functional programmers itching to show off their skills in abstraction, instead of solving business problems.

I hope I'm wrong, and that this will make Go a better language. But I doubt it.

Re:Functional Programming in Go with Generics by judofyr on Thursday May 27, 2021 @01:23AM (#27299679)
As someone who's working on code base at ~100k LoC I'd say that generics would be great to have:

- We have some utilities (e.g. caching layer) which now either needs to use interface{} (and lose all type safety) or hard-code the type their dealing with (and thus be duplicated).

- Lack of iterators are annoying. We often need to stream data from a database and now we need to introduce a separate iterator-interface for each thing that can be streamed (`Next() (Entry, error)`). Working with these iterators are clunky since we can't write common tooling around it (e.g. "fetch the first entry").

Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @01:37AM (#27299748)
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.

Re:Functional Programming in Go with Generics by nicoburns on Thursday May 27, 2021 @11:31AM (#27304288)
> 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.

Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @03:33PM (#27307164)
You'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".
Re:Functional Programming in Go with Generics by nicoburns on Thursday May 27, 2021 @04:31PM (#27308029)
If you're writing generic code using interface{} and then wrapping that in concrete wrappers then you're actually doing both!
Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @06:33PM (#27309419)
I’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.

Re:Functional Programming in Go with Generics by nicoburns on Friday May 28, 2021 @05:38AM (#27313359)
> 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.)

Unless I'm mistaken, the "generic type specifications" are just interfaces. Instead of specifying the concrete type of a function parameter, you specify which interface it needs to implement, and then everything else is the same (except you may need to define getters/setters if you need access to struct fields). There's no need to have a new language primitive. That's certainly how Rust does it anyway. And given that Go's interfaces are structurally typed, it'll be even simpler in Go.

I don't really understand the argument that generics are complex. As far as I can see, they're super simple.

Re:Functional Programming in Go with Generics by moldavi on Thursday May 27, 2021 @02:03AM (#27299878)
I'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?

Re:Functional Programming in Go with Generics by masklinn on Thursday May 27, 2021 @03:28AM (#27300350)
> 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/dcsgk7...

Re:Functional Programming in Go with Generics by pharmakom on Thursday May 27, 2021 @02:43AM (#27300119)
Except you still have to write out the typed implementation - even if it is small. In Java this is not necessary.
Re:Functional Programming in Go with Generics by cratermoon on Thursday May 27, 2021 @12:22PM (#27304842)
Not 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).
Re:Functional Programming in Go with Generics by cben on Friday May 28, 2021 @10:30AM (#27315742)
On 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

Re:Functional Programming in Go with Generics by hajile on Thursday May 27, 2021 @11:39AM (#27304377)
That's just going back to dynamic typing.
Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @03:41PM (#27307278)
It'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.
Re:Functional Programming in Go with Generics by jshen on Thursday May 27, 2021 @01:38AM (#27299751)
I have similar feelings. I’ve been coding a long time, and the longer I do it, the less sure I am about any of this stuff. The one thing I can say for sure, I find it relatively easy to jump into an arbitrary go code base and make sense of it. I can’t say this about languages with all the features people are clamoring for, and I’ve worked on large projects in Ruby, python, Java, scala, clojure, swift, JavaScript, typescript, and a few others.

I’m not sure exactly which qualities/features of Go make it so much easier to read, but I worry that change will lead to the Go losing what makes it unique and special.

Side note: clojure was oddly the second easiest for me to read.

Re:Functional Programming in Go with Generics by kaba0 on Thursday May 27, 2021 @05:04AM (#27300774)
Making sense of a small, detailed part of a codebase is meaningless. But too much detail will make it much harder to see the big picture, something that may be more apparent in more expressive languages.

On a deliberate hyperbole, reading assembly, each line is trivial, but it is very very hard to make sense of what does it do compared to a line of a high level language.

Re:Functional Programming in Go with Generics by gher-shyu3i on Thursday May 27, 2021 @08:28AM (#27302183)
> I’m not sure exactly which qualities/features of Go make it so much easier to read,

In my experience, golang is harder to read. It's overly verbose that it's hard to figure out the underlying logic. What can be written as

    items.filter(|n| n.price >= 10)
         .groupBy(|n| n.source)
         .mapValues(|v| v.sum()/v.length())
would be over a dozen lines of code in golang, with potentially one off functions everywhere. This only gets more obnoxious with larger code bases.

The problem is that even if golang added generics, they won't be composable. In their proposal, they proposed adding map/filter/etc functions in a separate package, not as functions on slices as a proper language would do. The same mistake they did with not having any functions on strings, but kept them in a separate package.

Also, they need to improve their anonymous function syntax.

    foo("param1", func(a int, b string) bool { return len(b) < a }
is verbose, more advanced languages simply shorten it to

    foo("param1", |a, b| b.length() < a)
or something equivalent
Re:Functional Programming in Go with Generics by edem on Thursday May 27, 2021 @03:21AM (#27300312)
It is no surprise that Clojure was the easiest to read. It is composed of S expressions and some syntactic sugar.
Re:Functional Programming in Go with Generics by whateveracct on Thursday May 27, 2021 @04:11AM (#27300533)
> I don't like the kinds of discussions it attracts...vague hand-wavy arguments about "expressiveness" and "purity".

Pretty much every argument about how to write Go programs is hand-wavy.

I'd actually argue (from years of experience at least) that FP discussions of code are pretty much the only ones of actual substance instead of mostly aesthetics and opinion and heuristic.

The best part of writing Haskell professionally is I no longer have to deal with hand-wavy programming folk-isms. We can do better, and it's not that hard.

Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @03:45PM (#27307330)
Any stylistic discussions are like that, I agree. The opinions that Go makes are themselves hand-wavy, like any stylistic opinion.

What's important to me is that the decision is already made, and when me and my team are writing code, we don't have to worry about making those decisions over and over again. They're already made for us. IME the costs/benefits of the different styles are not even worth the discussion, just pick something and move on. This is the aesthetic that I like about Go.

Re:Functional Programming in Go with Generics by jackcviers3 on Thursday May 27, 2021 @06:45PM (#27309540)
Exactly. Is it RT? Is it well-typed? Is it as simple as it could be? Is there a small number of inhabitants? Ship it. Using some weird recursion scheme when fold right will do?
Re:Functional Programming in Go with Generics by sudhirj on Thursday May 27, 2021 @02:26AM (#27300010)
There was a thought expressed in one of the original drafts that went along the lines of "the only people worrying about generics will be library authors", which I think will and should be true. The structure and architecture of existing codebases won't change, but the removal of casting to and from interface{} when using libraries will be a welcome change.
Re:Functional Programming in Go with Generics by eru on Thursday May 27, 2021 @02:47AM (#27300144)
> [...] and nothing is stopping us from writing pure functions now, I do it all the time.

One point of generics is that you have to write your pure functions less often..

Re:Functional Programming in Go with Generics by haolez on Thursday May 27, 2021 @11:05AM (#27303988)
All languages are converging to the ultimate language: The TypePyGon!

Jokes aside, I wish our tools were more "final". When is a programming language done regarding the pain it was meant to solve?

Re:Functional Programming in Go with Generics by Zababa on Thursday May 27, 2021 @11:28AM (#27304250)
> When is a programming language done regarding the pain it was meant to solve?

Elixir is often presented as "done" (https://elixirforum.com/t/is-elixir-done/20830/12). For example, the depreciation policy mention that function can only be removed on a major version (1.X to 2.Y for example), and for now it's still in 1.X and no Elixir 2 is planned.

It still has releases (https://elixir-lang.org/blog/2021/05/19/elixir-v1-12-0-relea...) to follow Erlang releases, but Erlang itself is also more conservative than some other languages.

Re:Functional Programming in Go with Generics by munificent on Thursday May 27, 2021 @12:43PM (#27305096)
> When is a programming language done regarding the pain it was meant to solve?

It's hard to imagine that a language can be "done" when the problems being solved with it keep changing and we keep discovering new techniques for solving them.

When is automotive design done? Farming?

Re:Functional Programming in Go with Generics by goatlover on Friday May 28, 2021 @03:08PM (#27319287)
Then why not just use C++ since it’s already accumulated all the features?
Re:Functional Programming in Go with Generics by munificent on Tuesday June 01, 2021 @03:37PM (#27360114)
The absence of features is often one of the greatest values a tool can have.

Features that you don't use carry a cognitive load, increase the number of choices you have to make, and reduce the usability of other features that they have to be disambiguated with.

Re:Functional Programming in Go with Generics by bfrog on Thursday May 27, 2021 @09:05PM (#27310622)
I hit the 100kloc size project in Go, the lack of generics and the never ending nested if err != nil lines were a huge part of that. It wore on myself and my team, and was certainly not helpful for the rsi I was experiencing.

10kloc is pretty small these days realistically. Especially in Go land so I get it. But yeah from my experience that simplicity at some point becomes more a burden and less a help.

Re:Functional Programming in Go with Generics by somezero on Friday May 28, 2021 @12:08PM (#27317135)
It depends on the type of the work you do. Whenever I have to cast ints to floats because I want to use something in math library, I want to claw my eyes out.
Re:Functional Programming in Go with Generics by flippinburgers on Friday May 28, 2021 @07:20PM (#27321642)
Most problems that programmers are trying to "solve" seem rather banal to me. They aren't inherently difficult in a way that generics really does much to help. Honestly I think abstraction is often the route that smart - or wanting to be perceived as smart - programmers take to keep themselves entertained. Ultimately it is overkill and wastes time in my opinion.
Re:Functional Programming in Go with Generics by klodolph on Thursday May 27, 2021 @01:22AM (#27299676)
I'm hoping people won't go crazy with it. Generics are one of the things that drive me nuts about the Rust ecosystem... it feels like every library in Cargo is based around a bunch of types with a bunch of unnecessary type parameters. Like, if I want to parse command-line arguments.

What I do want is to stop implementing sort.Interface over and over again.

Re:Functional Programming in Go with Generics by masklinn on Thursday May 27, 2021 @02:27AM (#27300015)
> Like, if I want to parse command-line arguments.

What command-line parsing libraries have “a bunch of unnecessary type parameters”?

Only library I can think of which even has them would be structopt, and that’s not unnecessary, the entire point of the library is to deserialise to a structured type.

And of course rust was designed from the ground up to leverage generics, e.g. by design it does not have reflection / RTTI, interactions with variable or foreign types are thus generics based (often, sometimes trait objects will do though they have their own tradeoffs), or it doesn’t have overloading so while not handing all overloading use cases by a long shot it uses conversion traits (aka generics) for “convenience” overloads e.g. foo(string) and foo(path) become foo<T>(_: T) where T: AsRef<Path>.

Re:Functional Programming in Go with Generics by klodolph on Thursday May 27, 2021 @03:28AM (#27300353)
Yes, Rust was designed from the ground-up to leverage generics, and as a result, the ecosystem is full of generics. There is overuse of generics in Rust.

> ...by design it does not have reflection / RTTI,..

I don't think of those as comparable features.

Reflection is more or less an alternative way to accomplish many of the same things that you get with macros in Rust. Where you'd see reflection in C# or Go is for something like serializing an object to JSON, and in Rust you'd get some library with a macro to do it for you. The Rust version could still be completely monomorphic, most of the time.

RTTI is just std::any. Rust has it. However, 99% of the time, when I'm using dynamic_cast<T>(x) in C++ or switch x := x.(type) in Go, I would have been using an enum in Rust.

The convenience overloads for Rust are nice, that's not the overuse I'm talking about. I'm talking about the fact that some library authors seem to avoid &dyn like it were poisonous, even if it makes total sense and would make large chunks of your library monomorphic. There are also minor code size issues that come about because some library authors forget that the convenience overload should probably just call an underlying monomorphic function, especially for cases like AsRef arguments.

I am under the assumption here that if you really like generics, you probably like Rust, and vice versa. This is kind of a taste thing, so what is overuse of generics for me (hello, C++'s std::chrono, std::mt19937) might be the bee's knees for you.

I did a fair bit of Haskell and C++ before Rust, and as I got more experience with those languages, I used generics less. Monomorphic types are always easier to understand, and they should be preferred.

Re:Functional Programming in Go with Generics by masklinn on Thursday May 27, 2021 @09:07AM (#27302605)
> There is overuse of generics in Rust.

You made that claim several time, but still provided literally no evidence, just a lot of handwaving and careful avoidance of any sort of concrete point.

> I don't think of those as comparable features.

> Reflection is more or less an alternative way to accomplish many of the same things that you get with macros in Rust.

They go together e.g. where Go uses reflection, Rust uses Derive or manually implemented traits and generic functions working with those traits. JSON is a pretty obvious example there.

> I'm talking about the fact that some library authors seem to avoid &dyn like it were poisonous, even if it makes total sense and would make large chunks of your library monomorphic.

I would not necessarily disagree with that although I would word it more kindly: since generics always work, they're the default, as a result dynamic dispatch is a fallback when either you must have dynamic dispatch or someone pointed out that the static dispatch was less than optimal (which can be impossible to find out through microbenchmarks).

Plus `&dyn` means you're now restricted to borrow-ability, and `Box<dyn>` incurs allocation costs. Generic function skip both concerns.

Re:Functional Programming in Go with Generics by klodolph on Friday May 28, 2021 @02:37PM (#27318968)
> You made that claim several time, but still provided literally no evidence, just a lot of handwaving and careful avoidance of any sort of concrete point.

I'm not really interested in arguing that point, just because you asked me to give concrete details doesn't obligate me to provide them or engage in the conversation to a level of detail that would satisfy your request. It's okay to share an opinion without defending it.

Part of language ergonomics is that languages provide you with with "escape hatches" to avoid making certain decisions in the design of your system. This might mean that the decisions are made by the callers. Good API design requires figuring out which questions should be answered by your API and which questions should be answered by the caller.

Just as an observation... generics are an escape hatch that let you avoid choosing concrete types, and forces your caller to do that for you, and in general, I think library authors use that escape hatch too often. This is not specific to Rust.

Re:Functional Programming in Go with Generics by duped on Thursday May 27, 2021 @10:08AM (#27303323)
The vast majority of the usage of generics in Rust are as replacements for inheritance or dynamic dispatch. It's not very different structurally.
Re:Functional Programming in Go with Generics by cle on Thursday May 27, 2021 @01:38AM (#27299755)
Agree, this is my hope. Seeing the same thing play out in other language ecosystems though, I'm just not very optimistic about it.
Re:Functional Programming in Go with Generics by Fire-Dragon-DoL on Saturday May 29, 2021 @03:31PM (#27327665)
Generics can and will be abused for terrible stuff, that's a reality. There are however a bunch of spots where the difference in not having them is a lot of additional manual code, or unoptimized code using reflection.

Every language feature can be abused, that's why Go tries to have a small amount

Re:Functional Programming in Go with Generics by agumonkey on Thursday May 27, 2021 @07:33PM (#27309919)
maybe go culture and community will add its own pragmatic flavour to generics use ? not everything has to end up in endless categorical soup
Re:Functional Programming in Go with Generics by marcus_holmes on Friday May 28, 2021 @10:10AM (#27315509)
I'm totally with you on this.