On Saturday, 15 May 2021 at 13:46:57 UTC, Chris Piker wrote:
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:

Phobos has plenty of design flaws, you don't want to copy that.

Generally you should just accept the range with a simple foreach in your handler.

```
void processRange(R)(R r) {
   foreach(item; r) {
      // use item
   }
}
```

If you want it forwarded in a pipeline, make a predicate that works on an individual item and pass it to `map` instead of trying to forward everything.

If you're creating a range, only worry about the basic three functions: empty, front, and popFront. That's the minimum then it works with most phobos things too. That's where I balance ease of use with compatibility - those three basics let the phobos ones iterate through your generated data. Can't jump around but you can do a lot with just that.


(personally btw I don't even use most of this stuff at all)



// ... what's with the . before the ElementType statement?

Now that is good to know: that is a D language thing meaning "look this up at top level".

So like let's say you are writing a module with

```
void func();

class Foo {
    void func();

    void stuff() {
         func();
    }
}
```

The func inside stuff would normally refer to the local method; it is shorthand for `this.func();`.

But what if you want that `func` from outside the class? That's where the . comes in:

```
void func();

class Foo {
    void func();

    void stuff() {
         .func(); // now refers to top-level, no more `this`
    }
}
```

In fact, it might help to think of it as specifically NOT wanting `this.func`, so you leave the this out.


What the heck is that?

idk i can't read that either, the awful error message are one reason why i don't even use this style myself (and the other is im just not on the functional bandwagon...)

Most the time std.algorithm vomits though it is because some future function required a capability that got dropped in the middle.

For example:

some_array.filter.sort


would vomit because sort needs random access, but filter drops that. So like sort says "give me the second element" but filter doesn't know what the second element is until it actually processes the sequence - it might filter out ALL the elements and it has no way of knowing if anything is left until it actually performs the filter.

And since all these algorithms are lazy, it puts off actually performing anything until it has some idea what the end result is supposed to be.


The frequent advice here is to stick ".array" in the middle, which performs the operation up to that point and puts the result in a freshly-created array. This works, but it also kinda obscures why it is there and sacrifices the high performance the lazy pipeline is supposed to offer, making it process intermediate data it might just discard at the next step anyway.

Rearranging the pipeline so the relatively destructive items are last can sometimes give better results. (But on the other hand, sorting 100,000 items when you know 99,000 are going to be filtered out is itself wasted time... so there's no one right answer.)


anyway idk what's going on in your case. it could even just be a compile error in a predicate, like a typo'd name. it won't tell you, it just vomits up so much spam it could fill a monty python sketch.

messages. (Using interfaces or *gasp* casts, would break the TMI situation.)

i <3 interfaces

it is a pity to me cuz D's java-style OOP is actually pretty excellent. a few little things I'd fix if I could, a few nice additions I could dream up, but I'm overall pretty happy with it and its error messages are much better.

but too many people in the core team are allergic to classes. and i get it, classes do cost you some theoretical performance, and a lot of people's class hierarchies are hideous af, but hey they work and give pretty helpful errors. Most the time.

better know all of std.traits and std.meta cause you're going to need them too implement a range-of-ranges consumer.

Write your function like it is Python or javascript - use the properties you want on an unconstrained template function.

void foo(T)(T thing) {
    // use thing.whatever
    // or thing[whatever]
    // or whatever you need
}

Even if that's a range of ranges:

void foo(T)(T thing) {
      foreach(range; thing)
      foreach(item; range)
           // use item.
}

It will work if you actually get a range of ranges and if not, you get an error anyway. It isn't like the constraint ones are readable, so just let this fail where it may. (In fact, I find the non-contraint messages to be a little better! I'd rather see like "cannot foreach over range" than "no match for <spam>")

I don't even think phobos benefits from its traits signatures. If you do it wrong it won't compile the same as if you do all the explicit checks.


But again, if you're doing some intermediate processing... try to use map, filter, fold, and friends... since doing the forwarding they do is legitimately complicated and my little foo consumers here don't even touch it.

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.

idk.... maybe with the full code i could guess and check my way to something but i too lazy rn tbh.

Reply via email to