www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Ad hoc ranges

reply Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Doing my own deeds, I often found myself in need of writing up a range just to
e.g. feed it into an algorithm. Problem is, defining even the simplest range --
one-pass forward -- is verbose enough to render this (correct) approach
unprofitable.

This is how I went about the problem:

auto range(T, Whatever)(lazy bool _empty, lazy Whatever _popFront, lazy T
_front) {
    struct AdHocRange {
         property bool empty() { return _empty(); }
        void popFront() { _popFront(); }
         property T front() { return _front(); }
    }
    return AdHocRange();
}

--- example ---

try { ... }
catch(Throwable t)
{
    auto r = range(t is null, t = t.next, t);

    // process exception chain...
}

I don't know a terser way to get a full-fledged range. It comes at a cost,
though. Lazy parameters are just sugar over delegates, so it's not exactly
Usain Bolt**... And you can't return it because by bug or by design lazy
parameters (unlike vanilla delegates) don't work like closures. Still, even
with the overhead and limitations the idiom is remarkably useful, especially in
face of range-unfriendly libraries from outside D realm.

Enjoy.

-- 
Tomek

** Of course, there exists a somewhat more verbose compile-time variant of the
idiom I presented.
Jan 20 2011
next sibling parent reply bearophile <bearophileHUGS lycos.com> writes:
Tomek Sowiński:

 auto range(T, Whatever)(lazy bool _empty, lazy Whatever _popFront, lazy T
_front) {

I am not sure, but I think Andrei has deprecated the "lazy" attribute. Bye, bearophile
Jan 20 2011
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, January 20, 2011 16:19:54 bearophile wrote:
 Tomek Sowi=F1ski:
 auto range(T, Whatever)(lazy bool _empty, lazy Whatever _popFront, lazy=


 _front) {

I am not sure, but I think Andrei has deprecated the "lazy" attribute.

In general or on a specific function? I'm pretty sure that lazy isn't going= =20 anywhere as far as the language goes. It's used on enforce, and Andrei hasn= 't=20 wanted to make enforce take a non-lazy attribute. Also, for cases like the = unit=20 testing functions that I've been working on to get into Phobos, the loss of= lazy=20 would be pretty devastating. You could still do the, but it would be much=20 uglier. =2D Jonathan M Davis
Jan 20 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
bearophile napisa=B3:

 I am not sure, but I think Andrei has deprecated the "lazy" attribute.

Yes, but AFAIR in favor of implicit conversions of expressions to parameter= less delegates, which strengthens my little idiom. --=20 Tomek
Jan 20 2011
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, January 20, 2011 16:12:58 Tomek Sowi=C5=84ski wrote:
 Doing my own deeds, I often found myself in need of writing up a range ju=

 to e.g. feed it into an algorithm. Problem is, defining even the simplest
 range -- one-pass forward -- is verbose enough to render this (correct)
 approach unprofitable.
=20
 This is how I went about the problem:
=20
 auto range(T, Whatever)(lazy bool _empty, lazy Whatever _popFront, lazy T
 _front) { struct AdHocRange {
          property bool empty() { return _empty(); }
         void popFront() { _popFront(); }
          property T front() { return _front(); }
     }
     return AdHocRange();
 }
=20
 --- example ---
=20
 try { ... }
 catch(Throwable t)
 {
     auto r =3D range(t is null, t =3D t.next, t);
=20
     // process exception chain...
 }
=20
 I don't know a terser way to get a full-fledged range. It comes at a cost,
 though. Lazy parameters are just sugar over delegates, so it's not exactly
 Usain Bolt**... And you can't return it because by bug or by design lazy
 parameters (unlike vanilla delegates) don't work like closures. Still,
 even with the overhead and limitations the idiom is remarkably useful,
 especially in face of range-unfriendly libraries from outside D realm.
=20
 Enjoy.

What types of stuff do you need ad-hoc ranges for? What's the use case? I'v= e=20 never actually needed such a thing. I'm curious. If it's really something t= hat's=20 likely to be generally useful, then a function similar to what you're sugge= sting=20 probably should be added to std.range. =2D Jonathan M Davis
Jan 20 2011
parent reply Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/21/11 3:15 PM, Tomek Sowiński wrote:
 Jonathan M Davis napisał:

 I don't know a terser way to get a full-fledged range. It comes at a cost,
 though. Lazy parameters are just sugar over delegates, so it's not exactly
 Usain Bolt**... And you can't return it because by bug or by design lazy
 parameters (unlike vanilla delegates) don't work like closures. Still,
 even with the overhead and limitations the idiom is remarkably useful,
 especially in face of range-unfriendly libraries from outside D realm.

 Enjoy.

What types of stuff do you need ad-hoc ranges for? What's the use case? I've never actually needed such a thing. I'm curious. If it's really something that's likely to be generally useful, then a function similar to what you're suggesting probably should be added to std.range.

Like I said, anything that doesn't bother to expose range-interfaced iterators and is not performance critical is considered a target for ad hoc ranges. Working with non-D libraries, or libraries ported to D but preserving mother-language idioms. Tasks like traversing a tree of GUI widgets, or business specific objects where defining proper ranges rarely happens and is use-case driven in practice. I expect they could be of some use in unittesting as mock input. Vaguely related: educational -- ad hoc ranges read almost like a for loop so the learning curve for ranges in general is eased off. Adding them to Phobos is an interesting idea. We need to evaluate their worth, though. Everybody: if you could write up a one-liner like range(empty, popFront, front), what would you use it for?

How about a singleton range - a range with exactly one element. It could be done with repeat(x, 1) but let's try it with your function as a warm-up exercise. Andrei
Jan 21 2011
parent Andrei Alexandrescu <SeeWebsiteForEmail erdani.org> writes:
On 1/21/11 7:35 PM, Tomek Sowiński wrote:
 Andrei Alexandrescu napisał:

 Like I said, anything that doesn't bother to expose range-interfaced iterators
and is not performance critical is
 considered a target for ad hoc ranges. Working with non-D libraries, or
libraries ported to D but preserving
 mother-language idioms. Tasks like traversing a tree of GUI widgets, or
business specific objects where defining
 proper ranges rarely happens and is use-case driven in practice. I expect they
could be of some use in unittesting
 as mock input. Vaguely related: educational -- ad hoc ranges read almost like
a for loop so the learning curve for
 ranges in general is eased off.

 Adding them to Phobos is an interesting idea. We need to evaluate their worth,
though.

 Everybody: if you could write up a one-liner like range(empty, popFront,
front), what would you use it for?

How about a singleton range - a range with exactly one element. It could be done with repeat(x, 1) but let's try it with your function as a warm-up exercise.

If x is nullable, range(x, x=null, x); it destroys x, though. Otherwise the state must be held separately on the stack. bool empty; auto r = range(empty, empty=true, x); So repeat(x, 1) wins this one. I think such nuggets can better be expressed as a degenerate case of existing facilities. I envision ad hoc ranges at places where no iteration is defined and a one-off range struct doesn't pay. Like database-backed entities which don't conform to any clear-cut data structure, but if you squint you see it's sort of a tree, and you may just be able to e.g. walk through children recursively fetching only active ones from DB, traverse columns of interest, and dump their content to a grid component which takes an arbitrary range of values. And all this can be wrapped in std.parallelism to overlap DB round trips.

I think the challenge here is to figure out where to store the state. The idiom makes it difficult for the delegates to communicate state to one another. Andrei
Jan 21 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Jonathan M Davis napisa=B3:

 I don't know a terser way to get a full-fledged range. It comes at a co=


 though. Lazy parameters are just sugar over delegates, so it's not exac=


 Usain Bolt**... And you can't return it because by bug or by design lazy
 parameters (unlike vanilla delegates) don't work like closures. Still,
 even with the overhead and limitations the idiom is remarkably useful,
 especially in face of range-unfriendly libraries from outside D realm.
=20
 Enjoy. =20

What types of stuff do you need ad-hoc ranges for? What's the use case? I=

 never actually needed such a thing. I'm curious. If it's really something=

 likely to be generally useful, then a function similar to what you're sug=

 probably should be added to std.range.

Like I said, anything that doesn't bother to expose range-interfaced iterat= ors and is not performance critical is considered a target for ad hoc range= s. Working with non-D libraries, or libraries ported to D but preserving mo= ther-language idioms. Tasks like traversing a tree of GUI widgets, or busin= ess specific objects where defining proper ranges rarely happens and is use= -case driven in practice. I expect they could be of some use in unittesting= as mock input. Vaguely related: educational -- ad hoc ranges read almost l= ike a for loop so the learning curve for ranges in general is eased off. Adding them to Phobos is an interesting idea. We need to evaluate their wor= th, though. Everybody: if you could write up a one-liner like range(empty, popFront, fr= ont), what would you use it for? --=20 Tomek
Jan 21 2011
prev sibling next sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Andrei Alexandrescu napisa=B3:

 Like I said, anything that doesn't bother to expose range-interfaced it=


 considered a target for ad hoc ranges. Working with non-D libraries, or=


 mother-language idioms. Tasks like traversing a tree of GUI widgets, or=


 proper ranges rarely happens and is use-case driven in practice. I expe=


 as mock input. Vaguely related: educational -- ad hoc ranges read almos=


 ranges in general is eased off.

 Adding them to Phobos is an interesting idea. We need to evaluate their=


 Everybody: if you could write up a one-liner like range(empty, popFront=


=20
 How about a singleton range - a range with exactly one element. It could=

 be done with repeat(x, 1) but let's try it with your function as a=20
 warm-up exercise.

If x is nullable, range(x, x=3Dnull, x); it destroys x, though. Otherwise t= he state must be held separately on the stack. bool empty; auto r =3D range(empty, empty=3Dtrue, x); So repeat(x, 1) wins this one. I think such nuggets can better be expressed= as a degenerate case of existing facilities. I envision ad hoc ranges at p= laces where no iteration is defined and a one-off range struct doesn't pay.= Like database-backed entities which don't conform to any clear-cut data st= ructure, but if you squint you see it's sort of a tree, and you may just be= able to e.g. walk through children recursively fetching only active ones f= rom DB, traverse columns of interest, and dump their content to a grid comp= onent which takes an arbitrary range of values. And all this can be wrapped= in std.parallelism to overlap DB round trips. --=20 Tomek
Jan 21 2011
prev sibling parent Tomek =?ISO-8859-2?Q?Sowi=F1ski?= <just ask.me> writes:
Andrei Alexandrescu napisa=B3:

 On 1/21/11 7:35 PM, Tomek Sowi=F1ski wrote:
 Andrei Alexandrescu napisa=B3:

 Like I said, anything that doesn't bother to expose range-interfaced =




 considered a target for ad hoc ranges. Working with non-D libraries, =




 mother-language idioms. Tasks like traversing a tree of GUI widgets, =




 proper ranges rarely happens and is use-case driven in practice. I ex=




 as mock input. Vaguely related: educational -- ad hoc ranges read alm=




 ranges in general is eased off.

 Adding them to Phobos is an interesting idea. We need to evaluate the=




 Everybody: if you could write up a one-liner like range(empty, popFro=




 How about a singleton range - a range with exactly one element. It cou=



 be done with repeat(x, 1) but let's try it with your function as a
 warm-up exercise.

If x is nullable, range(x, x=3Dnull, x); it destroys x, though. Otherwi=


 stack.

 bool empty;
 auto r =3D range(empty, empty=3Dtrue, x);

 So repeat(x, 1) wins this one. I think such nuggets can better be expre=


 facilities. I envision ad hoc ranges at places where no iteration is de=


 pay. Like database-backed entities which don't conform to any clear-cut=


 it's sort of a tree, and you may just be able to e.g. walk through chil=


 from DB, traverse columns of interest, and dump their content to a grid=


 values. And all this can be wrapped in std.parallelism to overlap DB ro=


=20
 I think the challenge here is to figure out where to store the state.=20
 The idiom makes it difficult for the delegates to communicate state to=20
 one another.

On the stack, for loops do it for years. --=20 Tomek
Jan 22 2011