April 14, 2009

Andrei Alexandrescu wrote:
> Daniel Keep wrote:
>> ...
> 
> So essentially we're looking at a symbolic approach - a resumable range would need to advertise that. I've used that for isSorted too, and it works pretty well.
> 
> The remaining question is one of defaults - are most ranges resumable or not? I.e., should a range advertise explicitly when it's resumable or when it's *not* resumable? I think the safe approach is to go as you say: a range ain't resumable unless it explicitly claims to. So if you forget stuff, the compiler will remind you.
> 
> I'd love to hear more opinions on the topic.
> 
> 
> Andrei

Actually, I stuffed up the test; I wanted the default to be resumable. :P  That'll teach me to not double-check my logic.  A quick truth table later, and the correct test is this:

> template isResumableRange(R)
> {
>     enum bool isResumableRange = isInputRange!(R)
>         && (!is(typeof(R.isResumableRange))
>             || (is(typeof(R.isResumableRange)) && R.isResumableRange))
>         && is(typeof(
>         {
>             R r1;
>             R r2 = r1;
>         }()));
> }

... I think.  :P

Actually, I've been thinking and I realised that in 95% of cases, you can assume a range is resumable if it has no references.  If it has no references, the only way the range can be non-resumable is if the advance member uses the range's state as an argument to some global method.  An example might be a Range that statically accesses Stdout instead of taking it as an argument.

It's a real shame the range interface doesn't support this:

> struct R
> {
>     ...
>     pure R advance();
> }

If it did, we could prove a range was resumable if advance was pure and R has no mutable or const references.

Honestly, I think the safest option is to *require* resuming to be explicitly stated by the programmer.  It'd be nice if we could automatically account for some cases, but I can't think of any you couldn't escape from.

Maybe we should default to non-resumable for now, then re-visit the issue when we have an idea of how people are using ranges.

  -- Daniel
April 14, 2009
Daniel Keep wrote:
> Actually, I've been thinking and I realised that in 95% of cases, you
> can assume a range is resumable if it has no references.

Well I'm not so sure. How about a range around an integral file handle or socket?

> If it has no
> references, the only way the range can be non-resumable is if the
> advance member uses the range's state as an argument to some global
> method.  An example might be a Range that statically accesses Stdout
> instead of taking it as an argument.
> 
> It's a real shame the range interface doesn't support this:
> 
>> struct R
>> {
>>     ...
>>     pure R advance();
>> }
> 
> If it did, we could prove a range was resumable if advance was pure and
> R has no mutable or const references.

Hmmmm... well, pure changes "this". We'd need to say that it only changes state owned by "this", but we have no notion of "almost pure".

> Honestly, I think the safest option is to *require* resuming to be
> explicitly stated by the programmer.  It'd be nice if we could
> automatically account for some cases, but I can't think of any you
> couldn't escape from.
> 
> Maybe we should default to non-resumable for now, then re-visit the
> issue when we have an idea of how people are using ranges.

I agree. Probably I'll do that, thanks.

By the way, Walter and I both changed the names of the members to what everybody seemed to liked best: front, back, popFront, popBack. No more heads and toes.


Andrei
April 14, 2009
Andrei Alexandrescu wrote:
> Daniel Keep wrote:
>> Actually, I've been thinking and I realised that in 95% of cases, you
>> can assume a range is resumable if it has no references.
> 
> Well I'm not so sure. How about a range around an integral file handle or socket?

If ranges can advertise their resumability, it wouldn't be hard to write a simple template wrapper that provides resumability to an underlying non-resumable range.

--benji
April 14, 2009

Andrei Alexandrescu wrote:
> Daniel Keep wrote:
>> Actually, I've been thinking and I realised that in 95% of cases, you can assume a range is resumable if it has no references.
> 
> Well I'm not so sure. How about a range around an integral file handle or socket?

Most of the time, I'd expect people to be accessing those via the standard library.  And that wraps them in objects.  :)

>> If it has no
>> references, the only way the range can be non-resumable is if the
>> advance member uses the range's state as an argument to some global
>> method.  An example might be a Range that statically accesses Stdout
>> instead of taking it as an argument.
>>
>> It's a real shame the range interface doesn't support this:
>>
>>> struct R
>>> {
>>>     ...
>>>     pure R advance();
>>> }
>>
>> If it did, we could prove a range was resumable if advance was pure and R has no mutable or const references.
> 
> Hmmmm... well, pure changes "this". We'd need to say that it only changes state owned by "this", but we have no notion of "almost pure".

Hence why I made R a return value.  If you have a member function that's pure in every way EXCEPT that it changes "this", you can rewrite it like so:

> R range = getRange();
> range = range.advance;

Ta-da, advance can be pure since the changes are pushed out via the return value.  In other words,

> struct R(T)
> {
>     pure bool empty();
>     pure T head();
>     pure R!(T) advance();
> }

is a pure, guaranteed safe-to-resume version of this:

> struct R(T)
> {
>     bool empty();
>     T head();
>     void advance();
> }

The only difference is that instead of writing this:

> for( auto v = r.head; !r.empty; r.advance ) ...

You'd write this:

> for( auto v = r.head; !r.empty; r = r.advance ) ...

>> Honestly, I think the safest option is to *require* resuming to be explicitly stated by the programmer.  It'd be nice if we could automatically account for some cases, but I can't think of any you couldn't escape from.
>>
>> Maybe we should default to non-resumable for now, then re-visit the issue when we have an idea of how people are using ranges.
> 
> I agree. Probably I'll do that, thanks.
> 
> By the way, Walter and I both changed the names of the members to what everybody seemed to liked best: front, back, popFront, popBack. No more heads and toes.
> 
> 
> Andrei

Cool.  I really can't wait to dive into this stuff.  There are a few things I've been wanting to write in D2 that I'm holding off until the range stuff is done so I can give it a workout.

  -- Daniel
April 14, 2009
On 2009-04-13 22:28:33 -0400, Benji Smith <dlanguage@benjismith.net> said:

> Andrei Alexandrescu wrote:
>> Daniel Keep wrote:
>>> Actually, I've been thinking and I realised that in 95% of cases, you
>>> can assume a range is resumable if it has no references.
>> 
>> Well I'm not so sure. How about a range around an integral file handle or socket?
> 
> If ranges can advertise their resumability, it wouldn't be hard to write a simple template wrapper that provides resumability to an underlying non-resumable range.

If the language supported making an struct non-copyable, you could use this.

Actually, using a class for a non-resumable range would already acheive this (you'd only be copying references). So perhaps you could consider a class used as a range as non-resumable, and use classes for non-resumable ranges.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

1 2 3 4 5 6 7 8 9 10
Next ›   Last »