digitalmars.D - Re: integer division with float result
- Bruce Adams <tortoise_74 yeah.who.co.uk> Nov 18 2007
- 0ffh <frank frankhirsch.youknow.what.todo.net> Nov 18 2007
- 0ffh <frank frankhirsch.youknow.what.todo.net> Nov 18 2007
- Bruce Adams <tortoise_74 yeah.who.co.uk> Nov 18 2007
- 0ffh <frank frankhirsch.youknow.what.todo.net> Nov 18 2007
- 0ffh <frank frankhirsch.youknow.what.todo.net> Nov 18 2007
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
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
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
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
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
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