Re: Gee Functional iterators - call for consensus



On Wed, 2011-06-29 at 13:11 +0200, Quikee wrote:
> Hi,
> 
> I intended to write this for quite some time - I am sorry that it took so long.
> 

No problem.

> I have looked at the implementation and proposal for "functional
> iterators" and I have some remarks and things I really don't like.
> 
> - Implementation directly on iterator interface: Even if it is legal
> to do it in GObject I don't like that the interface contains the
> implementation and then you are forced to override it in your
> implementation just to do something different. This is for example
> also the reason for the existence of AbstractCollection and co.
> because neither I nor Didier did not want to put code into the
> interface. I hope you will also change this for the iterators.
> 

Well - possibly due to different background I like virtual method in
interfaces (i.e. like classes in Haskell). They allow to change
interface w/out breaking API (breaking ABI however).

> - Stream function: Stream function is for me just a implementation
> detail how the functional iterators are implemented. I don't think it
> is wise to force it into the interface of iterator. They should be
> available but only as a special type of iterator or something similar
> that is just used as the implementation and hidden on the interface. I
> also don't think there will be a lot of people that will write its own
> functional operator anyway. I must also say that I don't like that
> stream operation as it is very hard to read what exactly it does and
> how it works. The performance might also be an issue as functional
> programming languages are heavily optimised for (tail) recursion and
> lambda but vala is not. Still if the stream operation is just regarded
> as a implementation detail I don't mind.
> 

The stream function was written for performance reason. The Vala does
not optimize the virtual calls at all so they perform slowly as Java or
C# would do. Vala have no static or dynamic type analysis and therefore
each call to interface goes through 1-2 jumps by function pointers.

For exact numbers see:

https://bugzilla.gnome.org/show_bug.cgi?id=645850#c4

It is written mostly for implemantators as it:

 - Allows to reuse of code across functions (like map etc.) therefore
making life of people implementing new combinators easier (i.e. Jurg,
Dider, mine, ...). I agree that it is small benefit and therefore it was
not in original spec.
 - As a side effect it allows to implement all functional methods to be
implemented efficiently by just reimplementing forall and stream. As it
generally have huge impact (virtual calls are heavy in Vala, virtual
calls to interfaces via abstract classes are even more).

As shown in the data I've linked it have the  some constant overhead
(which quickly outperform other methods except .get for array).

In short - it is implementation detail but important one from
performance POV (yes, I was surprised by benefits of forall).

> - Call to iterator() before executing an functional operation is not
> elegant. Each collection could have functional operations directly
> accessible as well and just could delegate to the iterator when it is
> called.
> 

Hmm. +1?

What about something like Stream interface from which both Collection
and Iterator inherit?

Edit: it seems you call it Functional. I'm not particulary happy with
either of names.

> - In my opinion a functional operation is in itself an special
> iterator not an additional method on iterator itself. I don't like
> that I can call iterator() and do next() next() next() and afterwards
> call a functional operator. What can I expect in such an case?

Ok. There was take and skip operators in spec which get lost.

it would be something like:

iterator().skip(3).map(func)


> Also
> there is nothing preventing an Iterator to never end the iteration
> (not in any implementation in libgee but doable with a custom
> iterator). What can I expect in such a case from an functional
> iterator?
> 

They produces elements as they go. So say there is iterator returning:

iter = [1, 2, 3, 4, ....]

iter.map((x) => {return x + 1;}) returns

[2, 3, 4, 5, ...]

iter.scan((x, y) => {return x + y}, 0) returns

[0, 1, 3, 6, 10, ...]

> I hope you don't take this negatively this is my personal opinion and
> I also may be wrong. :) Generally I like the interface.
> 

No. It would be... well stupid if I sent RFC/call for consensus
expecting only positive feedback. Well - ok, I do hope everything is
fine with my original design ;) but from my experience negative, but
constructive, feedback is the most valuable one.

> I have also implemented how I think the functional iterators should be
> implemented (however I am not totally happy with the code but it
> should be good enough as an example).
> The code is available as a clone of your repository in gitorious in:
> http://gitorious.org/~quikee/libgee/quikees-mpiechotkas-libgee/commits/functional-iterators
> 

To be honest I don't like the separation of FunctionalIterator and
Iterator. Every iterator is, conceptually, functional iterator. There is
no iterator for which you cannot define meaningfully map function.

> Regards, Tomaž

Regards

Attachment: signature.asc
Description: This is a digitally signed message part



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]