View mode: basic / threaded / horizontal-split · Log in · Help
May 18, 2005
Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
>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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Re: Value-based function overloading
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
Top | Discussion index | About this forum | D home