slices, closures and . . .

1,728 views
Skip to first unread message

Russel Winder

unread,
Jun 27, 2010, 2:48:39 PM6/27/10
to GoLang Nuts
It may be that I have just missed something . . .

Given that Go has slices and closures, it seems entirely natural for it
to have map, filter and reduce (or collect, filter, inject or fold --
choose your favourite name for the functions). Given the type
interface{} and reflection it is clearly possible to write these -- and
I am hoping that someone has already done that, that they are in the
standard library and I have just missed them.

I have spotted Apply in the itertools package and various Map functions
in gotgo, but I think having a package hof containing these higher order
functions and a partial application function in would be a great benefit
for Go.

I appreciate that there are going to be arguments about efficiency and
performance using reflection . . .

--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net
41 Buckmaster Road m: +44 7770 465 077 xmpp: rus...@russel.org.uk
London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder

signature.asc

peterGo

unread,
Jun 27, 2010, 5:45:47 PM6/27/10
to golang-nuts
Russel,

This may not be hard to do. For example, I wrote a prototype reduce
and ran some tests as a result of a discussion on general min and max
functions. The number sequence was described by a variable number of
interface{} arguments, a slice of interface{} arguments, or, the
primitive form, a pair of interface{} arguments. The functions were
greaterthan() and lessthan(). The cost of the type assertion in the
function was the major expense.

Peter

On Jun 27, 2:48 pm, Russel Winder <rus...@russel.org.uk> wrote:
> It may be that I have just missed something . . .
>
> Given that Go has slices and closures, it seems entirely natural for it
> to have map, filter and reduce (or collect, filter, inject or fold --
> choose your favourite name for the functions).  Given the type
> interface{} and reflection it is clearly possible to write these -- and
> I am hoping that someone has already done that, that they are in the
> standard library and I have just missed them.
>
> I have spotted Apply in the itertools package and various Map functions
> in gotgo, but I think having a package hof containing these higher order
> functions and a partial application function in would be a great benefit
> for Go.
>
> I appreciate that there are going to be arguments about efficiency and
> performance using reflection . . .
>
> --
> Russel.
> =============================================================================
> Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.win...@ekiga.net
> 41 Buckmaster Road    m: +44 7770 465 077   xmpp: rus...@russel.org.uk
> London SW11 1EN, UK   w:www.russel.org.uk skype: russel_winder
>
>  signature.asc
> < 1KViewDownload

Jessta

unread,
Jun 27, 2010, 9:30:54 PM6/27/10
to Russel Winder, GoLang Nuts
On Mon, Jun 28, 2010 at 4:48 AM, Russel Winder <rus...@russel.org.uk> wrote:
> It may be that I have just missed something . . .
>
> Given that Go has slices and closures, it seems entirely natural for it
> to have map, filter and reduce (or collect, filter, inject or fold --
> choose your favourite name for the functions).  Given the type
> interface{} and reflection it is clearly possible to write these -- and
> I am hoping that someone has already done that, that they are in the
> standard library and I have just missed them.

I think the main reason they aren't in the standard library yet is the
lack of generics.
interface{} can do it, but it's not very nice. The runtime type check
and the overhead of reflection isn't great. This is the same reason
there aren't a lot of container structures there.
It's best not to have them in the standard library until this issue is
resolved, otherwise people will start using it and lots of code will
get broken when it eventually gets changed.

- jessta
--
=====================
http://jessta.id.au

Russel Winder

unread,
Jun 28, 2010, 5:27:39 AM6/28/10
to peterGo, golang-nuts
Peter,

On Sun, 2010-06-27 at 14:45 -0700, peterGo wrote:
> Russel,
>
> This may not be hard to do. For example, I wrote a prototype reduce
> and ran some tests as a result of a discussion on general min and max
> functions. The number sequence was described by a variable number of
> interface{} arguments, a slice of interface{} arguments, or, the
> primitive form, a pair of interface{} arguments. The functions were
> greaterthan() and lessthan(). The cost of the type assertion in the
> function was the major expense.

Can you point me at the code you wrote -- any examples of using the Go
reflection system are very useful. Whilst I am comfortable with the
meta-object protocol systems in Groovy and (the restricted form) in
Python, and the reflection system of Java, the Go model still hasn't
quite jelled -- I am having difficulty getting the size of the passed
slice so as to make a new slice of the same size but of the type of the
return value of the function for my map function. This maybe because I
am not trying hard enough.

I guess what is really important is to agree the signature of map,
filter and reduce, so everyone looking at this in any way is working
towards the same goal. I was thinking (in pseudocode):

map ( func(X)Y , slice<X> ) slice<Y>
filter ( func(X)bool , slice<X> ) slice<X>
reduce ( func(X,Y)Y , Y , slice<X> ) Y

but I am not committed to this if there is another, more widely
acceptable choice.

--
Russel.
=============================================================================
Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel...@ekiga.net

signature.asc

Russel Winder

unread,
Jun 28, 2010, 5:36:22 AM6/28/10
to Jessta, GoLang Nuts
On Mon, 2010-06-28 at 11:30 +1000, Jessta wrote:
[ . . . ]

> I think the main reason they aren't in the standard library yet is the
> lack of generics.

The lack of generics isn't really a barrier as long as there is a
reflection system that enables checking consistency of the types at
runtime. Generics move things from runtime to compile time and so are
beneficial -- assuming you don't do what Java did which is type erasure.
Yuk.

> interface{} can do it, but it's not very nice. The runtime type check
> and the overhead of reflection isn't great. This is the same reason
> there aren't a lot of container structures there.

It's good to know the overhead is not huge.

Generics is just a way of enforcing at compile time type consistency for
containers where the types have to be consistent. Containers don't
necessarily have to be homogeneous -- though I agree it does help.

> It's best not to have them in the standard library until this issue is
> resolved, otherwise people will start using it and lots of code will
> get broken when it eventually gets changed.

I hope Go isn't already at the stage of having to obsess about backward
compatibility, it is supposed to be in an experimental stage. Clearly
it is better to avoid API breakages, but isn't having the right language
better than causing a little bit of pain along the way.

Historically the JVM tried to avoid all breaking changes, hence type
erasure, but then they went and made breaking changes anyway for
annotations -- which means they could have made a breaking change for
generics and avoided type erasure, which is what they should have done.

signature.asc

Jessta

unread,
Jun 28, 2010, 8:16:26 AM6/28/10
to Russel Winder, GoLang Nuts
On Mon, Jun 28, 2010 at 7:36 PM, Russel Winder <rus...@russel.org.uk> wrote:
> On Mon, 2010-06-28 at 11:30 +1000, Jessta wrote:
>> It's best not to have them in the standard library until this issue is
>> resolved, otherwise people will start using it and lots of code will
>> get broken when it eventually gets changed.
>
> I hope Go isn't already at the stage of having to obsess about backward
> compatibility, it is supposed to be in an experimental stage.  Clearly
> it is better to avoid API breakages, but isn't having the right language
> better than causing a little bit of pain along the way.

It's not about obsessing about backwards compatibility. The Go Devs
seem to love breaking things.
It's knowing that you definitely will have to re-write the code and
that the eventually change will definitely break everything that uses
it. So why write the code when you can just wait until you can
actually write it properly.

Russel Winder

unread,
Jun 28, 2010, 9:49:20 AM6/28/10
to Jessta, GoLang Nuts
On Mon, 2010-06-28 at 22:16 +1000, Jessta wrote:
[ . . . ]
> It's knowing that you definitely will have to re-write the code and
> that the eventually change will definitely break everything that uses
> it. So why write the code when you can just wait until you can
> actually write it properly.

Rewriting is definitely a pain, I agree. However, not having a single,
central, quality set of data structures that are actively maintained by
people interested in that sort of stuff that everyone can work with,
everyone has to write their own. Or perhaps chooses a different
programming language?

I guess the converse argument is that very few people properly use all
the weird and wonderful data structures in C++ and Java, and Python
users seem happy with sequence and dictionary.

For me the generic data structures issue is actually much less of a
problem than not having map, filter and reduce, either as functions or
as comprehensions.

signature.asc

Ian Lance Taylor

unread,
Jun 28, 2010, 1:42:36 PM6/28/10
to Russel Winder, peterGo, golang-nuts
Russel Winder <rus...@russel.org.uk> writes:

> I guess what is really important is to agree the signature of map,
> filter and reduce, so everyone looking at this in any way is working
> towards the same goal. I was thinking (in pseudocode):
>
> map ( func(X)Y , slice<X> ) slice<Y>
> filter ( func(X)bool , slice<X> ) slice<X>
> reduce ( func(X,Y)Y , Y , slice<X> ) Y
>
> but I am not committed to this if there is another, more widely
> acceptable choice.

The current reflection support does not permit creating a new type
defined in terms of other types. It only supports creating new values
of existing types. This makes it difficult to write your suggested map
function, as there is no way to create a value of type slice<Y>.

Ian

Reply all
Reply to author
Forward
0 new messages