www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Re: integer division with float result

reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
0ffh Wrote:

 Bruce Adams wrote:
 
 Here's another (non-D?) thought. How about overloading on the return
 type? In a strongly typed language its only convention that makes the
 return type somehow special. I believe the original reason for return
 values being special may have been that they are the only things left on
 the stack when returning from a function call. This was only true early
 on when all arguments were passed by value. We don't seem to have moved
 beyond that, we only tease around the edges with covariant returns and
 returning multiple values but semantically there's no difference
 between: [...] So why do we still insist on it in modern languages?
 
 Regards,
 
 Bruce.

Return type overloading is not practical, or at least not without solving a few problems first. What return type would you expect from the function? Okay, in an assignment it's clear. What about function calls in expressions? What if you have overloaded foo to return int or float, and bar to return int or float. Then go and call bar(foo())... oooopsie! =) And it's not always as easy as just int or float; think arbitrary types! Okay, there are solutions to all this, but the only reasonable ones I know need extra hints for the compiler (some kind of syntax extension, or building a new semantic upon an available syntax). Regards, Frank

I suspect what is required is type inference a la ML. So in the case of (in the following feel free to replace X with divde, Y with print and R with random if that makes it easier to read). int X(int a) long X(long b) void Y(int y) void Y(long y) void Z(int y) void Q(long y) int a = 1; long b = 2; Z(X(a)) is legal (no ambiguity) Q(X(b)) is legal (no ambiguity) Y(X(a)) - infer use of Y(int) because X(int) because a = int Y(X(b)) - infer use of Y(long) because X(long) because b = long The only place you have real ambiguity is: int R(void) long R(void) so X(R()) is ambiguous and should thus cause a compile error. It must be replaced with either: int temp = R(); X(temp) or X(cast(int)R()) This is trivial to implement in a compiler the type inference is a little more tricky (though Walter did say he was interested in adding functional programming features to D ;-). I think a good syntactic sugar to use for that would be named parameters, which are useful for so many other reasons (but much less trivial to implement) So Y(int Int) Y(long Long) would allow X(Y(Int)) unfortunately this doesn't solve the problem for R because the return type cannot be named So casting cannot be eliminated entirely that way but it can be significantly reduced. That's got to be a good thing surely? Regards, Bruce.
Nov 18 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bruce Adams wrote:
 So casting cannot be eliminated entirely that way but it can be
 significantly reduced. That's got to be a good thing surely?

Well, the use of a cast as hint for the compiler looks like a rather nice choice. But then I don't quite see how it improves the thing about integer and float division apart from the case of assignments. Take: void foo(int); void foo(float); As it is now, I have for example int i,j; float f; [...] i=i/j; // implicit int f=cast(float)i/j; // explicit float foo(i/j); // implicit int foo(cast(float)i/j); // explicit float With return type overloading I get int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit float foo(i/j); // compiler error: under-determined type information foo(cast(int)i/j); // explicit int foo(cast(float)i/j); // explicit float So now there are just different cases where a cast is needed. For some people I am sure the case with overloaded return types has more appeal, but for others it is different. It's just a matter of tastes, really, as the C way is no more complicated than the other way. It is just not what many people expect at first. I can't yet see how this small improvement is worth the trouble implementing. Regards, frank
Nov 18 2007
next sibling parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 With return type overloading I get
   [...]
   foo(cast(int)i/j); // explicit int
   foo(cast(float)i/j); // explicit float

Oops; this is with syntactic sugar, BTW, as I was just casting the first operand, not the expression. Otherwise foo(cast(int)(i/j)); // explicit int foo(cast(float)(i/j)); // explicit float (The current style example should work as it is.) Regards, Frank
Nov 18 2007
prev sibling parent reply Bruce Adams <tortoise_74 yeah.who.co.uk> writes:
0ffh Wrote:

 Bruce Adams wrote:
 So casting cannot be eliminated entirely that way but it can be
 significantly reduced. That's got to be a good thing surely?

Well, the use of a cast as hint for the compiler looks like a rather nice choice. But then I don't quite see how it improves the thing about integer and float division apart from the case of assignments. Take: void foo(int); void foo(float); As it is now, I have for example int i,j; float f; [...] i=i/j; // implicit int f=cast(float)i/j; // explicit float foo(i/j); // implicit int foo(cast(float)i/j); // explicit float With return type overloading I get int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit float foo(i/j); // compiler error: under-determined type information foo(cast(int)i/j); // explicit int foo(cast(float)i/j); // explicit float So now there are just different cases where a cast is needed. For some people I am sure the case with overloaded return types has more appeal, but for others it is different. It's just a matter of tastes, really, as the C way is no more complicated than the other way. It is just not what many people expect at first. I can't yet see how this small improvement is worth the trouble implementing. Regards, frank

Well I wasn't advocating a change to D (yet). Hence the non D in my original post. It was more a thought experiment. Your use case above is certainly a compelling reason not to do it this way, at least for division. I wonder if there is not a way of having the best of both worlds. Still, I begin to see why others want a seperate div operator. I shall ponder some more...
Nov 18 2007
parent reply 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
Bruce Adams wrote:
 0ffh Wrote:
 With return type overloading I get
 
 int i,j; float f; [...] i=i/j; // implicit int f=i/j; // implicit 
 float foo(i/j); // compiler error: under-determined type information 
 foo(cast(int)i/j); // explicit  int
 foo(cast(float)i/j); // explicit float
 [...btw. thunderbird rewrapping does strange things to those lines...]

Well I wasn't advocating a change to D (yet). Hence the non D in my original post. It was more a thought experiment. Your use case above is certainly a compelling reason not to do it this way, at least for division. I wonder if there is not a way of having the best of both worlds. Still, I begin to see why others want a seperate div operator. I shall ponder some more...

Far be it from me to add to the plethora of D feature requests, but one possible solution might be giving an explicit precedence hierarchy to the compiler at one point, e.g. void foo(int){...} void foo(float){...} precedence foo(float) > foo(int); could in case of ambiguity choose float over int. But I'm not quite sure this could not backfire in some way... Regards, frank
Nov 18 2007
parent 0ffh <frank frankhirsch.youknow.what.todo.net> writes:
0ffh wrote:
 precedence foo(float) > foo(int);

Nah, that's bull shite. We were talking return type overloading, so make that precedence float opDiv(int,int) > int opDiv(int,int); Good thing is, in my code I could adhere to the classic way. =) regards, frank (sleepy)
Nov 18 2007