Jump to page: 1 26  
Page
Thread overview
The purpose of opCast?
Feb 19, 2005
Derek
Feb 19, 2005
John Demme
Feb 19, 2005
Norbert Nemec
Feb 20, 2005
Regan Heath
Feb 20, 2005
Norbert Nemec
Feb 21, 2005
Georg Wrede
Feb 21, 2005
Derek
Feb 21, 2005
xs0
Feb 21, 2005
xs0
Feb 21, 2005
Regan Heath
Feb 21, 2005
Regan Heath
Feb 22, 2005
xs0
Feb 22, 2005
Regan Heath
Feb 22, 2005
xs0
Feb 22, 2005
Regan Heath
Feb 22, 2005
xs0
Feb 22, 2005
Georg Wrede
Feb 22, 2005
Regan Heath
Feb 22, 2005
brad
Feb 22, 2005
Regan Heath
Feb 22, 2005
brad
Feb 22, 2005
Regan Heath
Feb 23, 2005
brad
Feb 23, 2005
Regan Heath
Feb 24, 2005
Charles Hixson
Feb 24, 2005
Regan Heath
Feb 25, 2005
Charles Hixson
Feb 26, 2005
Georg Wrede
Feb 27, 2005
Regan Heath
Feb 24, 2005
Georg Wrede
Feb 23, 2005
xs0
Feb 23, 2005
Regan Heath
Feb 23, 2005
xs0
Feb 23, 2005
Regan Heath
Feb 23, 2005
xs0
Feb 23, 2005
Regan Heath
Feb 24, 2005
xs0
Feb 24, 2005
Regan Heath
Feb 22, 2005
Georg Wrede
Feb 22, 2005
Regan Heath
Feb 22, 2005
Derek Parnell
Feb 22, 2005
Georg Wrede
Feb 21, 2005
Derek
Feb 22, 2005
xs0
Feb 22, 2005
Chris Sauls
Feb 22, 2005
Regan Heath
Feb 22, 2005
Chris Sauls
Feb 23, 2005
Regan Heath
Feb 23, 2005
Chris Sauls
Feb 23, 2005
Regan Heath
Feb 23, 2005
xs0
Feb 23, 2005
Derek Parnell
Feb 23, 2005
Kris
Feb 23, 2005
xs0
Feb 23, 2005
Regan Heath
Feb 23, 2005
Kris
Feb 23, 2005
Derek Parnell
Feb 23, 2005
Chris Sauls
Feb 23, 2005
xs0
February 19, 2005
I know this is a "squeaky wheel", but has anyone found a good reason to use the current opCast overloading? To me it still seems like a half-baked idea that does nobody any good yet. I suspect its just that I don't understand what it was designed to do (read: what is the problem it is trying to solve).

-- 
Derek
Melbourne, Australia
February 19, 2005
Although I haven't found a good use for it yet, it's a matter of symmetry.  In D, I can overload *all* of the operators that primitives can use, and thusly replace a primitive with a class with very little effort.  Since primitives can be cast, there should be an operator overload for it.

Or at least that's my opinion.

John

Derek wrote:
> I know this is a "squeaky wheel", but has anyone found a good reason to use
> the current opCast overloading? To me it still seems like a half-baked idea
> that does nobody any good yet. I suspect its just that I don't understand
> what it was designed to do (read: what is the problem it is trying to
> solve).
> 
February 19, 2005
John Demme schrieb:
> Although I haven't found a good use for it yet, it's a matter of symmetry.  In D, I can overload *all* of the operators that primitives can use, and thusly replace a primitive with a class with very little effort.  Since primitives can be cast, there should be an operator overload for it.

But at best, it is a half-hearted attempt to cover up the asymmetry without really solving it.

Primitives can be cast to various types. opCast can be overloaded only for one target type.

Primitives can be casted implicitely. opCast only works for explicit casts.

The easiest solution for the first restriction could be learned from C++: change the specs in such a way that opCast takes one dummy argument of the same type as the return type.
	... cast(sometype)(someobject) ...
would then be equivalent to
	sometype dummyvar;
	... someobject.opCast(dummyvar) ...

For the second restriction the biggest hurdle might be to convince Walter that implicit casting is essential for the extensibility of the language. So far, he seems to be strictly against implicit casting (except for the builtin types, of course.)
February 20, 2005
On Sat, 19 Feb 2005 11:53:02 +0100, Norbert Nemec <Norbert@Nemec-online.de> wrote:
> John Demme schrieb:
>> Although I haven't found a good use for it yet, it's a matter of symmetry.  In D, I can overload *all* of the operators that primitives can use, and thusly replace a primitive with a class with very little effort.  Since primitives can be cast, there should be an operator overload for it.
>
> But at best, it is a half-hearted attempt to cover up the asymmetry without really solving it.
>
> Primitives can be cast to various types. opCast can be overloaded only for one target type.
>
> Primitives can be casted implicitely. opCast only works for explicit casts.

Some can, to some types, this seems to have been decided on a case by case basis.

I vaguely remember that some of these cases bothered me, but I can't remember which ones exactly.. maybe someone else can?

> The easiest solution for the first restriction could be learned from C++: change the specs in such a way that opCast takes one dummy argument of the same type as the return type.
> 	... cast(sometype)(someobject) ...
> would then be equivalent to
> 	sometype dummyvar;
> 	... someobject.opCast(dummyvar) ...

IMO this is a 'hack', surely we can do better, that is, if we want to do this at all.

I understand that overloading by return type has 'issues' of complexity, however, if the cast was always explicit...

I realise people don't like 'special-case' behaviour i.e. making opCast the only thing that overloads by return type... Does it make sense, is it possible, to allow overloads by return type for everything, giving an error where it's indeterminate and requiring and explicit cast.

> For the second restriction the biggest hurdle might be to convince Walter that implicit casting is essential for the extensibility of the language. So far, he seems to be strictly against implicit casting (except for the builtin types, of course.)

It's the classic trade off, implicit vs explicit, ease-of-use non-obvious behaviour vs verbose obvious behaviour. Everyone draws the line in a different place.

The difference between a class and primitives is that Walter can define casts that should be implicit and ones that shouldn't for primitives. He has no way of doing the same with classes, so takes the safest option making them all explicit. All FWICS and IMO of course.

Regan
February 20, 2005
Regan Heath schrieb:
> Does it make sense, is it  possible, to allow overloads by return type for everything, giving an  error where it's indeterminate and requiring and explicit cast.

I think, it would make parsing a mess. Currently, the type of an expression can always be determined bottom up: determine the types of the leaves and from there construct the type of the whole expression deterministically. If you break this up, the language becomes a mess. (C/C++ had a few exceptions which were cleaned out in D)

>> For the second restriction the biggest hurdle might be to convince  Walter that implicit casting is essential for the extensibility of the  language. So far, he seems to be strictly against implicit casting  (except for the builtin types, of course.)
> 
> It's the classic trade off, implicit vs explicit, ease-of-use non-obvious  behaviour vs verbose obvious behaviour. Everyone draws the line in a  different place.

Of course. Language design consists of drawing lines and making decisions. Neither language design nor any other art mix too well with democracy.

Still, since the artwork 'D' is still in progress, the lines that have been drawn before might slowly evolve...
February 21, 2005

Norbert Nemec wrote:
> Regan Heath schrieb:
> 
>> Does it make sense, is it  possible, to allow overloads by return type for everything, giving an  error where it's indeterminate and requiring and explicit cast.

Interesting thought.

At first sight, the compiler could surely use the return type
as well as argument types in overload resolution. Or could it?

Are there any strong reasons for not doing this?

OTOH, is it really needed? Or what reasons are there against it?
February 21, 2005
On Mon, 21 Feb 2005 12:16:13 +0200, Georg Wrede wrote:

> Norbert Nemec wrote:
>> Regan Heath schrieb:
>> 
>>> Does it make sense, is it  possible, to allow overloads by return type for everything, giving an  error where it's indeterminate and requiring and explicit cast.
> 
> Interesting thought.
> 
> At first sight, the compiler could surely use the return type as well as argument types in overload resolution. Or could it?
> 
> Are there any strong reasons for not doing this?
> 
> OTOH, is it really needed? Or what reasons are there against it?

The main one seems to be, what would happen if someone coded a function call but did not assign the return to anything? How would the compiler know which signature to use if it had to use return-type as a determinate?

 eg.

    int foo(char a) { . . . return 1;}
    real foo(char a) { . .  . return 1.0; }
    void bar(int x) {  . . . }
    void bar(real x) { . . . }

    foo('x');  // Does this return an int or real?
    bar( foo('y') ); // Which 'bar' is to be called?

To counter this, one could make the rule that every call to a function must either assign the result or indicate to the compiler which return type is being ignored/required. This would help make programs more robust and help readers know the coder's intentions better.

For example...
   cast(int)foo('x');  // Call the 'int' version and ignore the result.
   bar( cast(real)foo('y') ); // Call the 'real' version of foo and bar.

-- 
Derek
Melbourne, Australia
February 21, 2005

> The main one seems to be, what would happen if someone coded a function
> call but did not assign the return to anything? How would the compiler know
> which signature to use if it had to use return-type as a determinate?

Well, that's not the only "main" issue, imho.. For example, consider:

int mysqrt(double a) {
   return floor(sqrt(a));
}

double eval_some_cost(...)
{
    double cost=sqrt(..);

    if (something)
        cost*=1.3;

    return cost;
}

Now, this works fine and all. But, I (or my co-worker) can decide sometime in the future that there should also be a double mysqrt(double) returning the unrounded square root (or even something completely different, but that is bad style, I guess). The problem is that without any change in either the int version or in eval_some_cost(), the code will produce different results. This is most probably the reason why ambiguous function calls are not allowed and you need to be explicit which version you want to use.


> For example...
>    cast(int)foo('x');  // Call the 'int' version and ignore the result.
>    bar( cast(real)foo('y') ); // Call the 'real' version of foo and bar.

Hmm, but there's no casting, so why use the cast() operator? I'd like better something along the lines of

foo:int('x');
bar(foo:real('y'));

And cast(type)obj can almost be directly translated to obj.opCast:type() (almost because implicit casts should still be allowed when there's no ambiguity). Ambiguity should be defined differently for return types, though - the above problem is still not solved, even if there is an exact match (actually, precisely because of the exact match).

So, I'd say that if there are return types A and B, and either can be implicitly casted to the other, the caller should be forced to specify which is the right one when using either.

That's ok, though; even if you write A a=func(), it actually doesn't mean that func() should return something of type A, it just means that you'd like the compiler to implicitly cast it to A. This logic is actually the same as with double a=2/3 -- you'll still get 0, because the casting gets done on assignment, not evaluation..


xs0
February 21, 2005
>     double cost=sqrt(..);

should of course be

double cost=mysqrt(..);

:)


xs0
February 21, 2005
On Mon, 21 Feb 2005 14:03:04 +0100, xs0 <xs0@xs0.com> wrote:
>> The main one seems to be, what would happen if someone coded a function
>> call but did not assign the return to anything? How would the compiler know
>> which signature to use if it had to use return-type as a determinate?
>
> Well, that's not the only "main" issue, imho.. For example, consider:
>
> int mysqrt(double a) {
>     return floor(sqrt(a));
> }
>
> double eval_some_cost(...)
> {
>      double cost=sqrt(..);

I assume the above line is supposed to be
       double cost=mysqrt(..);

? if so, it doesn't compile, return type is wrong.

>      if (something)
>          cost*=1.3;
>
>      return cost;
> }
>
> Now, this works fine and all.

Can you give an example which compile, so I can mess with it :)

> But, I (or my co-worker) can decide sometime in the future that there should also be a double mysqrt(double) returning the unrounded square root (or even something completely different, but that is bad style, I guess). The problem is that without any change in either the int version or in eval_some_cost(), the code will produce different results. This is most probably the reason why ambiguous function calls are not allowed and you need to be explicit which version you want to use.

Consider this, existing, similar problem:

class Parent {
    void foo(long a) { printf("parent: foo: long\n"); }
}

class Child : Parent {
    //uncomment this line
    //void foo(int a) { printf("child: foo: int\n"); }
}

void main() {
    Child c = new Child();
    long a = 5;
    c.foo(a);
}

This issue is caused by name resolution matching the child function with implicit conversion.

In other words, implicit conversion causes the problem, and it's a seperate issue to solve, adding this new explicit function selection will not add new sources of bugs, they're already there.

>> For example...
>>    cast(int)foo('x');  // Call the 'int' version and ignore the result.
>>    bar( cast(real)foo('y') ); // Call the 'real' version of foo and bar.
>
> Hmm, but there's no casting, so why use the cast() operator?

Because it has basically the same meaning.

> I'd like better something along the lines of
>
> foo:int('x');
> bar(foo:real('y'));

I think we can avoid a 'new' syntax by using an existing one, I think cast(x) will be commonly understood.

> And cast(type)obj can almost be directly translated to obj.opCast:type() (almost because implicit casts should still be allowed when there's no ambiguity). Ambiguity should be defined differently for return types, though - the above problem is still not solved, even if there is an exact match (actually, precisely because of the exact match).

Agreed, however the problem already exists as shown in example #1.

> So, I'd say that if there are return types A and B, and either can be implicitly casted to the other, the caller should be forced to specify which is the right one when using either.

Agreed, but it's not the way D works currently.

> That's ok, though; even if you write A a=func(), it actually doesn't mean that func() should return something of type A, it just means that you'd like the compiler to implicitly cast it to A.

Yep, this is how D works currently.

> This logic is actually the same as with double a=2/3 -- you'll still get 0, because the casting gets done on assignment, not evaluation..

Yep, if this was an error the bug would be spotted.

This whole issue comes down to where you draw the line, where you balance convenience vs pedanticism. (if that aint a word it should be). Walter has drawn it in one place, almost everyone disagrees in some way, large or small.

Regan
« First   ‹ Prev
1 2 3 4 5 6