February 26, 2004
Roberto Mariottini wrote:

> IMHO narrowing casts (and sign casts) should be handled with care, not simply
> doing cast(something) expression:
> 
> [... more code ...]
> i = saturate(f);     // same as before
> i = precise(f);      // f must be an integer of the rignt range
> i = floor(f);
> i = round(f);
> i = ceil(f);
> 
> I know theese functions can be user defined, but I think it's better to help the
> user to use them, disallowing implicit narrowing conversions.

There's a big catch to this approach due to the way function overloading works.  For any one input type, someone could want to convert to any number of types.  So you'd need methods like saturateToFloat, (or some templating) which gets a little on the verbose side.

Aside from that, it's an elegant solution.  No extra syntax needs to be added to the language, and what the code is doing is crystal clear.

 -- andy
February 26, 2004
Walter wrote:

>
>You have some good points. One problem with casts is that they can mask bugs
>because the compiler will do whatever it takes to satisfy the cast. 
>
I think I know what you mean here but I can't think of any good examples, anyone?

>Another problem with doing away with implicit narrowing conversions is:
>
>    char a,b,c;
>    c = a + b;
>
>will no longer be valid because of the integral promotion rules. 
>
Why not make this kinda situation implicit?  I mean from the viewers point of view (most of the time) it is simply the addition of two characters.

>One could
>say get rid of the integral promotion rules, but then D will have a subtle
>semantic difference from C:
>
>    a = 128;
>    b = 128;
>    int i = a + b;    // 256 in C, 0 in D
>
>which is unacceptable. One possibility might be to just disallow implicit
>narrowing conversions from long to int.
>  
>
Then user should be force to cast to int.

ie
//if the user wanted 256
char a, b;
int i = (int) (a + b); //Even though a and b would really be using integer maths anyway.

//if the user wanted 0
int i = (int) ((byte) a + (byte) b);

Or parhaps
int i = (int) a + (byte) b; //b is added using byte addion and then it's converted to an int
or
int i = (byte) a + (byte) b; //implicit conversion from a cast byte

-- 
-Anderson: http://badmama.com.au/~anderson/
February 26, 2004
On Wed, 25 Feb 2004 15:13:31 -0800, Andres Rodriguez <rodriguez@ai.sri.com> wrote:

> One more vote for explicit casting.

Hi, I agree but how about:

	uint a = 123456789;
	ubyte b;
	b = narrow(a);

and than let the compiler apply the default rule as it does at the moment. Casting is to me a much rougher action than narrowing. The narrow will state that I know what I'm doing. Robert
February 26, 2004
Robert M. Münch wrote:

> On Wed, 25 Feb 2004 15:13:31 -0800, Andres Rodriguez  <rodriguez@ai.sri.com> wrote:
>
>> One more vote for explicit casting.
>
>
> Hi, I agree but how about:
>
>     uint a = 123456789;
>     ubyte b;
>     b = narrow(a);
>
> and than let the compiler apply the default rule as it does at the moment.  Casting is to me a much rougher action than

You do still mean that the narrow word is required?

> narrowing. The narrow will  state that I know what I'm doing. Robert

This is a good idea. I think it overcomes one of the problems Walter mentioned before.

Walter:

>One problem with casts is that they can mask bugs
>because the compiler will do whatever it takes to satisfy the cast. 
>
Another advantage is it's grepable, so you could easily stop these if trying to optimise narrowing conversions.

However I would prefer a shorter term then narrow.

Humm, what-about:
trim()
clip()
cut()

I'm sure there are better terms, smaller terms, although narrow is ok.

-- 
-Anderson: http://badmama.com.au/~anderson/
February 26, 2004
In article <c1k66n$212i$1@digitaldaemon.com>, J Anderson says...
>
>
>Vote for explicit casting.  The programmer needs to explicitly mention his intentions.  I think the code will be wrong most of the time and need fixing (how often do we use narrowing anyways?).
>
>-- 
>-Anderson: http://badmama.com.au/~anderson/

Hear hear.


February 26, 2004
Roberto Mariottini wrote:
> 
> There are obvious solutions:
> 
> - don't use chars for math

If there were a byte type then I wouldn't mind this, otherwise forget it.

> - don't use chars to do math that exceeds char's bounds (as you normally don't
> use int math that exceeds int's bounds). An OverflowException here could help,
> we discussed about this some time ago.

This would be fine, though it gives rise to some odd problems.  What if I do this:

char c = 1;
c <<= 10;

Overflow from bit shifting can be a desired effect.  I certainly wouln't want to have an exception thrown.

> - Throw away your old badly-written C code.

Works for me.


> b = -1;
> u = extract_bits(b); // u = unsigned_little_int.max
> u = saturate(b);     // u = 0
> u = precise(b);      // throw NarrowCastException

Ugh.  So I have to wait until run time to find out I'd done something illegal?  And this is something that could have been detected at compile time?  Overflow errors are one thing, but this is a bit extreme.

> I know theese functions can be user defined, but I think it's better to help the
> user to use them, disallowing implicit narrowing conversions.

That still doesn't address the integer promotion issue.  Should the compiler perhaps continue to allow implicit casting as a result of integer promotion if the widest involved type in the expression is smaller than or equal to the size of the result type?  ie.

char c1, c2, c3;
short s1, s2, s3;
unsigned u1;
float f1;

c1 = c2 + c3; // legal
c1 = c2 + s3; // illegal, s3 is wider than c1
s1 = c2 + s3; // legal
u1 = u1 + f1; // equal byte sizes but one is float

What should be done about the last case?  Should implicit conversion from float to int be allowed?


Sean

February 26, 2004
Robert M. Münch wrote:
> 
> Hi, I agree but how about:
> 
>     uint a = 123456789;
>     ubyte b;
>     b = narrow(a);
> 
> and than let the compiler apply the default rule as it does at the moment.  Casting is to me a much rougher action than narrowing. The narrow will  state that I know what I'm doing.

I agree.  If we're going to restrict implicit narrowing then a narrow cast with the above semantics is a good idea.


Sean

February 26, 2004
This shows promise as it handles the argument-passing case also. Plus, it's really hard to overlook during routine maintenance, *and* it's easy to find all these special-cases with a grep :-)

You might consider applying the verb "demote" instead of  "narrow".

- Kris


"Robert M. Münch" <robert.muench@robertmuench.de> wrote in message news:opr3zg6xv3heztw6@news.digitalmars.com...
> On Wed, 25 Feb 2004 15:13:31 -0800, Andres Rodriguez <rodriguez@ai.sri.com> wrote:
>
> > One more vote for explicit casting.
>
> Hi, I agree but how about:
>
> uint a = 123456789;
> ubyte b;
> b = narrow(a);
>
> and than let the compiler apply the default rule as it does at the moment. Casting is to me a much rougher action than narrowing. The narrow will state that I know what I'm doing. Robert


February 26, 2004
J Anderson wrote:

> Walter wrote:
>
>> You have some good points. One problem with casts is that they can mask bugs
>> because the compiler will do whatever it takes to satisfy the cast.
>
> I think I know what you mean here but I can't think of any good examples, anyone?


Just thought of one:

//module 1
char getValue() {...}

//module 2

class A {}

A getValue() {...}

void func()
{
   int x = (int) getValue(); //Calls the wrong version, converting the reference A into an int
}

Of course in this case using the suggested narrow (suggested by Munch) would solve the problem.

-- 
-Anderson: http://badmama.com.au/~anderson/
February 26, 2004
On Thu, 26 Feb 2004 16:26:47 +0100 (02/27/04 02:26:47)
, Robert M. Münch <robert.muench@robertmuench.de> wrote:

> On Wed, 25 Feb 2004 15:13:31 -0800, Andres Rodriguez  <rodriguez@ai.sri.com> wrote:
>
>> One more vote for explicit casting.
>
> Hi, I agree but how about:
>
> 	uint a = 123456789;
> 	ubyte b;
> 	b = narrow(a);
>
> and than let the compiler apply the default rule as it does at the moment.  Casting is to me a much rougher action than narrowing. The narrow will  state that I know what I'm doing. Robert

Yes, this will do nicely. Whether its 'narrow' or something else is not the point. What is important is that both the compiler and the coder are made explicitly aware of what is being attempted. This will reduce 'surprises' (a.k.a. bugs). It also makes it easy for an implementation of D to have this as a runtime-behaviour (a 'D' interpreter for example).

-- 
Derek