June 08, 2004
On Wed, 9 Jun 2004 07:51:09 +1000, Derek wrote:

> On Tue, 8 Jun 2004 10:58:30 +0200, Ivan Senji wrote:
> 
>> "Derek Parnell" <derek@psych.ward> wrote in message news:ca3shk$85s$1@digitaldaemon.com...
>>> On Tue, 8 Jun 2004 07:24:21 +0000 (UTC), Arcane Jill wrote:
>>>
>>>> I mentioned this before. It seems such a simple thing, too.
>>>>
>>>> I really think it's important that opCast() take a dummy parameter so
>> that we
>>>> can overload on it, because you can't overload on the return type. Then,
>> for
>>>> example, I would be able to do:
>>>>
>>>>>       class Int
>>>>>       {
>>>>>           int opCast(int dummy) { return toInt(); }
>>>>>           long opCast(long dummy) { return toLong(); }
>>>>>           double opCast(double dummy) { return toDouble(); }
>>>>>       }
>>>>
>>>> and so on. Without this, opCast is practically useless. This would be
>> such an
>>>> easy thing to add, would it not? It would certainly be of great benefit.
>>>>
>>>> Jill
>>>
>>> Not to be able to overload opCast() does seem a bit pointless. So I agree
>>> with you AJ.
>>>
>>> BTW, its been a while since I've seen the rationale for not overloading based on return type. Can somebody refresh me on this point?
>>>
>> 
>> int func(){return 3;}
>> char[] func(){return "Hello";}
>> 
>> func(); //which one to call?
> 
> Ah yes - the old "functions are assumed to return an int if the call is not explictly coded otherwise" trick.
> 
> So how about, in the case of ambiguity (such as above), the compiler just
> tells you about it (error-abort) until you tell it explicitly...
> 
>   int a;
>   a = func()
> 
> or
> 
>   cast(int)func();
> 
> This resolution of ambiguity would only be needed where it actually existed, much like operator overloading now.

Ahhh! What was I thinking.. Okay, I've had breakfast and a shower now.

Take Two: Maybe the compiler should just call the int func() as this is the default (used to automatically resolve ambiguity) and if the coder wishes to have the other called instead, she explictly nominates the return datatype.

func(); // CAlls the int version.
cast(char [])func(); // calls the other one.
char[] a = func(); also calls the other one.

-- 
Derek
Melbourne, Australia
June 08, 2004
In article <james-D93ECD.13022008062004@digitalmars.com>, James Widman says...
>
>In article <ca4kdc$1k59$1@digitaldaemon.com>,
> "Vathix" <vathixSpamFix@dprogramming.com> wrote:
>> 
>> I suggested using an out parameter instead of return value, like this:
>> 
>> class Int
>> {
>>    void opCast(out int result) { result = 3; }
>>    void opCast(out real result) { result = 3.0; }
>> }
>> 
>> So at least it doesn't look like a hack ;)
>

>To me the strangest part is that the function will behave as if it contained a return statement.
>
>1) is everybody ok with that lie?  I don't think we should be, because it will inhibit people's ability to understand code.

No, this is fine. It's completely comprehensible. It's a void function which takes an out parameter. It reads fine.

In fact, exactly the same trick is use to disambiguate all of the std.stream.Stream overloads. Check in out in the manual. There's...

void read(out byte x)
void read(out ubyte x)
void read(out short x)
void read(out ushort x)
void read(out int x)

..and so on. If it's good enough for Phobos, it's good enough for me.



>IMHO, a return type of "void" should mean "this function returns void".

There's nothing wrong with a void function taking out parameters.


>I vote for Jill's suggestion -- not that I actually have a vote. :-)

The syntax doesn't matter. All that matters is BEING ABLE TO DO IT AT ALL. I suggest we let Walter choose the syntax. I don't believe that any of us really care about the syntax all that much. Let's just be unequivocal about the fact that this is a desirable feature, whatever the syntax.


>One thing though, about Jill's example: since "dummy" is not used, need it be used in the opCast definition at all?

At present, it would be a compile error without it.


>On the other hand, would we be able to use "dummy" and expect that it contains the default initializer value for its type at the entry point of the function?

I would imagine it would be initialized with .init, but who cares?

Jill


June 08, 2004
In article <ca5e7o$7t$1@digitaldaemon.com>, Matthew says...
>
>Or
>
>     class Int
>     {
>         int opCast() { result = 3; }
>         real opCast() { result = 3.0; }
>     }

Which gets back to the old problem of overloading by return type.  And while I'm sure Walter could make this a special case, special cases scare me :)  This almost has me wanting to define member template function specializations for the purpose, except the syntax is kind of verbose:

class Int
{
template opCast(T:int){ int opCast() { result = 3; } }
template opCast(T:real){ real opCast() { result = 3.0; } }
}

Note that D doesn't recognize the above member templates as operator methods.

Sean


June 08, 2004
In article <ca4kdc$1k59$1@digitaldaemon.com>, Vathix says...
>
>I suggested using an out parameter instead of return value, like this:
>
>class Int
>{
>   void opCast(out int result) { result = 3; }
>   void opCast(out real result) { result = 3.0; }
>}
>
>So at least it doesn't look like a hack ;)

Best suggestion I've seen so far :)


Sean


June 09, 2004
Just thought I'd mention this and see what comes of it. C# has keywords "implicit" and "explicit" for overloading casts. D could get away with this easier just by making a new function name like opImplicitCast or opCoerce ...


June 09, 2004
In article <ca5kch$a5r$1@digitaldaemon.com>, Vathix says...
>
>Just thought I'd mention this and see what comes of it. C# has keywords "implicit" and "explicit" for overloading casts. D could get away with this easier just by making a new function name like opImplicitCast or opCoerce ...

Cool. I mentioned that very thing only yesterday (http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/3361).

Obviously I agree with you. I don't care about the syntax though, only the feature. (Though I think it /has/ to be a constructor, not a regular function).

Jill


June 09, 2004
Vathix wrote:
> Just thought I'd mention this and see what comes of it. C# has keywords
> "implicit" and "explicit" for overloading casts. D could get away with this
> easier just by making a new function name like opImplicitCast or opCoerce
> ...

No no no no please no.

When writing a smart pointer class in C++, writing both an operator bool() and an operator== can cause chaos when comparing with different smart pointers (when, for instance, interfacing with a library that has its own smart pointer) because C++ will sometimes prefer operator bool() over operator == when performing the comparison.

Long story short, if you're not careful, the x==y comparison becomes equivalent to (x != 0) == y.  Not Good.

Implicit conversions are not a can of worms that should be opened.

 -- andy
June 09, 2004
In article <ca5fls$2oi$1@digitaldaemon.com>,
 Arcane Jill <Arcane_member@pathlink.com> wrote:
> >1) is everybody ok with that lie?  I don't think we should be, because it will inhibit people's ability to understand code.
> 
> No, this is fine. It's completely comprehensible. It's a void function which takes an out parameter. It reads fine.

I think I'm ok with the concept of "out" parameters in general: you pass an argument to a function, and the function assigns something to it.

So for:

class A
    {
    void opCast(out int x) { x = 3; }
    }

void f(A a)
    {
    int i;
    a.opCast(i);     // OK; opCast will assign a value to "i".


// XXX But as for this:
    i = cast(int)a;  // opCast returns void...so for this to work there
                     // must be a hidden variable (the "out" argument)
                     // which will implicitly be used as if it were the
                     // cast operator's return value.  Should this work
                     // in general for void functions that take a single
                     // "out"?
    }


> >IMHO, a return type of "void" should mean "this function returns void".
> 
> There's nothing wrong with a void function taking out parameters.

Agreed -- but because of the way the cast operator is used, it looks to me like the compiler would have to behave as if opCast had been declared as returning non-void -- that's the "lie" I referred to earlier.

Or it could just be that I'm terribly confused. :-) Is there some relevant part of the spec that I should review?

> The syntax doesn't matter. All that matters is BEING ABLE TO DO IT AT ALL.I suggest we let Walter choose the syntax. I don't believe that any of us really care about the syntax all that much.

Oh come on; if the syntax really didn't matter, we could just copy the way C++ does conversion operators. :-)   ("Not that there's anything wrong with that...")

I think the clean design of the syntax is one of the main reasons why D code is so much more readable than the equivalent C++ -- take templates, for example.

Now, of course Walter's going to choose the syntax. But *everyone's* going to be stuck with it in the months and years to come (i.e., users, compiler writers, and language support tool-writers), so I think it pays to ask about these things.


> Let's just be unequivocal about the fact
> that this is a desirable feature, whatever the syntax.

It's definitely a desirable feature. :-)

I'm sorry; I really don't want to be the nit-picker in the crowd.  But in general, syntax issues really do matter. It affects the way language features will be used in the future, and it can affect the ease of implementation.

Now so far, I think I like Matthew's suggestion best, but FWIW, here's my stab at it:

class B
    {
    opCast(int) { return 0; }
    opCast(real) { return 0.0; }
    }

Notes:

1) Any way you slice it, the addition of this feature implies an overload on the return type.  Now in general, special cases should scare us, but since we're specifying the return type with /each invocation/, and that type (and the type of the cast-from object) is all we need to select the right overload, we should be scared less:

void f(B b)
    {
    int i = cast(int)b;   // it's pretty obvious which overload
    real r = cast(real)b; // we're selecting in both cases.

2) But since it is, after all, a special case, we should choose a syntax that shouts "I am a special case!" as loudly as possible. So "opCast" comes first in the declaration, then (parenthesized) return type, then function body.

James
June 09, 2004
In article <james-F9B8BE.03385009062004@digitalmars.com>, James Widman says...
>
>    i = cast(int)a;  // opCast returns void...so for this to work there
>                     // must be a hidden variable (the "out" argument)
>                     // which will implicitly be used as if it were the
>                     // cast operator's return value.  Should this work
>                     // in general for void functions that take a single
>                     // "out"?

It would be a compiler rewrite.

> int i = cast(int)a;

would have to be magically and invisibly transformed by the compiler into:

> int i = { int t; a.opCast(t); return t; };

Oh right. I see the problem. That won't compile, will it?

Well then, back to my first suggestion I don't mind a dummy argument. No-one objects to the dummy argument in the C++ operator++(int).

Maybe the only irritation here is that I named the dummy argument. Compare:
1)  int opCast(int dummy);
2)  int opCast(int);

Now (2) looks nicer, I grant you. It just won't compile - though of course, Walter may be able to change that, for this special case only. But personally, I don't mind naming a dummy parameter. It doesn't bother me at all. It makes it clear that this IS a normal function, declared in the normal way - I just happen not to be using that particular parameter in the function body.

Jill


June 09, 2004
"Arcane Jill" <Arcane_member@pathlink.com> wrote in message news:ca6g4o$1igp$1@digitaldaemon.com...
> In article <james-F9B8BE.03385009062004@digitalmars.com>, James Widman says...
> >
> >    i = cast(int)a;  // opCast returns void...so for this to work there
> >                     // must be a hidden variable (the "out" argument)
> >                     // which will implicitly be used as if it were the
> >                     // cast operator's return value.  Should this work
> >                     // in general for void functions that take a single
> >                     // "out"?
>
> It would be a compiler rewrite.
>
> > int i = cast(int)a;
>
> would have to be magically and invisibly transformed by the compiler into:
>
> > int i = { int t; a.opCast(t); return t; };
>
> Oh right. I see the problem. That won't compile, will it?
>
> Well then, back to my first suggestion I don't mind a dummy argument. No-one objects to the dummy argument in the C++ operator++(int).

Only because there's no choice. It's a pretty horrible construction.

> Maybe the only irritation here is that I named the dummy argument. Compare:
> 1)  int opCast(int dummy);
> 2)  int opCast(int);
>
> Now (2) looks nicer, I grant you. It just won't compile - though of course, Walter may be able to change that, for this special case only. But personally,
I
> don't mind naming a dummy parameter. It doesn't bother me at all. It makes it clear that this IS a normal function, declared in the normal way - I just
happen
> not to be using that particular parameter in the function body.
>
> Jill
>
>