May 19, 2005
Regan Heath wrote:
> On Wed, 18 May 2005 20:50:35 -0700, Kyle Furlong <ky220@umail.ucsb.edu>  wrote:
> 
>> Regan Heath wrote:
>>
>>>> This is why "cast" is a hackish solution (it doesn't even work).
>>>
>>>   In your opinion :)
>>>  Regan
>>
>>
>> In my opinion also. Keywords should be unambiguous to the newbie, or at  least make sense when explained. Using cast for all these purposes will  add to the learning curve and also, IMHO, is hackish, as has already  been stated.
> 
> 
> Each to thier own. I don't think it's too much of a stretch.
> 
>> Also, doesnt the complier "know" which overload to call for the example:
>>
>> foo(cast(int)a);
>>
>> ?
> 
> 
> Yes, because the cast tells it which one to call.
> 
> (I'm afraid I may have missed your point, there wasn't any more context to  this example, it was meant for another purpose, perhaps if you propose  another example I can answer more effectively)
> 
> Regan

What I meant to write was:

int x;

void foo(int x) { }
void foo(real x) { }

main() { foo(3); }

Doesn't this compile?

the compiler knows
May 19, 2005
"Kyle Furlong" <ky220@umail.ucsb.edu> wrote in message news:d6hb9u$14dn$1@digitaldaemon.com...
> Regan Heath wrote:
> > On Wed, 18 May 2005 20:50:35 -0700, Kyle Furlong <ky220@umail.ucsb.edu> wrote:
> >
> >> Regan Heath wrote:
> >>
> >>>> This is why "cast" is a hackish solution (it doesn't even work).
> >>>
> >>>   In your opinion :)
> >>>  Regan
> >>
> >>
> >> In my opinion also. Keywords should be unambiguous to the newbie, or at  least make sense when explained. Using cast for all these purposes will  add to the learning curve and also, IMHO, is hackish, as has already  been stated.
> >
> >
> > Each to thier own. I don't think it's too much of a stretch.
> >
> >> Also, doesnt the complier "know" which overload to call for the example:
> >>
> >> foo(cast(int)a);
> >>
> >> ?
> >
> >
> > Yes, because the cast tells it which one to call.
> >
> > (I'm afraid I may have missed your point, there wasn't any more context to  this example, it was meant for another purpose, perhaps if you propose  another example I can answer more effectively)
> >
> > Regan
>
> What I meant to write was:
>
> int x;
>
> void foo(int x) { }
> void foo(real x) { }
>
> main() { foo(3); }
>
> Doesn't this compile?
>
> the compiler knows

You're missing a type for "main" or it would compile...
However, both versions of foo are of type void.
The return type (although neither of them actually has a return statement) is therefore the same in both cases.

This will also compile...

import std.stdio;
int x;
int foo(int x) {return x+1;}
real foo(real x) {return x+1;}
void main() {
 writef("int = %d\n",foo(3));
 writef("real = %g\n",foo(3.0));
}
//........

but there again, it's the parameters that choose which version of foo to run...not the return values.

On the other hand...

import std.stdio;
int x;
int foo(real x) {return cast(int)x+1;}
real foo(real x) {return x+1;}
void main() {
 writef("int = %d\n",cast(int)foo(3.0));
 writef("real = %g\n",cast(real)foo(3.0));
}
//........

...will produce a compile-time error like ...
z.d(4): function z.foo conflicts with z.foo at z.d(3)

...because the two versions of foo both have identical parameter lists.

However, one call to foo is asking for an int result and the other is asking for a real result,
and likewise, one version of foo returns an int result while the other returns a real result,
so the compiler could theoretically be modified to match the return types with the requested types
and allow the compilation of the second version.

TZ


May 19, 2005
An update on this idea:

I've familiarized myself with the TinyCC source code enough to make a few initial changes to come up with a proof-of-concept (or failure-of-concept for that matter =P).

Currently, I have the TinyCC compiler checking for casts on function return types and simply erroring out on them.  This is just a start.  Since C does not support function overloading at all, I'll have to implement it myself. Hopefully it won't be that hard.  The only complexities I foresee are in matching overloaded function calls.

Maybe I'll simplify things here by disallowing any implicit casting on overloaded parameters!  I'm all for removing ambiguity wherever possible.

Here's a nice example of what I have TinyCC doing so far:

: // ex3.c
: #include <tcclib.h>

: int fib(int n)
: {
:     if (n <= 2)
:         return 1;
:     else
:         return fib(n-1) + fib(n-2);
: }

: int main(int argc, char **argv)
: {
:     short n;
:
:     if (argc < 2) {
:         printf("usage: fib n\n"
:                "Compute nth Fibonacci number\n");
:         return 1;
:     }

:     n = fib(2);
:     n = atoi(argv[1]);

:     printf("fib(%d) = %d\n", n, fib(n, 2));
:     return 0;
: }

$ ./tcc ex3.c -run
ex3.c:21: uncastable function return type 'int' cannot be cast to 'short'

I've tested all different types of casts, including integer promotions and demotions.

On a random whim I also changed C's '->' and '.' operators to behave alike on struct pointers.  The '->' operator is still supported for backwards compatibility.

Seems like I'm sort of making my own language as a minimal superset of C! =D  Of course, I couldn't come anywhere near what D has!  I'm content with just extending and fixing the simple things I don't like about C.  I don't need an entire object-oriented paradigm.

Next thing (after return-type function overloading is done/works) will hopefully be to completely remove the need for the pre-processor and go with a simple module/import system.

Compilers are FUN!! =D  *as Walter's eyes glaze over*

In article <d6h5b7$10fd$1@digitaldaemon.com>, James Dunne says...
>
>
>I'd like to throw this idea out there:
>
>Make the return types of functions overloaded on multiple return types non-castable.  Ugh, I hate english... there's no better way to say that :-/. Yes, I'm a native speaker of the language, and I still hate it.  Boy, talk about ambiguity... Anyways...
>
>If return types were non-castable (for overloaded functions) this would solve the implicit v. explicit cast fights (hehe, sounds like cat fights) going on.  I agree that if the compiler detects any ambiguity, the user should be at least warned, or error'd =).
>
>Take this for example:
>
>#class DBColumn {
>#  public ushort opIndex(int i) { ... }
>#  public int opIndex(int i) { ... }
>#  public double opIndex(int i) { ... }
>#  .
>#  .
>#}
>#
>#int main(char[][] args) {
>#  DBColumn  col = new DBColumn(......);
>#  int    col1;
>#  ushort col2;
>#  double col3;
>#
>#  col1 = col[0];  // ok - call int opIndex(0)
>#  col2 = col[1];  // ok - call ushort opIndex(1)
>#  // error! explicit cast; cannot determine which opIndex to call
>#  col3 = cast(ushort)col[2];
>#}
>
>Implicit or explicit casting on the return-types should be disallowed.  The return-type should be treated specially as a non-castable type.  If the return value were passed to another function as a parameter which required the type to be casted/promoted to fit, it should be disallowed.  Semantics like this would be easy to implement into the current compiler - just add a non-castable flag to the type and if it has that flag set when it is to be casted, bail out. Generating error messages for these conditions should be fun!
>
>There should be a different operation defined to allow explicit specification of the return type wanted in ambiguous situations, much like the call() operator mentioned earlier.
>
>How does 'call(int) col[0]' look?  I suppose the opIndex function is a bad
>example ;).
>
>Someone please break my example!!  Proof by contradiction is the best proof there is. =P
>
>Regards,
>James Dunne

Regards,
James Dunne
May 20, 2005
On Wed, 18 May 2005 23:21:49 -0700, Kyle Furlong <ky220@umail.ucsb.edu> wrote:
> Regan Heath wrote:
>> On Wed, 18 May 2005 20:50:35 -0700, Kyle Furlong <ky220@umail.ucsb.edu>  wrote:
>>
>>> Regan Heath wrote:
>>>
>>>>> This is why "cast" is a hackish solution (it doesn't even work).
>>>>
>>>>   In your opinion :)
>>>>  Regan
>>>
>>>
>>> In my opinion also. Keywords should be unambiguous to the newbie, or at  least make sense when explained. Using cast for all these purposes will  add to the learning curve and also, IMHO, is hackish, as has already  been stated.
>>   Each to thier own. I don't think it's too much of a stretch.
>>
>>> Also, doesnt the complier "know" which overload to call for the example:
>>>
>>> foo(cast(int)a);
>>>
>>> ?
>>   Yes, because the cast tells it which one to call.
>>  (I'm afraid I may have missed your point, there wasn't any more context to  this example, it was meant for another purpose, perhaps if you propose  another example I can answer more effectively)
>>  Regan
>
> What I meant to write was:
>
> int x;
>
> void foo(int x) { }
> void foo(real x) { }
>
> main() { foo(3); }
>
> Doesn't this compile?

Ignoring the malformed main ;) Yes. Due to (as someone mentioned earlier) the 'default' type of a numeric literal is 'int'. So, my example wasn't perfect. :)

Try this one:

void foo(long a) {}
void foo(float a) {}

void main()
{
	foo(5);	
}

The error reads:

pick.d(6): function pick.foo called with argument types:
	(int)
matches both:
	pick.foo(long)
and:
	pick.foo(float)

This is because 'int' is implicitly castable to both 'long' and 'float'.

Regan
May 20, 2005
I wish return values were thought of as an additional (hidden) "inout" argument to the function. Much like "this" is a hidden "in" argument when calling methods of an object.

If this could be consistently done, then it would not only allow for "return-type function overloading" but maybe also create the possibility of returning multiple values (tuples)! (which basically comes down to inventing a nice-enough syntax for it)

L.


May 20, 2005
"Regan Heath" <regan@netwin.co.nz> wrote in message news:opsq1tkott23k2f5@nrage.netwin.co.nz...
> On Wed, 18 May 2005 23:21:49 -0700, Kyle Furlong <ky220@umail.ucsb.edu> wrote:
> > Regan Heath wrote:
> >> On Wed, 18 May 2005 20:50:35 -0700, Kyle Furlong <ky220@umail.ucsb.edu>  wrote:
> >>
> >>> Regan Heath wrote:
> >>>
> >>>>> This is why "cast" is a hackish solution (it doesn't even work).
> >>>>
> >>>>   In your opinion :)
> >>>>  Regan
> >>>
> >>>
> >>> In my opinion also. Keywords should be unambiguous to the newbie, or at  least make sense when explained. Using cast for all these purposes will  add to the learning curve and also, IMHO, is hackish, as has already  been stated.
> >>   Each to thier own. I don't think it's too much of a stretch.
> >>
> >>> Also, doesnt the complier "know" which overload to call for the example:
> >>>
> >>> foo(cast(int)a);
> >>>
> >>> ?
> >>   Yes, because the cast tells it which one to call.
> >>  (I'm afraid I may have missed your point, there wasn't any more
> >> context to  this example, it was meant for another purpose, perhaps if
> >> you propose  another example I can answer more effectively)
> >>  Regan
> >
> > What I meant to write was:
> >
> > int x;
> >
> > void foo(int x) { }
> > void foo(real x) { }
> >
> > main() { foo(3); }
> >
> > Doesn't this compile?
>
> Ignoring the malformed main ;) Yes. Due to (as someone mentioned earlier)
> the 'default' type of a numeric literal is 'int'. So, my example wasn't
> perfect. :)
>
> Try this one:
>
> void foo(long a) {}
> void foo(float a) {}
>
> void main()
> {
> foo(5);
> }
>
> The error reads:
>
> pick.d(6): function pick.foo called with argument types:
> (int)
> matches both:
> pick.foo(long)
> and:
> pick.foo(float)
>
> This is because 'int' is implicitly castable to both 'long' and 'float'.
>
> Regan

Now, I would have espected it to choose long over float
since long anf int are both integer types and float is not...
however, I would say that if this ambiguity of passed parameters
would cause a compile-time error, then the same ambiguity when applied to
a choice of overloaded functions based on return types should also cause
a compile-time error... for consistancy.

TZ


May 20, 2005
"Lionello Lunesu" <lio@lunesu.removethis.com> wrote in message news:d6k1qi$bbj$1@digitaldaemon.com...
> I wish return values were thought of as an additional (hidden) "inout" argument to the function. Much like "this" is a hidden "in" argument when calling methods of an object.
>
> If this could be consistently done, then it would not only allow for "return-type function overloading" but maybe also create the possibility of returning multiple values (tuples)! (which basically comes down to inventing a nice-enough syntax for it)
>
> L.
>
>

Beautiful idea... I really like this one.  :)

But yes, coming up with a good syntax could be an issue.

My first thought was, perhaps something similar to a built in struct with optional members...

void main()
{
  struct{int,real} a() { return {9,1.2}}
  printf("___%d___%g___",a);
  real b = a.real;
}

but then I thought... what else could "int,real x" mean?

void main()
{
  int,real x() { return 9,1.2;}
  printf("___%d___%g___",x);
  real b = x.real;
}

of course, the commas look funny there, but I suppose one could get used to them. How about this?...

void main()
{
  int : real y() { return 9 : 1.2;}
  printf("___%d___%g___",y);
  real b = y.real;
}

or, here's one other possibility to consider...

void main()
{
  function (int,real) q() { return (9,1.2);}
  printf("___%d___%g___",q);
  real b = q.real;
}

just fule for brainstorming.  :)  Anyone care to add to it?

TZ


May 20, 2005
Hi.

> But yes, coming up with a good syntax could be an issue.

<snip>

>  struct{int,real} a() { return {9,1.2}}
>  int,real x() { return 9,1.2;}

I liked these two best. The other example introduced new stuff :-S that always scares me. Especially since "function" doesn't really have anything to do with the multiple-return value stuff.

I guess multiple return values should be treated as a struct, since that's how you would do it now. It's the implicit-ness that makes it nice. At the moment you'll have to manually declare a struct for each function with multiple return values.

The second example looks a lot like Python though. I like python's "a,b = x();".

L.


May 20, 2005
"Lionello Lunesu" <lio@lunesu.removethis.com> wrote in message news:d6k66u$g2j$1@digitaldaemon.com...
> Hi.
>
> > But yes, coming up with a good syntax could be an issue.
>
> <snip>
>
> >  struct{int,real} a() { return {9,1.2}}
> >  int,real x() { return 9,1.2;}
>
> I liked these two best. The other example introduced new stuff :-S that always scares me. Especially since "function" doesn't really have anything to do with the multiple-return value stuff.
>
> I guess multiple return values should be treated as a struct, since that's how you would do it now. It's the implicit-ness that makes it nice. At the moment you'll have to manually declare a struct for each function with multiple return values.
>
> The second example looks a lot like Python though. I like python's "a,b =
> x();".
>
> L.
>
>

Yep.  That's kindof what I was thinking also.
...except for the python stuff, which I wasn't aware of.

Figured either treat it as an implied struct, or as an implied set. Not really sure there's much (if any) difference, conceptually.

Anyway, of those two, I personally prefer...
int,real x() { return 9,1.2;}
because of it's simplicity...
but the other has more potential for flexibility.

TZ


May 20, 2005
Lionello Lunesu wrote:
> I wish return values were thought of as an additional (hidden) "inout" argument to the function. Much like "this" is a hidden "in" argument when calling methods of an object.
> 
> If this could be consistently done, then it would not only allow for "return-type function overloading" but maybe also create the possibility of returning multiple values (tuples)! (which basically comes down to inventing a nice-enough syntax for it)
> 
> L. 
> 
> 

You can use a Box or an array of Boxes as the return type.
This way, you can return anything you want, and if you use an array, you can return many thngs of any type you want.