January 24
On Wednesday, January 24, 2024 11:20:38 AM MST Paul Backus via Digitalmars-d wrote:
> On Wednesday, 24 January 2024 at 17:35:32 UTC, Paul Backus wrote:
> > In general, we should not make assumptions in our library code unless we are capable of enforcing them. Since we are, unfortunately, not capable of enforcing the assumption that all copyable ranges have forward-range semantics, we should not allow ourselves make it.
>
> Having thought about it some more, this is a bad argument, and I withdraw it.
>
> The entire range API is based on convention to begin with. Of course there's no enforcement mechanism!

Yeah. We can enforce some stuff statically (e.g. we can require that a forward range be a dynamic array or a struct, since if it's a class or a pointer, we know for sure that it doesn't have the right copy semantics), but we can't actually enforce the correct copy semantics statically - just like we can't enforce the correct copy semantics with save right now. We can't even enforce that popFront removes an element from the range or that empty has anything to do with how many elements the range has. We can improve the situation with the API (e.g. getting rid of the requirement for save), and we can try to make it easier to use correctly and harder to use incorrectly, but unfortunately, there's no way to not rely on convention on some basis.

- Jonathan M Davis



January 24

On Wednesday, 24 January 2024 at 18:20:38 UTC, Paul Backus wrote:

>

The entire range API is based on convention to begin with. Of course there's no enforcement mechanism!

Isn't isInputRange, isForwardRange, and the rest, kind of enforcement machanism?

January 24
On Wednesday, January 24, 2024 12:23:45 PM MST Alexandru Ermicioi via Digitalmars-d wrote:
> On Wednesday, 24 January 2024 at 18:20:38 UTC, Paul Backus wrote:
> > The entire range API is based on convention to begin with. Of course there's no enforcement mechanism!
>
> Isn't `isInputRange`, `isForwardRange`, and the rest, kind of enforcement machanism?

Traits like that can test (and thus be used to enforce) _some_ of the semantics, but there are plenty of things that can't be tested statically (like what popFront actually does). They are able to test that certain code will compile with the range API (or that certain code won't compile) using the type that they're instantiated with, and they can test certain explicit stuff about the type (e.g. enforcing that it's a struct if we want to do that), but they can't actually test what the functions do.

So, while we can enforce that a forward range is copyable, we can't enforce what its copy semantics are beyond disallowing stuff like classes or pointers to structs, since those are clearly reference types. But the struct itself could have a variety of copy semantics depending on its implementation, and there's no way to determine that statically. Ultimately, for a range to have the correct copy semantics, we have to rely on the programmer to implement them correctly, just like we have to rely on them implementing what front, popFront, and empty do correctly.

- Jonathan M Davis



January 24
On Wednesday, 24 January 2024 at 20:08:56 UTC, Jonathan M Davis wrote:

> Traits like that can test (and thus be used to enforce) _some_ of the semantics, but there are plenty of things that can't be tested statically (like what popFront actually does). They are able to test that certain code will compile with the range API (or that certain code won't compile) using the type that they're instantiated with, and they can test certain explicit stuff about the type (e.g. enforcing that it's a struct if we want to do that), but they can't actually test what the functions do.
>
> So, while we can enforce that a forward range is copyable, we can't enforce what its copy semantics are beyond disallowing stuff like classes or pointers to structs, since those are clearly reference types. But the struct itself could have a variety of copy semantics depending on its implementation, and there's no way to determine that statically. Ultimately, for a range to have the correct copy semantics, we have to rely on the programmer to implement them correctly, just like we have to rely on them implementing what front, popFront, and empty do correctly.

That's what unit tests are for, while those traits act like pseudo interfaces. Maybe there could be a test suite provided in Phobos for user to run over his own range implementations, in his own unit tests. This would make easy to spot whether user's range does or does not follow proper logic.


January 24
On Wednesday, January 24, 2024 2:31:19 PM MST Alexandru Ermicioi via Digitalmars-d wrote:
> On Wednesday, 24 January 2024 at 20:08:56 UTC, Jonathan M Davis
>
> wrote:
> > Traits like that can test (and thus be used to enforce) _some_ of the semantics, but there are plenty of things that can't be tested statically (like what popFront actually does). They are able to test that certain code will compile with the range API (or that certain code won't compile) using the type that they're instantiated with, and they can test certain explicit stuff about the type (e.g. enforcing that it's a struct if we want to do that), but they can't actually test what the functions do.
> >
> > So, while we can enforce that a forward range is copyable, we can't enforce what its copy semantics are beyond disallowing stuff like classes or pointers to structs, since those are clearly reference types. But the struct itself could have a variety of copy semantics depending on its implementation, and there's no way to determine that statically. Ultimately, for a range to have the correct copy semantics, we have to rely on the programmer to implement them correctly, just like we have to rely on them implementing what front, popFront, and empty do correctly.
>
> That's what unit tests are for, while those traits act like pseudo interfaces.

Of course that's what unit tests are for, but that doesn't enforce anything. That's the programmers making sure that their code behaves the way that it should - that their code follows the conventions required by the range API. On the other hand, what Paul was talking about was actually statically enforcing the semantics via template constraints rather than relying on coventions, which is something that we can do with some portions of the semantics of the range API but can't do for a good chunk of it.

> Maybe there could be a test suite provided in Phobos for user to run over his own range implementations, in his own unit tests. This would make easy to spot whether user's range does or does not follow proper logic.

Well, we can provide test ranges to use to test a function with, but not much can be automated there, since the results would depend on what the function actually did. However, if there were set of standard range types to test with, then it would at least be easier to test a proper range of range types. Phobos itself doesn't always do a good job with that though.

As for testing that a range behaves properly, that might be possible to automate, but since it's usually the case that a range comes from a function, that's not always straightforward. And while how the range should behave is largely defined by the range API, not all ranges are generic with regards to what they work with (e.g. what their element type is) or how they're constructed, so writing a generic set of tests could be challenging. Off the top of my head, I don't know how possible it would be, though I'm sure that it could be made to work with a subset of ranges.

All in all, providing better testing tools is a good idea, but a lot of the question here is what we can statically enforce, since the more that we can statically enforce, the harder it will be to write range-based code that does the wrong thing, and the harder it will be to pass types to a range-based function which then won't behave properly even if the function is written properly.

- Jonathan M Davis



February 01

On Wednesday, 24 January 2024 at 20:08:56 UTC, Jonathan M Davis wrote:

>

Traits like that can test (and thus be used to enforce) some of the semantics, but there are plenty of things that can't be tested statically (like what popFront actually does).

Even if you could, what would you even test? Especially for popFront, what does it mean to “pop front”? A no-op could be a reasonable popFront implementation for a range that represents a value infinitely repeated, i.e. something like cycle(1).

1 2 3 4 5 6 7
Next ›   Last »