March 22, 2004
I like the idea of with beeing used this way, it could save a lot of typing
and help prevent a lot of bugs.
It would be great if I could, instead of writing something like this (real
code):
        P.G.nonTerminalToStr[a.element][1 ..
P.G.nonTerminalToStr[a.element].length-1]
write something like this:
        with(P.G.nonTerminalToStr[a.element])[1..length-1]
//compiler realizes that "length" is something that needs to be called on
"P.G.nonTerminalToStr[a.element]"

This is more readable, easier to find bugs in, easier to change if changes
need to be made.
I only don't know is it possible to implement.


"Matthew" <matthew@stlsoft.org> wrote in message news:c3jmsb$o6d$1@digitaldaemon.com...
> A bit more DTL ranges, involving slices:
>
>     foreach(int i; range(-10, 10, +1)[6 .. 12])
>     {
>         printf("%d ", i);
>     }
>
> This prints out
>
>     -4 -3 -2 -1 0 1
>
> To slice from the beginning, we would start with 0, as in:
>
>     foreach(int i; range(-10, 10, +1)[0 .. 12])
>
> This prints out
>
>     -10 -9 -8 -7 -6 -5 -4 -3 -2 -1 0 1
>
> But to go to the end from, say, the third element, what do we do?
>
>     foreach(int i; range(-10, 10, +1)[3 .. ??])
>
> Now of course we can calculate it by the following:
>
>     foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
>
> But it's not very succinct, is it? It's pretty confusing to look at for
me,
> so I'm guessing people who aren't familiar with it would have a hard time.
>
> Maybe we can use "with", somehow, as in
>
>     foreach(int i; with range(-10, 10, +1)[3 .. length])
>
> or
>
>     foreach(int i; with range(-10, 10, +1)[3 .. object.length])
>
> where "object" would be a reserved word and would refer to the current with'd instance.
>
> Thoughts?
>
>
>
>


March 23, 2004
That looks a whole lot like std.dtl.ranges.IntegralRange!(). :)


"Ben Hinkle" <bhinkle4@juno.com> wrote in message news:gqbr5016l0ajrvg5h5f1f4jbql4c7nok2p@4ax.com...
>
> [snip]
> >Maybe we can use "with", somehow, as in
> >
> >    foreach(int i; with range(-10, 10, +1)[3 .. length])
> >
> >or
> >
> >    foreach(int i; with range(-10, 10, +1)[3 .. object.length])
> >
> >where "object" would be a reserved word and would refer to the current with'd instance.
> >
> >Thoughts?
>
>
> Seems like a simple work-around is to assign the range to a variable and get the length of that. I don't think creating a range and slicing it in the same expression is common.
>
> Talking about ranges inspired me to play around with structs and
> overloading. D is just too much fun. Here's a stab at a range struct
> for indexing arrays. I hope this is roughly what you had in mind
> for use cases for ranges. I couldn't find a nice API for overloading
> the slicing of an arbitrary array type using ranges so I just
> made it a template and defined some overloaded convience functions.
>
>
> /** A range of ints a, a+step, a+2*step,..., b */
> struct range {
>    int a,b,step;
>
>    /** Constructor (using Stewart Gordon's trick) */
>    static range opCall(int a,int b,int step) {
>       range t;
>       t.a = a;
>       t.b = b;
>       t.step = step;
>       return t;
>    }
>
>    /** Constructor with implicit step of 1 */
>    static range opCall(int a,int b) {
>       return range(a,b,1);
>    }
>
>    /** Length property */
>    uint length() {
>       int res = (b-a+1)/step; // overflow?
>       return res>0?res:0;
>    }
>
>    /** Index operator */
>    int opIndex(int x) {
>       return a+x*step;
>    }
>
>    /** Slice operator */
>    range opSlice(int x, int y) {
>       return range(a+x*step, a+y*step,step);
>    }
>
>    /** Foreach iteration */
>    int opApply(int delegate(inout int val) dg) {
>       int res = 0;
>       for (int k=a; k<b; k+=step) {
> res = dg(k);
> if (res)
>     break;
>       }
>       return res;
>    }
> }
>
> template TStepSlice(T:T[]) {
>
>    /** Slice and extract an array x of type T[] by range r */
>    T[] slice(T[] x, range r) {
>       uint len = r.length;
>       int ind = r.a;
>       T[] res = new T[len];
>       for (int k; k<len; k++, ind+=r.step )
> res[k] = x[ind];
>       return res;
>    }
>
> }
>
> // conveniece functions
> double[] slice(double[] x, range r) {
>    return TStepSlice!(double[]).slice(x,r);
> }
> int[] slice(int[] x, range r) {
>    return TStepSlice!(int[]).slice(x,r);
> }
> // ...etc
>
> int
> main()
> {
>    // make the array x we are going to slice
>    double[10] x;
>    for (int k=0;k<10;k++) x[k] = k;
>    // print out x
>    foreach (double val; x)
>       printf("%f ", val);
>    printf("\n");
>
>    // slice x using a range
>    double[] y = slice(x,range(0,10,2));
>
>    // print out the result
>    foreach (double val; y)
>       printf("%f ", val);
>    printf("\n");
>
>    // index into a range
>    range r = range(3,9,2);      // 3,5,7
>    printf("r[1] = %d\n",r[1]);
>
>    // slice a range
>    range r2 = r[1 .. r.length]; // 5,7
>
>    // print out the result
>    foreach (int val; r2)
>       printf("%d ", val);
>    printf("\n");
>
>    return 0;
> }
>
>


March 23, 2004
"larry cowan" <larry_member@pathlink.com> wrote in message news:c3li6m$l3t$1@digitaldaemon.com...
> >>> A bit more DTL ranges, involving slices:
> >>>
> >>>     foreach(int i; range(-10, 10, +1)[6 .. 12])
> >>>     foreach(int i; range(-10, 10, +1)[3 .. ??])
> >>>     foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
> >>>     foreach(int i; with range(-10, 10, +1)[3 .. length])
> >>>     foreach(int i; with range(-10, 10, +1)[3 .. object.length])
> >>> Thoughts?
>
> How is this more useful, readable, valuable than:
>
> for ( i = v1 ; i < v2 ; i += v3 )
>
> ?

Depends on context. In "normal" code, it isn't, but I'm not (going to) claim
that it is.

>  Can it be used in cases which are not indexable directly

In the general case, yes.

>or via opAdd and
> opCmp?  Can it do something the "for loop" cannot?
>
> Range: what uses are there beyond the loop usage?

They encompass within a common construct - foreach in D - a wider range of "ranges" than any other concept, since they include notional ranges, such as for(int i = ...) and also actual ranges, as denoted by iterators.

> Slicing: what does it add to the mix?

Haven't a clue. Walter requested it, and I wrote before I thought. :)

Please don't everyone get hung up on the IntegralRange. It's fairly useful, but I've shown it as it clearly illustrates the concept. Once everything's written up it should be clearer how these things fall into place. (In my defense, I'll say that Walter, the arch-pragmatist, gave the thumbs up to the chapter on ranges in "Imperfect C++", so it's probably not all philosophical fancy. <g>)

> Performance: how can you hope to improve on the simple "for loop"?

I don't. As good as is fine by me.

I'll be stunned if the compiler doesn't translate it into the exact same machine code, heap objects and templates notwithstanding.

> Control: this does probably have automatic limits checking and does any necessary memory allocation for itself, but what about the objects it's
used on?

Don't understand the question

> Readability: this is much harder to read and understand than the simple, concise, and ubiquitously familar format of the "for loop".

Disagree. Once most/all things in D can be done by foreach, the opposite could be said by someone who thinks in D.

> Generic programming is a wonderful concept, but should be used to
standardize
> and optimize the attack on more difficult and complex problems.  Where the language itself, or common usage is simple and straightforward, and
handles the
> needs well it should go look for a richer vein.

Generally agree. Time will tell on this specific case. (I refer one to the pedagogical motivations of this example mentioned above)

> Where the implementation is common but has a lot of code, generics can
hide the
> complexity and standardize the solution; however if a simple call to a
library
> function or class can handle it well, do it that way.  Only where the
solution
> needs many options and hooks into a standardized method, or where the
coding is
> often done incompletely or wrong do I see a need.  There are uses where
building
> blocks can be created and stacked together to do a large number of
different
> things well.  There are uses which provide a framework for a very
generalized
> activity.  Any well-defined territory where there are established coding
methods
> can probably provide useful generics, but look beyond library functions to
more
> structural needs and usages.  Probably a lot of what is currently being
done
> with specialized classes could be refactored into templates handling a
wider
> variety of object types and simpler even more specialized classes.
>
> Suggestions beyond the current bounds (not for DTL):

Agreed. My intention - though I am aware I may be outvoted by the members of the ISO 2006 D Language Standards Committe - is that DTL is what the STL is to C++, and *not* what the standard library is. In other words, it's about containers and algorithms, and *not* about all the other ill-judged cack that got stuck in with it in C++, especially the IOStreams. If people want to write their streams to interroperate with DTL, or even to ape its interfaces, that's great, but I don't want to shove a load of nonsense - a la the forward declarations of many IOStream components into the basic_string<> implementation - into DTL that will do nothing but reduce it's simplicity, orthogonality and low coupling. It may be that D's lack of need for forward declarations will make this point moot, but if not I'll be a real stick in the mud until and unless I'm overruled.

> Business: standardized file matching skeltons (2-file, 3-file,
master/detail,
> etc), multi-currency methods, database interaction models?, lots more... Scientific: matrix operations, statistics, any area of math where a
special
> abbreviated terminology has developed and hides the underlying complexity.

Agreed. We needs lots of great libs. We're getting OT now, though, so I'll merely say I'm looking forward to a C implementation of the wildcards lib, for recls and STLSoft. ;)



March 23, 2004
larry cowan wrote:

>>>>A bit more DTL ranges, involving slices:
>>>>
>>>>    foreach(int i; range(-10, 10, +1)[6 .. 12])
>>>>    foreach(int i; range(-10, 10, +1)[3 .. ??])
>>>>    foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
>>>>    foreach(int i; with range(-10, 10, +1)[3 .. length])
>>>>    foreach(int i; with range(-10, 10, +1)[3 .. object.length])
>>>>Thoughts?
>>>>        
>>>>
>
>How is this more useful, readable, valuable than:
>
>for ( i = v1 ; i < v2 ; i += v3 )
>  
>
For one thing, you can pass this information by function parameter.

-- 
-Anderson: http://badmama.com.au/~anderson/
March 23, 2004
"J Anderson" <REMOVEanderson@badmama.com.au> wrote in message news:c3p9d5$oh2$1@digitaldaemon.com...
> larry cowan wrote:
>
> >>>>A bit more DTL ranges, involving slices:
> >>>>
> >>>>    foreach(int i; range(-10, 10, +1)[6 .. 12])
> >>>>    foreach(int i; range(-10, 10, +1)[3 .. ??])
> >>>>    foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
> >>>>    foreach(int i; with range(-10, 10, +1)[3 .. length])
> >>>>    foreach(int i; with range(-10, 10, +1)[3 .. object.length])
> >>>>Thoughts?
> >>>>
> >>>>
> >
> >How is this more useful, readable, valuable than:
> >
> >for ( i = v1 ; i < v2 ; i += v3 )
> >
> >
> For one thing, you can pass this information by function parameter.

Quite right! I forgot my one compelling advantage.

The start, end and increment can be passed by function params, but what about if you want the increment to be *=3, rather than +=3. This would lead to really hairy, and inefficient, coding. With a range, you don't have to worry about that, since the range knows how to do it's own "increment", whatever that may be.

Thanks JA. :)


March 23, 2004
Matthew wrote:

>"J Anderson" <REMOVEanderson@badmama.com.au> wrote in message
>news:c3p9d5$oh2$1@digitaldaemon.com...
>  
>
>>larry cowan wrote:
>>
>>    
>>
>>>>>>A bit more DTL ranges, involving slices:
>>>>>>
>>>>>>   foreach(int i; range(-10, 10, +1)[6 .. 12])
>>>>>>   foreach(int i; range(-10, 10, +1)[3 .. ??])
>>>>>>   foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
>>>>>>   foreach(int i; with range(-10, 10, +1)[3 .. length])
>>>>>>   foreach(int i; with range(-10, 10, +1)[3 .. object.length])
>>>>>>Thoughts?
>>>>>>
>>>>>>
>>>>>>            
>>>>>>
>>>How is this more useful, readable, valuable than:
>>>
>>>for ( i = v1 ; i < v2 ; i += v3 )
>>>      
>>>
>>For one thing, you can pass this information by function parameter.
>>    
>>
>
>Quite right! I forgot my one compelling advantage.
>
>The start, end and increment can be passed by function params, but what
>about if you want the increment to be *=3, rather than +=3. This would lead
>to really hairy, and inefficient, coding. With a range, you don't have to
>worry about that, since the range knows how to do it's own "increment",
>whatever that may be.
>
>Thanks JA. :)
>
>
>  
>

Well you could pass it as 3 params but what I meant to say is that you can create a reusable object and store it and pass as a block.  Make it a member of a class for a kinda state machine, use it for returning range or whatever.  Pairs can be very useful, no doubt  ranges (of which a pair is one type) will be useful.

Can ranges be staticly created?  I mean like when the min and max values stay the same.  In ada they were.

-- 
-Anderson: http://badmama.com.au/~anderson/
March 23, 2004
In article <c3p9r8$q36$1@digitaldaemon.com>, Matthew says...
>
>
>"J Anderson" <REMOVEanderson@badmama.com.au> wrote in message news:c3p9d5$oh2$1@digitaldaemon.com...
>> larry cowan wrote:
>>
>> >>>>A bit more DTL ranges, involving slices:
>> >>>>
>> >>>>    foreach(int i; range(-10, 10, +1)[6 .. 12])
>> >>>>    foreach(int i; range(-10, 10, +1)[3 .. ??])
>> >>>>    foreach(int i; range(-10, 10, +1)[3 .. range(-10, 10, +1).length])
>> >>>>    foreach(int i; with range(-10, 10, +1)[3 .. length])
>> >>>>    foreach(int i; with range(-10, 10, +1)[3 .. object.length])
>> >>>>Thoughts?
>> >>>>
>> >>>>
>> >
>> >How is this more useful, readable, valuable than:
>> >
>> >for ( i = v1 ; i < v2 ; i += v3 )
>> >
>> >
>> For one thing, you can pass this information by function parameter.
>
>Quite right! I forgot my one compelling advantage.
>
>The start, end and increment can be passed by function params, but what about if you want the increment to be *=3, rather than +=3. This would lead to really hairy, and inefficient, coding. With a range, you don't have to worry about that, since the range knows how to do it's own "increment", whatever that may be.
>
>Thanks JA. :)
>
Still don't see it. Even with

for (i=v1; i != v2%7 ;i=((i+2)*v3)%42)

it seems clearer than going on a search in other code to find out the rules that
are being used.  We are, however, still just talking about int stuff here.
Where external info (business rules) provide an adequate understanding of what
is being used all over in various ways, I may come around.
I have no problem with implementations of all sorts of common and useful
collection types where the same can be said of programmer concepts (external
info), but I still don't see where ranges fit in.
I should get your current DTL status file - I think you posted it or a link, but
I missed it.  Please repeat it if you did.  I should look through that before I
blow any more hot air.

-larry


March 23, 2004
In article <c3pels$11s8$2@digitaldaemon.com>, J Anderson says...
>
>Matthew wrote:
>

Put my vote in for python syntax

slice[x:y], slice[:3], slice[:4], slice[1:-1], etc.

slice[:] forces a copy, I think, somebody correct me if I'm wrong.

If the colon is a parsing problem, then .. is ok, but changing to colon would force a lot of current code to be updated (easy grep for \.\.) to replace awkward xxxxxxxxxxxx.length-y constructs.  The empty left or right side should make a 0 at the left unnecessary and the implied begin/end should make negative right-side values easily interprable with +x on the left the same as just x. This is far better than forcing a new symbol or keyword into being.

-larry


March 23, 2004
Update: The reasoning on negative index isn't right, because we need it in the left side as well:  slice[-3,-1] for the last 2 chars, etc.  But I still think it's the right way to go.

In article <c3pl6n$1ebh$1@digitaldaemon.com>, larry cowan says...
>
>In article <c3pels$11s8$2@digitaldaemon.com>, J Anderson says...
>>
>>Matthew wrote:
>>
>
>Put my vote in for python syntax
>
>slice[x:y], slice[:3], slice[:4], slice[1:-1], etc.
>
>slice[:] forces a copy, I think, somebody correct me if I'm wrong.
>
>If the colon is a parsing problem, then .. is ok, but changing to colon would force a lot of current code to be updated (easy grep for \.\.) to replace awkward xxxxxxxxxxxx.length-y constructs.  The empty left or right side should make a 0 at the left unnecessary and the implied begin/end should make negative right-side values easily interprable with +x on the left the same as just x. This is far better than forcing a new symbol or keyword into being.
>
>-larry
>
>


March 23, 2004
I meant:

>Update: The reasoning on negative index isn't right, because we need it in the left side as well:  slice[-3:] for the last 3 chars, etc.  But I still think it's the right way to go.