On Saturday, 15 May 2021 at 11:51:11 UTC, Adam D. Ruppe wrote:
On Saturday, 15 May 2021 at 11:25:10 UTC, Chris Piker wrote:
The idea is you aren't supposed to care what the type is, just what attributes it has, e.g., can be indexed, or can be assigned, etc.

(Warning, new user rant ahead. Eye rolling warranted and encouraged)

I'm trying to do that, but range3 and range2 are written by me not a Phobos wizard, and there's a whole library of template functions a person needs to learn to make their own pipelines. For example:
```d
// From std/range/package.d
CommonType!(staticMap!(ElementType, staticMap!(Unqual, Ranges))

alias RvalueElementType = CommonType!(staticMap!(.ElementType, R)); // ... what's with the . before the ElementType statement? Line 921 says // .ElementType depends on RvalueElementType. How can they depend on
// each other?  Is this a recursive template thing?
```

and all the other automagic stuff that phobos pulls off to make ranges work. If that's what's needed to make a custom range type, then D ranges should come with the warning **don't try this at home**. (Ali's book made it look so easy that I got sucker in)

Every time I slightly change the inputs to range2, then a function that operates on *range3* output types blows up with a helpful message similar to:
```
template das2.range.PrioritySelect!(PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe), PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe)).PrioritySelect.getReady.filter!((rng) => !rng.empty).filter cannot deduce function from argument types !()(PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe), PriorityRange!(DasRange!(Tuple!(int, int)[], int function(Tuple!(int, int)) pure nothrow @nogc @safe, int function(Tuple!(int, int)) pure nothrow @nogc @safe, Tuple!(int, int), int), int function() pure nothrow @nogc @safe))
```
What the heck is that?

Anyway, you put it all in one bit thing and this is kinda important: avoid assigning it to anything. You'd ideally do all the work, from creation to conclusion, all in the big pipeline.

I fell back to using assignments just to make sure range2 values were saved in a concrete variable so that range3 didn't break when I changed the lambda that was run by range2 to mutate it's output elements.

What went in to getting the element to range3's doorstep is a detail that I shouldn't have to care about inside range3 code, but am forced to care about it, because changing range2's type, changes range3's type and triggers really obscure error messages. (Using interfaces or *gasp* casts, would break the TMI situation.)

So say you want to write it

auto mega_range = range1.range2!(lambda2).range3!(lambda3);
writeln(mega_range);

that'd prolly work, writeln is itself flexible enough, but you'd prolly be better off doing like

Sure it will work, because writeln isn't some function written by a new user, it's got all the meta magic.

This way the concrete type never enters into things, it is all just a detail the compiler tracks to ensure the next consumer doesn't try to do things the previous step does not support.

It's all just a detail the compiler tracks, until you're not sending to writeln, but to your own data consumer. Then, you'd better know all of std.traits and std.meta cause you're going to need them too implement a range-of-ranges consumer. And by the way you have to use a range of ranges instead of an array of ranges because two ranges that look to be identical types, actually are not identical types and so can't go into the same array.

Here's an actual (though formatted by me) error message I got stating that two things were different and thus couldn't share an array. Can you see the difference? I can't. Please point it out if you do.

```d
das2/range.d(570,39): Error: incompatible types for (dr_fine) : (dr_coarse):

das2.range.PriorityRange!(
  DasRange!(
    Take!(
      ZipShortest!(
cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128))
      )
    ),
    int function(Tuple!(int, int)) pure nothrow @nogc @safe,
    int function(Tuple!(int, int)) pure nothrow @nogc @safe,
    Tuple!(int, int),
    int
  ),
  int function() pure nothrow @nogc @safe
)

and

das2.range.PriorityRange!(
  DasRange!(
    Take!(
      ZipShortest!(
cast(Flag)false, Result, Generator!(function () @safe => uniform(0, 128))
      )
    ),
    int function(Tuple!(int, int)) pure nothrow @nogc @safe,
    int function(Tuple!(int, int)) pure nothrow @nogc @safe,
    Tuple!(int, int),
    int
  ),
  int function() pure nothrow @nogc @safe
)
```

But, loops are bad. On the D blog I've seen knowledgeable people say all loops are bugs.

Meh, don't listen to that nonsense, just write what works for you. D's strength is that it adapts to different styles and meets you where you are. Listening to dogmatic sermons about idiomatic one true ways is throwing that strength away and likely to kill your personal productivity as you're fighting your instincts instead of making it work.

Insightful.

Anyway, if you made it this far, you're a saint. Thanks for your time :)



Reply via email to