August 25, 2004
On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:
> I thought about trying to get around the toString() issue using opCat() and
> opCat_r(). It /nearly/ works ... the nice thing about opCat() et. al. is
> that they're not overriding anything (like toString) and therefore can have
> pretty much any kind of argument and/or return value. For example:
>
> class A
> {
>     dchar[] opCat (dchar[] x) {...}
>
>     dchar[] opCat (char[] x) {...}
>
>     dchar[] opCat (wchar[] x) {}
>
>     dchar[] opCat (int x) {..}
>
>     // plus the opCat_r() equivalents
> }
>
> This looked really promising! However, it all fell apart when trying to add
> a different return type:
>
>    char[] opCat (char[] x) {...}
>
> because D only looks at the method name and argument type, and ignores the
> return type. Therefore, a conflict occurs between two operators, and the
> compiler throws an error. Adopting a type promotion approach (as both
> yourself and Matthew have suggested) would probably have to fix this
> bugaboo.

Yeah.. it would be nice to have the return type included in the method lookup.. it would be breaking from C/C++ convention, apart from that is it really that hard to do?

Regan

> "Regan Heath" <regan@netwin.co.nz> wrote in message
> news:opsc5skbhm5a2sq9@digitalmars.com...
>> On Sun, 22 Aug 2004 16:29:29 -0700, antiAlias <fu@bar.com> wrote:
>> > Right. But I don't think this stuff should be done by a cast(). I 
>> mean,
>> > you
>> > can just as easily convert them "manually" using the functions in 
>> utf.d,
>> > can't you?
>>
>> Yep, we want implicit conversion, eg.
>>
>> char[] a = "abc";
>> dchar[] b = a;     <- does a UTF-8 to UTF-32
>>
>> > Where automated conversion would really help is in stringizing
>> > (the original topic; I think):
>>
>> Definately.
>>
>> > class A {}
>> >
>> > int x;
>> > long y;
>> > dchar[] z;
>> > A a = new A;
>> >
>> > char[] narrow = "string some stuff together " ~ z ~ y ~ x ~ a;
>> >
>> > and the wide version:
>> >
>> > dchar[] wide = "string some stuff together " ~ z ~ y ~ x ~ a;
>> >
>> > If the ~ concatenators could convert between dchar[] and char[]
>> > appropriately, then Matthew's idea about the type being specified by 
>> the
>> > left-hand side would probably work. Though, on reflection, this seem
>> > like an
>> > awful lot of work for an operator to perform. Particularly so when 
>> it's
> a
>> > special-case, as it is here (e.g. int[] does not does anything fancy
> like
>> > this).
>>
>> The operator itself doesn't do the work, it's the type promotion system,
>> eg when you say
>>
>> int a;
>> float b,c;
>>
>> c = b+a;
>>
>> the compiler first promotes 'a' to float, then adds them, then assigns
>> that to 'c'.
>>
>> So, Matthews idea effects the type promotion system, I had a similar idea,
>> I suggested the type promotion system use the type of the thing being
>> assigned to (c in the above) to determine what to promote the type to.
>> This was to solve the common:
>>
>> float percentage;
>> int value,total;
>>
>> percentage = value/total*100;
>>
>> bug which only ever assigns percentage an integral value as value,total
>> and 100 are integral.
>> To fix the above you must go
>>
>> cast(float)value/cast(float)total*100.0
>>
>> notice the casts and the .0 on the 100, this makes them all floats, which
>> is the type of the result.
>>
>>
>> I think we want/need two things:
>>   - implicit calling of toString for types with toString defined.
>>   - implicit calling of toString for basic types.
>>   - type promotion in operators to cause implicit conversion between UTF-x
>> types.
>>
>> Such that the example:
>>
>> # char[] narrow = "string some stuff together " ~ z ~ y ~ x ~ a;
>>
>> Will cause:
>>
>> - represent "string.." in UTF-32
>> - append z
>> - call y.toString(), convert to UTF-32, append
>> - call x.toString(), convert to UTF-32, append
>> - call a.toString(), convert to UTF-32, append
>> - convert to UTF-8, assign to narrow.
>>
>> If the example were changed to:
>>
>> # char[] narrow = cast(char[])"string some stuff together " ~ z ~ y ~ x ~
>> a;
>>
>> then the operations would be:
>>
>> - represent "string.." in UTF-8
>> - convert z to UTF-8, append
>> - call y.toString(), append
>> - call x.toString(), append
>> - call a.toString(), append
>> - assign to narrow
>>
>> which is better as less conversions are required. This is in essence what
>> Matthews idea causes, yes?
>>
>> My suggestion causes the same sequence of events as Matthews idea.
>>
>> The other example:
>>
>> # dchar[] wide = "string some stuff together " ~ z ~ y ~ x ~ a;
>>
>> probably causes:
>>
>> - represent "string.." as UTF-32
>> - append z
>> - call y.toString(), convert to UTF-32, append
>> - call x.toString(), convert to UTF-32, append
>> - call a.toString(), convert to UTF-32, append
>> - assign to wide
>>
>> interestingly this is identical to the first example, if we take Matthews
>> idea into account we get:
>>
>> - represent "string.." as UTF-8
>> - convert z to UTF-8, append
>> - call y.toString(), append
>> - call x.toString(), append
>> - call a.toString(), append
>> - convert to UTF-32, assign to wide
>>
>> which is better, my idea actually causes the original behaviour :(
>>
>> > Instead, how about a concat(...) method? It's not hard to make a
> typesafe
>> > one that can do whatever conversion one desires (including calling
>> > toString() and converting as necessary). Hell; you could have two
>> > concat()
>> > methods: one for a dchar[] result and one for a char[] result.
>> >
>> > return "my granny is "~age~" old";
>> >
>> > becomes
>> >
>> > return concat ("my granny is ", age, " old");
>> >
>> > Is that really so awful?
>>
>> Not awful, but IMO it's better if we don't need one.
>>
>> > Regardless; I think there's still an issue about toString() not 
>> handling
>> > dchar[]. Although you can utf8 encode the content, that's hardly a
>> > convenience, or exactly efficient.
>>
>> Exactly, so why not implicitly convert.. I can't see what problems it
>> causes, and it certainly solves several.
>>
>> Regan
>>
>> > "Regan Heath" <regan@netwin.co.nz> wrote in message
>> > news:opsc5nxehm5a2sq9@digitalmars.com...
>> >> On Sun, 22 Aug 2004 10:11:10 +0000 (UTC), Arcane Jill
>> >> <Arcane_member@pathlink.com> wrote:
>> >> > In article <cg68tk$11on$1@digitaldaemon.com>, antiAlias says...
>> >> >>
>> >> >> The problems with that particular approach are twofold:
>> >> >>
>> >> >> 2) more importantly: it doesn't work for unicode strings, because
>> >> >> providing
>> >> >> a "dchar toString()" in each class is not covariant with the "char
>> >> >> toString()" living in the root Object. I wish there was an nice,
>> >> clean,
>> >> >> elegant solution to this ...
>> >> >
>> >> > I've wondered about that myself, but I guess having toString() 
>> return
>> >> > char[] is
>> >> > not so bad. The magic of UTF-8 does, after all, allow us to store
>> >> every
>> >> > character in a char[] (even though not in a char).
>> >> >
>> >> > But it would be really, really, /really/ cool, if all string types
>> >> would
>> >> > *implicitly* cast to one another, *and* go through the relevant
>> >> std.utf
>> >> > conversion routine to do so. Then classes could implement any of 
>> the
>> >> > following
>> >> > at their choice:
>> >> >
>> >> > #    char[] toString();
>> >> > #    wchar[] toString();
>> >> > #    dchar[] toString();
>> >> >
>> >> > Walter has opposed the notion that even /explicit/ casts from 
>> string
>> >> to
>> >> > string
>> >> > should not do any conversion. I suggest:
>> >>
>> >> I believe Walters opposition was due to the fact that a conversion
> would
>> >> create inconsistency between string types and ubyte etc, also that 
>> the
>> >> ability to 'paint' one type as another is desired.
>> >>
>> >> I think the fact that char, wchar, and dchar have a specified 
>> encoding
>> >> sets them apart from other types, this fact makes painting one string
>> >> type
>> >> to another completely useless, I cannot think of a reason to paint a
>> >> char[], wchar[] or dchar[] to each other? can you?
>> >>
>> >> If you can then I suggest something like:
>> >>
>> >> > #    c = cast(char[]) cast(void[]) d;  // does not call toUTF8()
>> >>
>> >> will suffice.
>> >>
>> >> It *does* make sense to paint char[], wchar[] or dchar[] as ubyte[] 
>> or
>> >> void[] etc so what I suggest is that conversion does occur, but, only
> if
>> >> both the source type and destination type have a specified encoding,
>> >> i.e.
>> >> char, wchar and dchar to char, wchar or dchar.
>> >>
>> >> In conclusion I cannot see any valid reason not to make this change, 
>> I
>> >> believe it makes string handling:
>> >>   - simpler
>> >>   - more consistent
>> >>   - less error prone
>> >>
>> >> This change would make a string class totally useless, which I 
>> believe
>> >> was
>> >> Walters original intention when creating these types.
>> >>
>> >> Regan
>> >>
>> >> --
>> >> Using M2, Opera's revolutionary e-mail client: 
>> http://www.opera.com/m2/
>> >
>> >
>>
>>
>>
>> --
>> Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
>
>



-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 25, 2004
"Regan Heath" <regan@netwin.co.nz> wrote in message news:opsc9jlr0b5a2sq9@digitalmars.com...
> On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:
> > I thought about trying to get around the toString() issue using opCat()
> > and
> > opCat_r(). It /nearly/ works ... the nice thing about opCat() et. al. is
> > that they're not overriding anything (like toString) and therefore can
> > have
> > pretty much any kind of argument and/or return value. For example:
> >
> > class A
> > {
> >     dchar[] opCat (dchar[] x) {...}
> >
> >     dchar[] opCat (char[] x) {...}
> >
> >     dchar[] opCat (wchar[] x) {}
> >
> >     dchar[] opCat (int x) {..}
> >
> >     // plus the opCat_r() equivalents
> > }
> >
> > This looked really promising! However, it all fell apart when trying to
> > add
> > a different return type:
> >
> >    char[] opCat (char[] x) {...}
> >
> > because D only looks at the method name and argument type, and ignores
> > the
> > return type. Therefore, a conflict occurs between two operators, and the
> > compiler throws an error. Adopting a type promotion approach (as both
> > yourself and Matthew have suggested) would probably have to fix this
> > bugaboo.
>
> Yeah.. it would be nice to have the return type included in the method lookup.. it would be breaking from C/C++ convention, apart from that is it really that hard to do?

AFAIK, the issue has always been "what happens if the return-value is not assigned? Then you've lost part of the signature, and conflict can arise". This wouldn't occur with opCat() and friends because there's always a left and right operand ...


August 25, 2004
On Tue, 24 Aug 2004 18:10:53 -0700, antiAlias wrote:

> "Regan Heath" <regan@netwin.co.nz> wrote in message news:opsc9jlr0b5a2sq9@digitalmars.com...
>> On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:

[snip]

>> Yeah.. it would be nice to have the return type included in the method lookup.. it would be breaking from C/C++ convention, apart from that is it really that hard to do?
> 
> AFAIK, the issue has always been "what happens if the return-value is not assigned? Then you've lost part of the signature, and conflict can arise". This wouldn't occur with opCat() and friends because there's always a left and right operand ...

In my hypothetically 'good' language, return values would either always be assigned or explicitly rejected.

   int funcA() { return 0; }
   float funcA() { return 1.2; }
   int x;
   float y;


   x = funcA();   // Return 0 assigned
   y = funcA();   // Return 1.2 assigned
   cast(int)funcA(); // Return 0 rejected.
   cast(float)funcA(); // Return 1.2 rejected.
   y = cast(int)funcA(); // Return 0 converted to float and assigned.
   x = cast(int)(cast(float)funcA()); // Return 1.2 converted to int and
assigned.

-- 
Derek
Melbourne, Australia
25/Aug/04 11:12:00 AM
August 25, 2004
Here's some ambiguity with overloading on return type;

# SomeType f1() { return new SomeType; }
# SomeOtherType f1() { return new SomeOtherType; }
# void f2(SomeType t) {
#  printf("got SomeType\n");
# }
# void f2(SomeOtherType t) {
#  printf("got SomeOtherType\n");
# }
#
# int main() {
#  f2(f1);
#  return 0;
# }

IMHO, mutually recursive type signatures are a Bad Thing(TM).

Derek Parnell wrote:
> On Tue, 24 Aug 2004 18:10:53 -0700, antiAlias wrote:
> 
> 
>>"Regan Heath" <regan@netwin.co.nz> wrote in message
>>news:opsc9jlr0b5a2sq9@digitalmars.com...
>>
>>>On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:
> 
> 
> [snip]
> 
> 
>>>Yeah.. it would be nice to have the return type included in the method
>>>lookup.. it would be breaking from C/C++ convention, apart from that is it
>>>really that hard to do?
>>
>>AFAIK, the issue has always been "what happens if the return-value is not
>>assigned? Then you've lost part of the signature, and conflict can arise".
>>This wouldn't occur with opCat() and friends because there's always a left
>>and right operand ...
> 
> 
> In my hypothetically 'good' language, return values would either always be
> assigned or explicitly rejected.
> 
>    int funcA() { return 0; }
>    float funcA() { return 1.2; }
>    int x;
>    float y;
> 
> 
>    x = funcA();   // Return 0 assigned
>    y = funcA();   // Return 1.2 assigned
>    cast(int)funcA(); // Return 0 rejected.
>    cast(float)funcA(); // Return 1.2 rejected.
>    y = cast(int)funcA(); // Return 0 converted to float and assigned.
>    x = cast(int)(cast(float)funcA()); // Return 1.2 converted to int and
> assigned.
> 
August 25, 2004
Right.

But that doesn't apply when there's /always/ a left & right operand present (such as with opCat and friends). We're specifically avoiding the general case, such as you illustrated, in an effort to explore how type-promotion + operator-overloading might resolve some thorny issues. No offence intended.


"Devin Papineau" <devin_papineau@sympatico.ca> wrote in message news:cggqgv$1hk6$1@digitaldaemon.com...
> Here's some ambiguity with overloading on return type;
>
> # SomeType f1() { return new SomeType; }
> # SomeOtherType f1() { return new SomeOtherType; }
> # void f2(SomeType t) {
> #  printf("got SomeType\n");
> # }
> # void f2(SomeOtherType t) {
> #  printf("got SomeOtherType\n");
> # }
> #
> # int main() {
> #  f2(f1);
> #  return 0;
> # }
>
> IMHO, mutually recursive type signatures are a Bad Thing(TM).
>
> Derek Parnell wrote:
> > On Tue, 24 Aug 2004 18:10:53 -0700, antiAlias wrote:
> >
> >
> >>"Regan Heath" <regan@netwin.co.nz> wrote in message news:opsc9jlr0b5a2sq9@digitalmars.com...
> >>
> >>>On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:
> >
> >
> > [snip]
> >
> >
> >>>Yeah.. it would be nice to have the return type included in the method lookup.. it would be breaking from C/C++ convention, apart from that is
it
> >>>really that hard to do?
> >>
> >>AFAIK, the issue has always been "what happens if the return-value is
not
> >>assigned? Then you've lost part of the signature, and conflict can
arise".
> >>This wouldn't occur with opCat() and friends because there's always a
left
> >>and right operand ...
> >
> >
> > In my hypothetically 'good' language, return values would either always
be
> > assigned or explicitly rejected.
> >
> >    int funcA() { return 0; }
> >    float funcA() { return 1.2; }
> >    int x;
> >    float y;
> >
> >
> >    x = funcA();   // Return 0 assigned
> >    y = funcA();   // Return 1.2 assigned
> >    cast(int)funcA(); // Return 0 rejected.
> >    cast(float)funcA(); // Return 1.2 rejected.
> >    y = cast(int)funcA(); // Return 0 converted to float and assigned.
> >    x = cast(int)(cast(float)funcA()); // Return 1.2 converted to int and
> > assigned.
> >


August 25, 2004
On Tue, 24 Aug 2004 18:49:44 -0700, antiAlias <fu@bar.com> wrote:
> Right.
>
> But that doesn't apply when there's /always/ a left & right operand present
> (such as with opCat and friends). We're specifically avoiding the general
> case, such as you illustrated, in an effort to explore how type-promotion +
> operator-overloading might resolve some thorny issues. No offence intended.

Also, can't we resolve the case below by calling it an error and requiring some guidance from the programmer eg.

# int main() {
#  f2(cast(SomeType)f1());
#  return 0;
# }

to print "got SomeType"

# int main() {
#  f2(cast(SomeOtherType)f1());
#  return 0;
# }

to print "got SomeOtherType"

> "Devin Papineau" <devin_papineau@sympatico.ca> wrote in message
> news:cggqgv$1hk6$1@digitaldaemon.com...
>> Here's some ambiguity with overloading on return type;
>>
>> # SomeType f1() { return new SomeType; }
>> # SomeOtherType f1() { return new SomeOtherType; }
>> # void f2(SomeType t) {
>> #  printf("got SomeType\n");
>> # }
>> # void f2(SomeOtherType t) {
>> #  printf("got SomeOtherType\n");
>> # }
>> #
>> # int main() {
>> #  f2(f1);
>> #  return 0;
>> # }
>>
>> IMHO, mutually recursive type signatures are a Bad Thing(TM).
>>
>> Derek Parnell wrote:
>> > On Tue, 24 Aug 2004 18:10:53 -0700, antiAlias wrote:
>> >
>> >
>> >>"Regan Heath" <regan@netwin.co.nz> wrote in message
>> >>news:opsc9jlr0b5a2sq9@digitalmars.com...
>> >>
>> >>>On Tue, 24 Aug 2004 14:58:09 -0700, antiAlias <fu@bar.com> wrote:
>> >
>> >
>> > [snip]
>> >
>> >
>> >>>Yeah.. it would be nice to have the return type included in the 
>> method
>> >>>lookup.. it would be breaking from C/C++ convention, apart from that 
>> is
> it
>> >>>really that hard to do?
>> >>
>> >>AFAIK, the issue has always been "what happens if the return-value is
> not
>> >>assigned? Then you've lost part of the signature, and conflict can
> arise".
>> >>This wouldn't occur with opCat() and friends because there's always a
> left
>> >>and right operand ...
>> >
>> >
>> > In my hypothetically 'good' language, return values would either 
>> always
> be
>> > assigned or explicitly rejected.
>> >
>> >    int funcA() { return 0; }
>> >    float funcA() { return 1.2; }
>> >    int x;
>> >    float y;
>> >
>> >
>> >    x = funcA();   // Return 0 assigned
>> >    y = funcA();   // Return 1.2 assigned
>> >    cast(int)funcA(); // Return 0 rejected.
>> >    cast(float)funcA(); // Return 1.2 rejected.
>> >    y = cast(int)funcA(); // Return 0 converted to float and assigned.
>> >    x = cast(int)(cast(float)funcA()); // Return 1.2 converted to int 
>> and
>> > assigned.
>> >
>
>



-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 25, 2004
On Wed, 25 Aug 2004 11:19:53 +1000, Derek Parnell <derek@psych.ward> wrote:
<snip>
> In my hypothetically 'good' language, return values would either always be
> assigned or explicitly rejected.
>
>    int funcA() { return 0; }
>    float funcA() { return 1.2; }
>    int x;
>    float y;

>    cast(int)funcA(); // Return 0 rejected.
>    cast(float)funcA(); // Return 1.2 rejected.

Are these backwards? or am I not understanding what you mean when you say:
 "Return 0 rejected."

??

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 25, 2004
On Wed, 25 Aug 2004 16:47:10 +1200, Regan Heath wrote:

> On Wed, 25 Aug 2004 11:19:53 +1000, Derek Parnell <derek@psych.ward> wrote: <snip>
>> In my hypothetically 'good' language, return values would either always
>> be
>> assigned or explicitly rejected.
>>
>>    int funcA() { return 0; }
>>    float funcA() { return 1.2; }
>>    int x;
>>    float y;
> 
>>    cast(int)funcA(); // Return 0 rejected.
>>    cast(float)funcA(); // Return 1.2 rejected.
> 
> Are these backwards? or am I not understanding what you mean when you say:
>   "Return 0 rejected."
> 
> ??

The "cast(int)funcA();" is meant to call the function that returns an int.
The "cast(float)funcA();" is meant to call the function that returns a
float.

This is a way of telling the compiler which function I want given that there is no other way to tell. You might like to use ...

    use(int)funcA(); // Return 0 rejected.
    use(float)funcA(); // Return 1.2 rejected.

instead of 'cast'.

-- 
Derek
Melbourne, Australia
25/Aug/04 3:11:24 PM
August 25, 2004
On Wed, 25 Aug 2004 15:14:08 +1000, Derek Parnell <derek@psych.ward> wrote:
> On Wed, 25 Aug 2004 16:47:10 +1200, Regan Heath wrote:
>
>> On Wed, 25 Aug 2004 11:19:53 +1000, Derek Parnell <derek@psych.ward> wrote:
>> <snip>
>>> In my hypothetically 'good' language, return values would either always
>>> be
>>> assigned or explicitly rejected.
>>>
>>>    int funcA() { return 0; }
>>>    float funcA() { return 1.2; }
>>>    int x;
>>>    float y;
>>
>>>    cast(int)funcA(); // Return 0 rejected.
>>>    cast(float)funcA(); // Return 1.2 rejected.
>>
>> Are these backwards? or am I not understanding what you mean when you say:
>>   "Return 0 rejected."
>>
>> ??
>
> The "cast(int)funcA();" is meant to call the function that returns an int.

I thought so.. why does the comment say "Return 0 rejected"?

> The "cast(float)funcA();" is meant to call the function that returns a
> float.
>
> This is a way of telling the compiler which function I want given that
> there is no other way to tell. You might like to use ...
>
>     use(int)funcA(); // Return 0 rejected.
>     use(float)funcA(); // Return 1.2 rejected.
>
> instead of 'cast'.

Nah, cast works for me.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
August 25, 2004
"Regan Heath" <regan@netwin.co.nz> wrote in message news:opsc9v0tvj5a2sq9@digitalmars.com...
> On Wed, 25 Aug 2004 15:14:08 +1000, Derek Parnell <derek@psych.ward> wrote:
> > On Wed, 25 Aug 2004 16:47:10 +1200, Regan Heath wrote:
> >
> >> On Wed, 25 Aug 2004 11:19:53 +1000, Derek Parnell <derek@psych.ward>
> >> wrote:
> >> <snip>
> >>> In my hypothetically 'good' language, return values would either always
> >>> be
> >>> assigned or explicitly rejected.
> >>>
> >>>    int funcA() { return 0; }
> >>>    float funcA() { return 1.2; }
> >>>    int x;
> >>>    float y;
> >>
> >>>    cast(int)funcA(); // Return 0 rejected.
> >>>    cast(float)funcA(); // Return 1.2 rejected.
> >>
> >> Are these backwards? or am I not understanding what you mean when you
> >> say:
> >>   "Return 0 rejected."
> >>
> >> ??
> >
> > The "cast(int)funcA();" is meant to call the function that returns an
> > int.
>
> I thought so.. why does the comment say "Return 0 rejected"?
>
> > The "cast(float)funcA();" is meant to call the function that returns a
> > float.
> >
> > This is a way of telling the compiler which function I want given that there is no other way to tell. You might like to use ...
> >
> >     use(int)funcA(); // Return 0 rejected.
> >     use(float)funcA(); // Return 1.2 rejected.
> >
> > instead of 'cast'.
>
> Nah, cast works for me.

Me too. Seems like a perfectly nice, albeit not pretty, iDiom.