May 21, 2017
I am having a crisis of confidence. In two places I have structurally:

    datum.action()
      .map!(…)

and then the fun starts as I need to actually do a flatMap. In one of the two places I have to:

    .array
    .joiner;

but in the other place I have to:

    .joiner
    .array;

in order to stop the compiler spewing out a mass of (to me anyway) incomprehensible messages with types I have no knowledge of. So why does the fluent API chain break in different ways in the two cases. A Priori this seems like a breakage of the abstraction.

Full code is at
https://github.com/russel/ApproxGC/blob/master/source/main.d
The comparison is between the functions createGenerationsDeleteList and
createListOfPlaces.

Any help rebuilding my knowledge would be good.

Also error message comprehensible to programmers rather than compiler writers  might help.

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

May 21, 2017
On Sunday, 21 May 2017 at 05:18:33 UTC, Russel Winder wrote:
> I am having a crisis of confidence. In two places I have structurally:
>
>     datum.action()
>       .map!(…)
>
> and then the fun starts as I need to actually do a flatMap. In one of the two places I have to:
>
>     .array
>     .joiner;
>
> but in the other place I have to:
>
>     .joiner
>     .array;
>
> in order to stop the compiler spewing out a mass of (to me anyway) incomprehensible messages with types I have no knowledge of. So why does the fluent API chain break in different ways in the two cases. A Priori this seems like a breakage of the abstraction.
>
> Full code is at
> https://github.com/russel/ApproxGC/blob/master/source/main.d
> The comparison is between the functions createGenerationsDeleteList and
> createListOfPlaces.
>
> Any help rebuilding my knowledge would be good.
>
> Also error message comprehensible to programmers rather than compiler writers  might help.

For this kind of errors I find that it helps to break the pipeline into individual stages and reason about the type separately.

Function createGenerationsDeleteList returns auto.
{
groups.byPair() // This gives a range of Tuple!(string, string[])
.map!(func) // this gives a sorted range of string[]
.array // this gives a string[][]
.joiner; // this gives a range of string[]
}

all is good. If we swap the array and joiner we get
{
.map!(func) // this gives a sorted range of string[]
.joiner // range of range of string(?)
.array; // array of range of string
}

return type is auto, no problems.

Function createListOfPlaces return string[]  <------
{
path.dirEntries(SpanMode.shallow) // range of DirEntries
.map!(p => p.name) // range of strings
.map!(p =>  // range of
           p.dirEntries("*.deb", SpanMode.depth). // range of dir entires
                       map!(a => a.dirName).uniq) // goes to a range of strings
// have a range of range of strings here
.joiner  // range of string
.array  // string[]
}

all is good.

swap the array and joiner and we have
{
// have a range of range of strings here
.array  // array of range of string
.joiner // range of string
}
range of string is NOT string[], hence you get an error.

TL;DR you specified the return type in the second case, changing the order of the operations yields a different type -> type error.