for example, long ago, i was looking at the source for some of the go libraries and couldn't understand why they had cut+paste code. when i asked on stackoverflow the unaminous answer was "because go doesn't support generics". you can see the discussion here - http://stackoverflow.com/questions/6645329/why-does-the-go-i...
BUT if you read that thread, and the discussion under the first answer, you'll see that there is an apparently reasonable solution without generics. that seemed like an obvious approach to me (coming, i guess, more from python and fp), but one that wasn't obvious to anyone answering (coming, i guess, more from java and c).
i have no evidence that this is a general problem, but it surprised me at the time. ever since i have been suspicious of people complaining about the lack of generics (disclaimer: i don't use go myself - when i looked at it i thought that it was clear improvement on c/c++/java, but could have been even better if they had been more open to ideas from fp - http://acooke.org/cute/GoRocksHow0.html ; in other words, i'd be happy to use it at work instead of c (current project), but if i can choose myself i'm more likely to go with a more functional approach).
i think the general conclusion from this thread is that generics would be useful because, at the moment, if you want top performance, you need to have type unsafe code in critical loops.
that sounds quite reasonable to me...
...so maybe i am just an arrogant bastard that doesn't think much of fellow programmers. but i suspect that most people, when they complain about generics are not making that argument. they're simply complaining because it's not what they are used to.
as i say, i may be wrong. i may be a horrible man. if people want to convert/improve me i suggest they start making comments that are a bit more nuanced than "i miss generics".
Such as the familiarity of java developers who had to wait for a decade to get generics? The familiarity of C developers where void*? Or the familiarity of Python developers where "whatever"?
This claim doesn't check out.
map :: (a -> b) -> [a] -> [b]
Interfaces can't provide this type of code reuse.Essential: no.
Map/Filter introduce several new semantic concepts to a language. I think they were avoided for simplicity's sake and the fact you can achieve the same result with a for loop, even if it is slightly less concise.
The only added simplicity here is for the compiler writers, not the end users.
for i, n := range numbers { numbers[i] = n * n }
Sorry, but I do not see a difference in the order of assembly language vs. high-level language.
a) With a more complex type (I don't see how this would affect one more than the other)
Functional would be:
foos = map(foos, func(f Foo) Foo { return Foo{f.A * f.A, f.B * f.B} })
Iterative is:
for i, f := range foos { foos[i] = Foo{f.A * f.A, f.B * f.B} }
b) Composing various operations. Composing filter + map:
Functional would be:
x := filter(map(numbers, func(n int) int { return n * n }), func(n int) bool { return n % 2 == 0 })
Iterative is:
x := make([]int, 0); for _, n := range numbers { sq := n * n; if sq % 2 == 0 { x = append(x, sq) } }
c) Swapping the container type is just a matter of swapping "_, n := range numbers".
It does because the discussion is about generics. The fact that you're writing out types for one and not the other makes your comparisons a bit disingenuous, though I understand if Go isn't very good at functional programming.
b) Composing various operations. Composing filter + map:
As you keep building them up the imperative style will have more code overhead and less efficiency.
> c) Swapping the container type is just a matter of swapping "_, n := range numbers".
This isn't true since the functional one could easily swap out to use an infinite data source whereas the imperative will be constrained to the arrays you're already using.
b) No, it will not be less efficient. It's all done within one loop, in-place. You can compose everything inside the body of the loop. A functional language would do the same if it's intelligent.
c) You can easily create an infinite data source in Go with the generator pattern:
numbers := make(chan int); go func() { for i := 0; ; i++ { numbers <- i } }()
for n := range numbers {...}
Yes, I should have said type inference obviously. I can't think of a decent functional language that doesn't have type inference though.
> No, it will not be less efficient. It's all done within one loop, in-place. You can compose everything inside the body of the loop. A functional language would do the same if it's intelligent.
If it's all done in one loop then it isn't composing. It's writing custom code every time you need to do something.
> You can easily create an infinite data source in Go with the generator pattern:
That's nice, you only need to change all of your code to do so. The functional version doesn't have that problem.
Please note that if your comment thread starts getting squished against the right side of the page like this, it might be time to move the conversation off of HN.
================
It could be a linked list that links back to it's own head. It could be a network stream, or a series of events from an input device. The program doesn't have to care.
It's a different way of approaching things. I'd say that golang was stream-based rather than functional or imperative.
Higher order functions are really useful for splitting apart navigation of a data structure and the processing of the data contained within it.
Given that you can use purely higher order functions for control flow, I wouldn't say one is more essential than the other.
No they don't. If you already have first-class functions (Go does) and some sort of sequence type (Go does), you have map/filter. There's no new semantic concepts.
https://github.com/tcard/functional
I can't say I've actually needed to use map or filter. You can, much as people did for the last 30 years and still do with C, quite happily do this sort of stuff with a for loop...
Common container data structures are one example. You can't write, say, a generic binary search tree in Go, unless you wrap all your data in an interface. While possible, this means you have to downcast all over the place.
The built-in map, while useful, is limited in how far it goes.
Maybe I'm just spoiled by the STL and the Java collections libraries.
I suspect this is why a lot of people who've jumped on the Golang bandwagon come from Python & Ruby: they're already used to no compile-time type safety, so they're not missing anything. For people who like type systems and have a style of programming that relies upon them, Go doesn't give them the tools they need to be productive.
In Steve Yegge's terms: C++ is a pretty software-conservative update to C (it even has backwards-compatible syntax). Meanwhile, Go is a pretty software-liberal update (slightly to the right of Python). G simply does not support a software-conservative programming style. Consequently, Go's adoption has mostly come from software-liberal communities.
The mapper can take care of almost everything using a few conventions and reflection, and for anything where those conventions don't cover it you plug in a little custom code (inherit from Mapper<,> or use composition).
Not sure how you’d handle that sort of case in Go without generics?