Jump to page: 1 24  
Page
Thread overview
Value-based function overloading
May 18, 2005
Nod
May 18, 2005
G.Vidal
May 18, 2005
Matthias Becker
May 18, 2005
G.Vidal
May 18, 2005
Nod
May 18, 2005
Thomas Kuehne
May 18, 2005
Hasan Aljudy
May 18, 2005
Thomas Kuehne
May 18, 2005
Derek Parnell
May 18, 2005
Thomas Kuehne
May 19, 2005
Derek Parnell
May 19, 2005
Thomas Kuehne
Floating point rounding [was: Re: Value-based function overloading]
May 19, 2005
Uwe Salomon
May 19, 2005
James Dunne
May 19, 2005
Thomas Kuehne
May 19, 2005
James Dunne
May 19, 2005
Thomas Kuehne
May 19, 2005
Matthias Becker
May 19, 2005
G.Vidal
May 19, 2005
G.Vidal
May 19, 2005
Matthias Becker
May 19, 2005
Nod
May 18, 2005
Hasan Aljudy
May 18, 2005
Hasan Aljudy
May 18, 2005
Nod
May 18, 2005
Nod
May 18, 2005
Hasan Aljudy
May 19, 2005
Nod
May 18, 2005
Kyle Furlong
May 18, 2005
Kyle Furlong
May 18, 2005
Nod
May 18, 2005
I know a good idea when I see one, and I believe this topic is good enough to warrant a proper discussion. I will present a short summary and a proposed integration into D. Yeah, I know it's a bit "up there"... Maybe for 3.0? :)

/****************************************
* Summary:
***/
As the name suggests, value-based function overloading does function call
resolution based on the *values* of the function parameters in addition to the
type-based overloading already found in D.

Potential benefits are: clearer, more concise code, eases refactoring, separates the special cases from main algorithm, overriding buggy libraries easy.

Potential dangers are: compiler complexity, it can be misused to create unreadable code (but what can't?).

For reference, these are interesting:
Antti(first):  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23643
David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23651
David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23686
Kevin Bealer:  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23745

Maybe not interesting, but explains some benefits:
Me: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23732

/****************************************
* Proposed integration with D
***/

Syntax:
retType funcName(paramType paramName in paramRange) { ... }

Example:
void foo(char ch in '\n') { ... }
void foo(int i in 0..10) { ... }
void foo(Bar b in null) { ... }
void foo(char[] str in new Regex("/fooi/i")) { ... }

Nothing complex, a new keyword, in, which tests for membership in something, and after that a list (array literal?) of values. The last one would require an operator like opIn or something overloaded. This is only a draft though.

Implementation:
If all data is literal, and ranges checkable at compile-time, the full overload
resolution can happen at compile time. If not, the compiler needs generate the
if-else[1] construct needed to select the correct function.

Ambiguites are illegal. If one value range overlaps another, a compile-time error is generated.

Example:
void foo(int a in 0..10) { ... }
void foo(int a in 5..15) { ... }  // illegal, range 5..15 overlaps 0..10

Multiple parameters can resolve each other's ambiguites and as such, two overloads are only ambiguous if all parameters common between the two have ambiguities.

Example:
1) void foo(int a in 0..10, char b in 'x') { ... }
2) void foo(int a in 5..15, char b in 'y') { ... }  // legal
3) void foo(int a in 0..5,  char b in 'y') { ... }  // legal, see below
4) void foo(int a in 0..5,  char b in 'x') { ... }  // illegal, ambiguous to 1)

Only two overloads are considered at any one time, which is why number three above is legal; while both a is ambiguous with 1), and b is ambiguous with 2), *both* are not ambiguous at the same time.

If ranges are not comparable at compile time, such as when using objects with overloaded opCmp, the compiler must defer ambiguity checking until run-time. This only needs to be done in debug builds.

It is not necessary for the overloaded functions to cover all possible value ranges. If a value does not fit any of the overloaded functions, either a compile-time error is emitted if data is compile-time checkable, or an OverloadExecption is thrown at run-time.

Example:
1) void foo(int a in 1..4) { ... }
2) void foo(int a in 6..9) { ... }

int main()
{
int x = 5;
foo(2);  // calls 1)
foo(5);  // complains at compile-time
foo(x);  // throws at run-time
}

/****************************************
* In closing...
***/
I think one can compare this technique with forward references. While one
certainly can manage without it, heck we've done it for >10 years, it is/would
be a great relief to have.

So, what do you all think?
-Nod-


[1] For brevity, I will only mention if-else constructs, but when the value ranges allow it, a switch-case construct could be used, or some combination of the two.


May 18, 2005
I like it.

But I'd prefer a match() statement similar to CamL's one:

void foo (int e) {
	match (e) {
		-1:
			dothing();

		[-1..10[: // -1 included to ten excluded
			dothis();
			break;

		[10..15]:  zero included to fifteen included
			dothat();
			break;
		default:
			do();
	}
}

That would be transformed by the compiler into this, more uglier and difficult to understand:

void foo (int e) {
	if (e == -1) dothing();
	if ((e >= 0) && (e < 10)) {
		dothis();
		goto end; // break
	}
	if ((e >= 10) && (10 <= 15)) {
		dothat();
		goto end; // break;
	}
	do();
	end:
}

We can also imagine this for strings regexps:

match (string) {
	RegExp (stuff..) {
		blabla
		break;
	}
	RegExp (other stuff) {
		blibli;
		break;
	}
	default: baba...
}

But the _real power_ is for recursive array:

This function count the number of elements > 0 in an array (recursivity is useless here, but it's just an illustration)

int positive (int[] array) {
	int count (int[] a, int t) {
		match (array) {
			[]: return t; // end of array

			e::next : // e = first element of a, next = array.ptr +1
				if (e > 0) count (next, t+1);
				else       count (next, t);
		}
	}
	return count (array, 0);
}














May 18, 2005
>But I'd prefer a match() statement similar to CamL's one:
[snip]
>But the _real power_ is for recursive array:
>
>This function count the number of elements > 0 in an array (recursivity is useless here, but it's just an illustration)
>
>int positive (int[] array) {
>	int count (int[] a, int t) {
>		match (array) {
>			[]: return t; // end of array
>
>			e::next : // e = first element of a, next = array.ptr +1
>				if (e > 0) count (next, t+1);
>				else       count (next, t);
>		}
>	}
>	return count (array, 0);
>}
>

Well if the only deonstructable operation is :: pattern matching isn't as powerfull as Caml's (or better ML's) pattern matching by far.


May 18, 2005
Le Wed, 18 May 2005 11:00:11 +0000, Matthias Becker a écrit :

> Well if the only deonstructable operation is :: pattern matching isn't as powerfull as Caml's (or better ML's) pattern matching by far.

Of course that was a mere illustration.
All the other operations should be implemented, but as I was talking to
people who potentially don't know pattern matching... well anyway

May 18, 2005
Nod wrote:
> I know a good idea when I see one, and I believe this topic is good enough to
> warrant a proper discussion. I will present a short summary and a proposed
> integration into D. Yeah, I know it's a bit "up there"... Maybe for 3.0? :)
> 
> /****************************************
> * Summary:
> ***/
> As the name suggests, value-based function overloading does function call
> resolution based on the *values* of the function parameters in addition to the
> type-based overloading already found in D.
> 
> Potential benefits are: clearer, more concise code, eases refactoring, separates
> the special cases from main algorithm, overriding buggy libraries easy.
> 
> Potential dangers are: compiler complexity, it can be misused to create
> unreadable code (but what can't?).
> 
> For reference, these are interesting:
> Antti(first):  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23643
> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23651
> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23686
> Kevin Bealer:  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23745
> 
> Maybe not interesting, but explains some benefits:
> Me: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23732
> 
> /****************************************
> * Proposed integration with D
> ***/
> 
> Syntax:
> retType funcName(paramType paramName in paramRange) { ... }
> 
> Example:
> void foo(char ch in '\n') { ... }
> void foo(int i in 0..10) { ... }
> void foo(Bar b in null) { ... }
> void foo(char[] str in new Regex("/fooi/i")) { ... }
> 
> Nothing complex, a new keyword, in, which tests for membership in something, and
> after that a list (array literal?) of values. The last one would require an
> operator like opIn or something overloaded. This is only a draft though.
> 
> Implementation:
> If all data is literal, and ranges checkable at compile-time, the full overload
> resolution can happen at compile time. If not, the compiler needs generate the
> if-else[1] construct needed to select the correct function.
> 
> Ambiguites are illegal. If one value range overlaps another, a compile-time
> error is generated.
> 
> Example:
> void foo(int a in 0..10) { ... }
> void foo(int a in 5..15) { ... }  // illegal, range 5..15 overlaps 0..10
> 
> Multiple parameters can resolve each other's ambiguites and as such, two
> overloads are only ambiguous if all parameters common between the two have
> ambiguities.
> 
> Example:
> 1) void foo(int a in 0..10, char b in 'x') { ... }
> 2) void foo(int a in 5..15, char b in 'y') { ... }  // legal
> 3) void foo(int a in 0..5,  char b in 'y') { ... }  // legal, see below
> 4) void foo(int a in 0..5,  char b in 'x') { ... }  // illegal, ambiguous to 1)
> 
> Only two overloads are considered at any one time, which is why number three
> above is legal; while both a is ambiguous with 1), and b is ambiguous with 2),
> *both* are not ambiguous at the same time.
> 
> If ranges are not comparable at compile time, such as when using objects with
> overloaded opCmp, the compiler must defer ambiguity checking until run-time.
> This only needs to be done in debug builds.
> 
> It is not necessary for the overloaded functions to cover all possible value
> ranges. If a value does not fit any of the overloaded functions, either a
> compile-time error is emitted if data is compile-time checkable, or an
> OverloadExecption is thrown at run-time.
> 
> Example:
> 1) void foo(int a in 1..4) { ... }
> 2) void foo(int a in 6..9) { ... }
> 
> int main()
> {
> int x = 5;
> foo(2);  // calls 1)
> foo(5);  // complains at compile-time
> foo(x);  // throws at run-time
> }
> 
> /****************************************
> * In closing...
> ***/
> I think one can compare this technique with forward references. While one
> certainly can manage without it, heck we've done it for >10 years, it is/would
> be a great relief to have.
> 
> So, what do you all think?
> -Nod-
> 
> 
> [1] For brevity, I will only mention if-else constructs, but when the value
> ranges allow it, a switch-case construct could be used, or some combination of
> the two.
> 
> 

I like the idea, although one downside is some runtime over head, but I think it's not really an issue, it would probably be equivilent to just an if statement.
Maybe there should be some keyword that must be used when declaring the function and/or using it, so that who ever reads the code can see that there are other parts of the function somewhere else.
I say other "parts", because this is not really function overloading, it's just seperating the function's parts into seperate functions.

so that

function(int i)
{
    if( i == 0 )
    {
        ....
    }
    else if( i >= 1 && i <= 5 )
    {
        ....
    }

    else
    {
        ....
    }
}

becomes

function( int 0 )
{
    ....
}
function( int 1..5 )
{
    ....
}
function( int i )
{
    ....
}

This might be confusing for some, so there probably must be some rules to make it clearer for the reader (since the original motivation for the idea is clarity and maintainability), at least all the function parts must be in the same module.
Also, maybe the part functions should be nested inside the whole function? and special cases should be above the general case, because they are handled logically as an if..else? So it maybe a clearer structur than a switch

/keyword/ function(int i)
{
    function( 0 )
    {
        ....
    }

    function( 1..5 )
    {
        ....
    }

    function( i )
    {
        ....
    }
}

And the function may contain nothing except for the "parts"
May 18, 2005
Hasan Aljudy wrote:
> Nod wrote:
> 
>> I know a good idea when I see one, and I believe this topic is good enough to
>> warrant a proper discussion. I will present a short summary and a proposed
>> integration into D. Yeah, I know it's a bit "up there"... Maybe for 3.0? :)
>>
>> /****************************************
>> * Summary:
>> ***/
>> As the name suggests, value-based function overloading does function call
>> resolution based on the *values* of the function parameters in addition to the
>> type-based overloading already found in D.
>>
>> Potential benefits are: clearer, more concise code, eases refactoring, separates
>> the special cases from main algorithm, overriding buggy libraries easy.
>>
>> Potential dangers are: compiler complexity, it can be misused to create
>> unreadable code (but what can't?).
>>
>> For reference, these are interesting:
>> Antti(first):  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23643
>> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23651
>> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23686
>> Kevin Bealer:  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23745
>>
>> Maybe not interesting, but explains some benefits:
>> Me: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23732
>>
>> /****************************************
>> * Proposed integration with D
>> ***/
>>
>> Syntax:
>> retType funcName(paramType paramName in paramRange) { ... }
>>
>> Example:
>> void foo(char ch in '\n') { ... }
>> void foo(int i in 0..10) { ... }
>> void foo(Bar b in null) { ... }
>> void foo(char[] str in new Regex("/fooi/i")) { ... }
>>
>> Nothing complex, a new keyword, in, which tests for membership in something, and
>> after that a list (array literal?) of values. The last one would require an
>> operator like opIn or something overloaded. This is only a draft though.
>>
>> Implementation:
>> If all data is literal, and ranges checkable at compile-time, the full overload
>> resolution can happen at compile time. If not, the compiler needs generate the
>> if-else[1] construct needed to select the correct function.
>>
>> Ambiguites are illegal. If one value range overlaps another, a compile-time
>> error is generated.
>>
>> Example:
>> void foo(int a in 0..10) { ... }
>> void foo(int a in 5..15) { ... }  // illegal, range 5..15 overlaps 0..10
>>
>> Multiple parameters can resolve each other's ambiguites and as such, two
>> overloads are only ambiguous if all parameters common between the two have
>> ambiguities.
>>
>> Example:
>> 1) void foo(int a in 0..10, char b in 'x') { ... }
>> 2) void foo(int a in 5..15, char b in 'y') { ... }  // legal
>> 3) void foo(int a in 0..5,  char b in 'y') { ... }  // legal, see below
>> 4) void foo(int a in 0..5,  char b in 'x') { ... }  // illegal, ambiguous to 1)
>>
>> Only two overloads are considered at any one time, which is why number three
>> above is legal; while both a is ambiguous with 1), and b is ambiguous with 2),
>> *both* are not ambiguous at the same time.
>>
>> If ranges are not comparable at compile time, such as when using objects with
>> overloaded opCmp, the compiler must defer ambiguity checking until run-time.
>> This only needs to be done in debug builds.
>>
>> It is not necessary for the overloaded functions to cover all possible value
>> ranges. If a value does not fit any of the overloaded functions, either a
>> compile-time error is emitted if data is compile-time checkable, or an
>> OverloadExecption is thrown at run-time.
>>
>> Example:
>> 1) void foo(int a in 1..4) { ... }
>> 2) void foo(int a in 6..9) { ... }
>>
>> int main()
>> {
>> int x = 5;
>> foo(2);  // calls 1)
>> foo(5);  // complains at compile-time
>> foo(x);  // throws at run-time
>> }
>>
>> /****************************************
>> * In closing...
>> ***/
>> I think one can compare this technique with forward references. While one
>> certainly can manage without it, heck we've done it for >10 years, it is/would
>> be a great relief to have.
>>
>> So, what do you all think?
>> -Nod-
>>
>>
>> [1] For brevity, I will only mention if-else constructs, but when the value
>> ranges allow it, a switch-case construct could be used, or some combination of
>> the two.
>>
>>
> 
> I like the idea, although one downside is some runtime over head, but I think it's not really an issue, it would probably be equivilent to just an if statement.
> Maybe there should be some keyword that must be used when declaring the function and/or using it, so that who ever reads the code can see that there are other parts of the function somewhere else.
> I say other "parts", because this is not really function overloading, it's just seperating the function's parts into seperate functions.
> 
> so that
> 
> function(int i)
> {
>     if( i == 0 )
>     {
>         ....
>     }
>     else if( i >= 1 && i <= 5 )
>     {
>         ....
>     }
> 
>     else
>     {
>         ....
>     }
> }
> 
> becomes
> 
> function( int 0 )
> {
>     ....
> }
> function( int 1..5 )
> {
>     ....
> }
> function( int i )
> {
>     ....
> }
> 
> This might be confusing for some, so there probably must be some rules to make it clearer for the reader (since the original motivation for the idea is clarity and maintainability), at least all the function parts must be in the same module.
> Also, maybe the part functions should be nested inside the whole function? and special cases should be above the general case, because they are handled logically as an if..else? So it maybe a clearer structur than a switch
> 
> /keyword/ function(int i)
> {
>     function( 0 )
>     {
>         ....
>     }
> 
>     function( 1..5 )
>     {
>         ....
>     }
> 
>     function( i )
>     {
>         ....
>     }
> }
> 
> And the function may contain nothing except for the "parts"

woops, my bad, didn't read the whole original post, the OP already outlined the specs for the feature.
May 18, 2005
Nod wrote:
> I know a good idea when I see one, and I believe this topic is good enough to
> warrant a proper discussion. I will present a short summary and a proposed
> integration into D. Yeah, I know it's a bit "up there"... Maybe for 3.0? :)
> 
> /****************************************
> * Summary:
> ***/
> As the name suggests, value-based function overloading does function call
> resolution based on the *values* of the function parameters in addition to the
> type-based overloading already found in D.
> 
> Potential benefits are: clearer, more concise code, eases refactoring, separates
> the special cases from main algorithm, overriding buggy libraries easy.
> 
> Potential dangers are: compiler complexity, it can be misused to create
> unreadable code (but what can't?).
> 
> For reference, these are interesting:
> Antti(first):  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23643
> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23651
> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23686
> Kevin Bealer:  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23745
> 
> Maybe not interesting, but explains some benefits:
> Me: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23732
> 
> /****************************************
> * Proposed integration with D
> ***/
> 
> Syntax:
> retType funcName(paramType paramName in paramRange) { ... }
> 
> Example:
> void foo(char ch in '\n') { ... }
> void foo(int i in 0..10) { ... }
> void foo(Bar b in null) { ... }
> void foo(char[] str in new Regex("/fooi/i")) { ... }
> 
> Nothing complex, a new keyword, in, which tests for membership in something, and
> after that a list (array literal?) of values. The last one would require an
> operator like opIn or something overloaded. This is only a draft though.
> 
> Implementation:
> If all data is literal, and ranges checkable at compile-time, the full overload
> resolution can happen at compile time. If not, the compiler needs generate the
> if-else[1] construct needed to select the correct function.
> 
> Ambiguites are illegal. If one value range overlaps another, a compile-time
> error is generated.
> 
> Example:
> void foo(int a in 0..10) { ... }
> void foo(int a in 5..15) { ... }  // illegal, range 5..15 overlaps 0..10
> 
> Multiple parameters can resolve each other's ambiguites and as such, two
> overloads are only ambiguous if all parameters common between the two have
> ambiguities.
> 
> Example:
> 1) void foo(int a in 0..10, char b in 'x') { ... }
> 2) void foo(int a in 5..15, char b in 'y') { ... }  // legal
> 3) void foo(int a in 0..5,  char b in 'y') { ... }  // legal, see below
> 4) void foo(int a in 0..5,  char b in 'x') { ... }  // illegal, ambiguous to 1)
> 
> Only two overloads are considered at any one time, which is why number three
> above is legal; while both a is ambiguous with 1), and b is ambiguous with 2),
> *both* are not ambiguous at the same time.
> 
> If ranges are not comparable at compile time, such as when using objects with
> overloaded opCmp, the compiler must defer ambiguity checking until run-time.
> This only needs to be done in debug builds.
> 
> It is not necessary for the overloaded functions to cover all possible value
> ranges. If a value does not fit any of the overloaded functions, either a
> compile-time error is emitted if data is compile-time checkable, or an
> OverloadExecption is thrown at run-time.
> 
> Example:
> 1) void foo(int a in 1..4) { ... }
> 2) void foo(int a in 6..9) { ... }
> 
> int main()
> {
> int x = 5;
> foo(2);  // calls 1)
> foo(5);  // complains at compile-time
> foo(x);  // throws at run-time
> }
> 
> /****************************************
> * In closing...
> ***/
> I think one can compare this technique with forward references. While one
> certainly can manage without it, heck we've done it for >10 years, it is/would
> be a great relief to have.
> 
> So, what do you all think?
> -Nod-
> 
> 
> [1] For brevity, I will only mention if-else constructs, but when the value
> ranges allow it, a switch-case construct could be used, or some combination of
> the two.
> 
> 
Hear, hear.
May 18, 2005
Kyle Furlong wrote:
> Nod wrote:
> 
>> I know a good idea when I see one, and I believe this topic is good enough to
>> warrant a proper discussion. I will present a short summary and a proposed
>> integration into D. Yeah, I know it's a bit "up there"... Maybe for 3.0? :)
>>
>> /****************************************
>> * Summary:
>> ***/
>> As the name suggests, value-based function overloading does function call
>> resolution based on the *values* of the function parameters in addition to the
>> type-based overloading already found in D.
>>
>> Potential benefits are: clearer, more concise code, eases refactoring, separates
>> the special cases from main algorithm, overriding buggy libraries easy.
>>
>> Potential dangers are: compiler complexity, it can be misused to create
>> unreadable code (but what can't?).
>>
>> For reference, these are interesting:
>> Antti(first):  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23643
>> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23651
>> David Medlock: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23686
>> Kevin Bealer:  http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23745
>>
>> Maybe not interesting, but explains some benefits:
>> Me: http://www.digitalmars.com/drn-bin/wwwnews?digitalmars.D/23732
>>
>> /****************************************
>> * Proposed integration with D
>> ***/
>>
>> Syntax:
>> retType funcName(paramType paramName in paramRange) { ... }
>>
>> Example:
>> void foo(char ch in '\n') { ... }
>> void foo(int i in 0..10) { ... }
>> void foo(Bar b in null) { ... }
>> void foo(char[] str in new Regex("/fooi/i")) { ... }
>>
>> Nothing complex, a new keyword, in, which tests for membership in something, and
>> after that a list (array literal?) of values. The last one would require an
>> operator like opIn or something overloaded. This is only a draft though.
>>
>> Implementation:
>> If all data is literal, and ranges checkable at compile-time, the full overload
>> resolution can happen at compile time. If not, the compiler needs generate the
>> if-else[1] construct needed to select the correct function.
>>
>> Ambiguites are illegal. If one value range overlaps another, a compile-time
>> error is generated.
>>
>> Example:
>> void foo(int a in 0..10) { ... }
>> void foo(int a in 5..15) { ... }  // illegal, range 5..15 overlaps 0..10
>>
>> Multiple parameters can resolve each other's ambiguites and as such, two
>> overloads are only ambiguous if all parameters common between the two have
>> ambiguities.
>>
>> Example:
>> 1) void foo(int a in 0..10, char b in 'x') { ... }
>> 2) void foo(int a in 5..15, char b in 'y') { ... }  // legal
>> 3) void foo(int a in 0..5,  char b in 'y') { ... }  // legal, see below
>> 4) void foo(int a in 0..5,  char b in 'x') { ... }  // illegal, ambiguous to 1)
>>
>> Only two overloads are considered at any one time, which is why number three
>> above is legal; while both a is ambiguous with 1), and b is ambiguous with 2),
>> *both* are not ambiguous at the same time.
>>
>> If ranges are not comparable at compile time, such as when using objects with
>> overloaded opCmp, the compiler must defer ambiguity checking until run-time.
>> This only needs to be done in debug builds.
>>
>> It is not necessary for the overloaded functions to cover all possible value
>> ranges. If a value does not fit any of the overloaded functions, either a
>> compile-time error is emitted if data is compile-time checkable, or an
>> OverloadExecption is thrown at run-time.
>>
>> Example:
>> 1) void foo(int a in 1..4) { ... }
>> 2) void foo(int a in 6..9) { ... }
>>
>> int main()
>> {
>> int x = 5;
>> foo(2);  // calls 1)
>> foo(5);  // complains at compile-time
>> foo(x);  // throws at run-time
>> }
>>
>> /****************************************
>> * In closing...
>> ***/
>> I think one can compare this technique with forward references. While one
>> certainly can manage without it, heck we've done it for >10 years, it is/would
>> be a great relief to have.
>>
>> So, what do you all think?
>> -Nod-
>>
>>
>> [1] For brevity, I will only mention if-else constructs, but when the value
>> ranges allow it, a switch-case construct could be used, or some combination of
>> the two.
>>
>>
> Hear, hear.

One thing that just occured to me is, cant you acheive the same goal using aserts and invariants? Isnt that what they are designed for?
May 18, 2005
In article <d6fkde$2i61$1@digitaldaemon.com>, Hasan Aljudy says...
>
>> <snip>
>
>I like the idea, although one downside is some runtime over head, but I think it's not really an issue, it would probably be equivilent to just an if statement.

Correct, that is what I think too. And since one would not be able to order the if/else statement after frequency, codegen may be slightly less optimized than a hand-coded one. But speed is rarely *that* important anyways. The gained clarity will make up for it.

>Maybe there should be some keyword that must be used when declaring the
>function and/or using it, so that who ever reads the code can see that
>there are other parts of the function somewhere else.
>I say other "parts", because this is not really function overloading,
>it's just seperating the function's parts into seperate functions.
>
>so that
>
>function(int i)
>{
>     if( i == 0 )
>     {
>         ....
>     }
>     else if( i >= 1 && i <= 5 )
>     {
>         ....
>     }
>
>     else
>     {
>         ....
>     }
>}
>
>becomes
>
>function( int 0 )
>{
>     ....
>}
>function( int 1..5 )
>{
>     ....
>}
>function( int i )
>{
>     ....
>}
>
>This might be confusing for some, so there probably must be some rules to make it clearer for the reader (since the original motivation for the idea is clarity and maintainability), at least all the function parts must be in the same module.

Yes, this may be confusing. However, I believe that putting too many restrictions on the technique will also limit its value. In this way, you would not be able to overload any function to which you do not have write access to the source. While that wouldn't be a very clear thing to do, sometimes you really need to, and when you do, you would have to use an even worse kludge like a wrapper function.

>Also, maybe the part functions should be nested inside the whole function? and special cases should be above the general case, because they are handled logically as an if..else? So it maybe a clearer structur than a switch
>
>/keyword/ function(int i)
>{
>     function( 0 )
>     {
>         ....
>     }
>
>     function( 1..5 )
>     {
>         ....
>     }
>
>     function( i )
>     {
>         ....
>     }
>}
>
>And the function may contain nothing except for the "parts"

This is again an interesting idea, and you are right, it would indeed make things very clear. But this would also be somewhat limiting. For instance, when splitting a function, that is turning it into two value-overloaded ones, you would have to add both the outer function and a new inner. This is not far from the original case of adding to an if/else statement *and* adding a new function. Too much editing imho.

Don't get me wrong though, there *will* have to be limits to the technique, I just don't think boxing it into keyword/function/module "jails" is giving enough freedom for the programmer. But this may just be me being too liberal :)



May 18, 2005
In article <d6fkhg$2i61$2@digitaldaemon.com>, Hasan Aljudy says...
>>
>> <snip
>>
>woops, my bad, didn't read the whole original post, the OP already outlined the specs for the feature.

Not at all, I posted a *draft* of the technique. Opinions/ideas are highly welcome!



« First   ‹ Prev
1 2 3 4