May 12, 2002
"Sean L. Palmer" <spalmer@iname.com> wrote in message news:abl6cj$1f1g$1@digitaldaemon.com...
> typedef float[4] vector;
> vector a,b,c;
> a[] += b[] * c[];
> which the compiler can easily tell what you intend, but what are the rules
> for what happens when the sizes of the arrays don't match?  What happens
if
> they're multidimensional?

That would be a runtime error.

> D can also already do this:
>
> a[1..3] += b[1..3] * c[1..3];
>
> If one defined a range like so:
>
> range int r = 1..3;
> a[r] += b[r] * c[r];
>
> would work as convenient shorthand.

I never thought of that.

> For multidimensional slicing, it could work as follows:
>
> typedef float[4][4] matrix;
> matrix a,b,c;
> range(int) i = 1..3;
> range(int) j = 1..3;
> a[i][j] = 2.0f * sqrt(b[i][j] + c[i][j+1]);

D doesn't currently allow multidimensional slicing, though it's an obvious future extension.

> The order of evaluation is undefined however it would be nice if one could control this behavior so that overlapping moves do the right thing.  It should be possible to figure out whether to go forward or backward for
each
> range by evaluating the dependencies in the graph of information flow.

The best thing to do with overlapping ranges is disallow them. That cleans up the semantics, and enables better code generation.


May 12, 2002
Sean L. Palmer wrote:
> I wonder if C++ has ever
> considered a "lossy" modifier ("typedef unsigned lossy long color", which
> would represent a data type that will be dealing with potentially 64 bit
> values but if it couldn't do that, or it wasn't fast to use longs and you'd
> selected high optimization settings, it could substitute a smaller type)

This seems like such a small incremental win (an
occasional increase in portability for certain kinds
of code) for the effort it would take to specify and
implement the feature that I don't see any language
doing it anytime soon. Of course, you could put it
in a class via operator overloading; it's up to the
library implementor to port it instead of the compiler
implementor.
> 
> I'd actually like to see bounded int types in the language.  Saturating int,
> call it whatever you want.  Something that the hardware "tops out" or clamps
> to the allowed range before storing into.  Alot of CPU's support this
> concept,

Not very many architectures do, and not very generally,
though...

> but no language that I know of ever has.  It's something the
> compiler could do for you automatically (using software emulation if
> necessary), and would sure be a convenient timesaver. 

Yeah, I called for this one a while ago. You should be able
to use it on floats and in arbitrary non-power-of-two ranges as
well. Besides arbitrary saturating ranges, arbitrary wrapping
ranges would be nice as well.

typedef saturated( 1, 5 ) char review_rating;	// 1 to 5 stars

typedef wrapped( 0.0, 2.0*3.14159265358 ) float phase_angle;

wrapped types would effectively do a % or fmod every time they
were evaluated unless the compiler could guarantee they were
already in-range.

> Have you ever written code to do bilinear filtering?  Conceptually it's
> given 2 inputs and a 2d array, does 4 lookups, 2 "frac" modulo 1.0
> operations, and blend the results together using 3 linear interpolations...
>
> Not sure what kind of language feature would make that kind of mess easier
> to deal with.

I've been playing with audio DSP stuff lately, and (usually
1D) interpolations and fmod(x,1.0) or f-int(f) are also
heavily used therein. I have no trouble with this stuff as
part of a standard library, but I'm less comfortable with
making it part of the language.

-Russell B

May 12, 2002
"Walter" <walter@digitalmars.com> wrote in message news:abl940$1h50$1@digitaldaemon.com...
> You're far beyond me in graphics code. But one possibility for easilly generating loop code would be to, say, build a simple compiler for a specialized language that generated D code. I use similar kinds of things for building tables. This would be easilly modifiable to generate custom code.

This array manipulation is just the basics of graphics code.  Everything today uses polygons, not rectangles.  I have some ideas for representing triangles in D but I'll save it til the right time.

Sean


May 12, 2002
"Walter" <walter@digitalmars.com> wrote in news:abm4c0$25l6$1@digitaldaemon.com:
> 
> The best thing to do with overlapping ranges is disallow them. That cleans up the semantics, and enables better code generation.

I understand your reasons for disallowing overlapping ranges but
it seems to make the language less consistant.  Would it be a
problem to have a small check at the begining of a copy to check
for overlapping ranges and switch between two differnt copy routines
based on the result?

May 12, 2002
"Walter" <walter@digitalmars.com> wrote in message news:abm4c0$25l6$1@digitaldaemon.com...
> > The order of evaluation is undefined however it would be nice if one
could
> > control this behavior so that overlapping moves do the right thing.  It should be possible to figure out whether to go forward or backward for
> each
> > range by evaluating the dependencies in the graph of information flow.
>
> The best thing to do with overlapping ranges is disallow them. That cleans up the semantics, and enables better code generation.

I'd weigh carefully before making it illegal.  People use memcpy and strcpy with overlapping all the time.  I'd strongly suggest trying to make the compiler "do the right thing".  I suppose someone could always write their own (probably non-optimal) move function that deals with this.

There are simple rules for it for 1d overlapping array copies:

if source doesn't overlap destination, do it however you please, i.e.
whatever's fastest.
if source begin is equal to destination begin, nothing needs to be done so
long as you're just copying (math ops would still need to be done)
if source begin is less than destination begin, iterate from the end to the
start
if source begin is greater than destination begin, iterate from the start to
the end

I think these rules could be easily extended to multiple dimensions, by applying the same rule separately for each dimension.

If you ignore these rules, and do it the other way, what it actually accomplishes is a "pattern fill" where the pattern size is equal to the offset between the starts of the ranges.  But that's not what the user asked for, they wanted the entire range copied intact.

One could see problems arise when the copy was to be done using a larger memory unit than the size of the type, such as copy using 128-bit blocks. But those kinds of copies usually have to be aligned anyway so the compiler would have to know the addresses at compile time or a "copy dispatch" wrapper would have had to decide that the large block move is ok.  If not, it does the slower "one item at a time" move.

Here again we have an arbitrary decision to limit a language feature just because it makes the compiler implementation a bit easier.  At least with your solution we don't end up with a language that doesn't specify the behavior ("implementation-defined" ala C++)  ;)

Sean


May 12, 2002
"Patrick Down" <pat@codemoon.com> wrote in message news:Xns920C89BAF31DApatcodemooncom@63.105.9.61...
> "Walter" <walter@digitalmars.com> wrote in news:abm4c0$25l6$1@digitaldaemon.com:
> >
> > The best thing to do with overlapping ranges is disallow them. That cleans up the semantics, and enables better code generation.
>
> I understand your reasons for disallowing overlapping ranges but
> it seems to make the language less consistant.  Would it be a
> problem to have a small check at the begining of a copy to check
> for overlapping ranges and switch between two differnt copy routines
> based on the result?

That's how memcpy is usually implemented.  If everything about the addresses involved is known at compile time, the compiler can select between several different code snippet templates to generate the code, ranging from completely unoptimized all the way down to just completely unrolling the loop.

I know this feels like one of the basics, Walter, and I know you're itching to move on to bigger and better things, but the fact that moving blocks of data is one of the basics of computing indicates that it needs robust language support, not special cases.

Sean



May 12, 2002
"Sean L. Palmer" <spalmer@iname.com> wrote in message news:abl6cj$1f1g$1@digitaldaemon.com...
> I've been thinking about this and it seems that it might be better to
extend
> the slicing mechanism D already has.
>
> D already has:
>
> typedef float[4] vector;
> vector a,b,c;
> a[] += b[] * c[];
>
> which the compiler can easily tell what you intend, but what are the rules for what happens when the sizes of the arrays don't match?  What happens
if
> they're multidimensional?
>
> D can also already do this:
>
> a[1..3] += b[1..3] * c[1..3];
>
> If one defined a range like so:
>
> range int r = 1..3;
> a[r] += b[r] * c[r];
>
> would work as convenient shorthand.

Yup.  That is one of the nice things you can do to extend the syntax once you have ranges.  Another is to symplify the common case of loop variables incrementing by 1.

range int r = 1..10;
For (r)
  . . .

etc.  And, since they are defined at compile time, the range variable name can be used to specify the size of an array.

There are a lot of advantages in maintainability since you can change the range in one place and it automaically gets all the places.

--
 - Stephen Fuld
   e-mail address disguised to prevent spam


May 12, 2002
Sean L. Palmer wrote:
> "Patrick Down" <pat@codemoon.com> wrote in message
> news:Xns920C89BAF31DApatcodemooncom@63.105.9.61...
>>I understand your reasons for disallowing overlapping ranges but
>>it seems to make the language less consistant.  Would it be a
>>problem to have a small check at the begining of a copy to check
>>for overlapping ranges and switch between two differnt copy routines
>>based on the result?
> 
> 
> That's how memcpy is usually implemented.

ITYM memmove(); C standard memcpy() has undefined behavior
for overlapping ranges, and I'd consider it a violation of
the implicit performance contract for memcpy() to check the
ranges.

-RB

May 12, 2002
Stephen Fuld wrote:
> "Sean L. Palmer" <spalmer@iname.com> wrote in message
> news:abl6cj$1f1g$1@digitaldaemon.com...

>>If one defined a range like so:
>>
>>range int r = 1..3;
>>a[r] += b[r] * c[r];
>>
>>would work as convenient shorthand.
> 
> 
> Yup.  That is one of the nice things you can do to extend the syntax once
> you have ranges.  Another is to symplify the common case of loop variables
> incrementing by 1.
> 
> range int r = 1..10;
> For (r)
>   . . .
> 

Eeek! I would beg for a distinct keyword like "foreach" in
both those cases to make it totally clear that these
were vectorized/iterated/looped operations in cases
where the range definition was far away from the range
usage:

range int r = 1..3;

foreach (r) { a[r] += b[r] * c[r]; }

Other than that, it's good.

-RB

May 14, 2002
"Sean L. Palmer" <spalmer@iname.com> wrote in message news:abmetg$2e7i$1@digitaldaemon.com...
> I know this feels like one of the basics, Walter, and I know you're
itching
> to move on to bigger and better things, but the fact that moving blocks of data is one of the basics of computing indicates that it needs robust language support, not special cases.

You're right, it is a basic thing, and I have not just blown it off. I use memcpy() very regularly, and I depend on it. With a few observations, I think you'll see my reasoning for disallowing overlapping copies, even if you don't agree with it:

1) 99% of memory copies are not overlapping.
2) overall program performance tends to be sensitive to memcpy speed.
3) putting the test in for each copy will sacrifice performance and add
bloat to satisfy only 1% of the cases.
4) I've seen memcpy code that *relied* on the wrong way overlapping copy
behavior.
5) Because of (4), I think if one needs to do an overlapping copy, one does
need to decide just what it means to do an overlapping copy, and explicitly
code appropriately. Leaving it implicit can be misleading.
6) In debug builds, checks for overlapping are inserted, so one will not
inadvertantly fall prey to copy direction bugs.
7) And most importantly, it gets rid of the "aliasing" problem C has that
prevents array operations from being compiled as efficiently as FORTRAN.