May 18, 2005
In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>
>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);
>}
>
>

Hey, I like the [x..y[ inclusive/exclusive ranges.

The match statement looks scary though :)

-Nod-


May 18, 2005
In article <d6fvvg$2vq1$2@digitaldaemon.com>, Kyle Furlong says...
>
>Kyle Furlong wrote:
>> Nod wrote:
>>>
>>> <snip>
>>>
>> 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?

No, asserts and invariants are only for verifying that the function/program is operating with sane values. Value-based function overloading on the other hand is a form of implicit flow control.

With asserts and invariants, the compiler inserts *checks* on function invocation, which throws exceptions if the values are out-of-range. With value-based overloading *flow instructions* are inserted, so that if the values are out-of-range (so to speak) another overload is called.

The two does not exclude one another. Neither do any of them supersede the other. I rather believe that they complement eachother.

-Nod-


May 18, 2005
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Nod schrieb am Wed, 18 May 2005 19:57:36 +0000 (UTC):
> In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>>
>>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:
>>}
>>

<snip>
>
> Hey, I like the [x..y[ inclusive/exclusive ranges.
<snip>

That syntax is a nightmare. Try to write a parser that generates a simple token tree and compare the complexity with and without exclusive-range support.

Is there any situation where exclusive ranges are neccesary and can't be replaced by inclusive ranges?

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFCi+Bs3w+/yD4P9tIRAnEHAKCY18ISk1OSixy7GT8+vnVeiYqHpgCfRWN/
SVSZOEy+YFDcAtm+ngavrGc=
=/llO
-----END PGP SIGNATURE-----
May 18, 2005
Nod wrote:
> In article <d6fkde$2i61$1@digitaldaemon.com>, Hasan Aljudy says...
> 
>>><snip>
>> <snip> 
>> 
> 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.
> 
> 
>> <snip>
>>
> 
> 
> 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 :)
> 
> 
> 

I see your point.
I still think the general function should have a keyword associated with it to indicate that it has value-based overloaders (if that's what you'd call it), otherwise it can cause serious ocnfusion and headechs when debugging, where you look at a function, expect certain results, but see  that the actual results are totally different than what you expected.
Then you're not so sure which values are overloaded and which are not, and unless you have a really good IDE, then you're gonna spend (read: waste) some time trying to figure out whether a specific value is overloaded or not.

So I think some rules must be set to elliminate such problems.

You can easily override library functions like this:

file1.d
----------------------
import library;

//we will override "foo" in the library
void foo( 0 )
{
  //do something special ..
}

void foo( int i )
{
   library.foo( i );
}
--------------------

file2.d
-------------------
//don't import the library, import your overloads
import file1;

foo(0); //value overloaded
foo(4); //default library function
-------------------

Anyway, I think in most cases users aren't exactly aware of the details of library implementations, so I dunno, but I don't think that case would come up very often.

However, the case of debugging code and not being sure which values are overloaded and which are not is very very likely to come up, infact I think it comes up all the time.
May 18, 2005
Thomas Kuehne wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Nod schrieb am Wed, 18 May 2005 19:57:36 +0000 (UTC):
> 
>>In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>>
>>>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:
>>>}
>>>
> 
> 
> <snip>
> 
>>Hey, I like the [x..y[ inclusive/exclusive ranges.
> 
> <snip>
> 
> That syntax is a nightmare. Try to write a parser that generates a
> simple token tree and compare the complexity with and without
> exclusive-range support. 
> 
> Is there any situation where exclusive ranges are neccesary and can't be
> replaced by inclusive ranges?
> 
> Thomas
>  
> 
> -----BEGIN PGP SIGNATURE-----
> 
> iD8DBQFCi+Bs3w+/yD4P9tIRAnEHAKCY18ISk1OSixy7GT8+vnVeiYqHpgCfRWN/
> SVSZOEy+YFDcAtm+ngavrGc=
> =/llO
> -----END PGP SIGNATURE-----

hmm, I can suggest of the top of my head the following: assume initially that both ends are exclusive, unless these ends are explicitly used somewhere else by themselves

foo( 1..5 ) //initially inclusive
{ .. }
foo( 5 ) //the previous declaration becomes exclusive

but this could easily lead to duplicate code nd/or redundancy..
foo( int i )
{
    //complex code
}

foo( 1..5 )
{
    //something else
}

foo( 5 )
{
    //this is not a special case, it's just for exclusion, so we
    //will probably copy-paste the complex code from the general
    //function, or call something like
    // default foo( 5 );
    //but even if we do that, the redundancy is still there
}
May 18, 2005
On Thu, 19 May 2005 02:40:16 +0200, Thomas Kuehne wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Nod schrieb am Wed, 18 May 2005 19:57:36 +0000 (UTC):
>> In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>>>
>>>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:
>>>}
>>>
> 
> <snip>
>>
>> Hey, I like the [x..y[ inclusive/exclusive ranges.
> <snip>
> 
> That syntax is a nightmare. Try to write a parser that generates a simple token tree and compare the complexity with and without exclusive-range support.
> 
> Is there any situation where exclusive ranges are neccesary and can't be replaced by inclusive ranges?
> 

   real x;
   . . .
   switch (x)
   {
       case 0.0 ... 0.9999999999:
           . . .
       break;
       case 1.0 ... 1.9999999999:
       . . .

   }

when what I really need is ...

   if (x >= 0.0 and < 1.0)
   {
      . . .
   } else if (x >= 1.0 and x < 2.0)
   {
      . . .
   }

-- 
Derek
Melbourne, Australia
19/05/2005 9:23:37 AM
May 18, 2005
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Derek Parnell schrieb am Thu, 19 May 2005 09:25:53 +1000:
> On Thu, 19 May 2005 02:40:16 +0200, Thomas Kuehne wrote:
>
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>> 
>> Nod schrieb am Wed, 18 May 2005 19:57:36 +0000 (UTC):
>>> In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>>>>
>>>>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:
>>>>}
>>>>
>> 
>> <snip>
>>>
>>> Hey, I like the [x..y[ inclusive/exclusive ranges.
>> <snip>
>> 
>> That syntax is a nightmare. Try to write a parser that generates a simple token tree and compare the complexity with and without exclusive-range support.
>> 
>> Is there any situation where exclusive ranges are neccesary and can't be replaced by inclusive ranges?
>> 
>
>    real x;
>    . . .
>    switch (x)
>    {
>        case 0.0 ... 0.9999999999:
>            . . .
>        break;
>        case 1.0 ... 1.9999999999:
>        . . .
>
>    }
>
> when what I really need is ...
>
>    if (x >= 0.0 and < 1.0)
>    {
>       . . .
>    } else if (x >= 1.0 and x < 2.0)
>    {
>       . . .
>    }

Floating types can't be used as switch conditionals.

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFCi+3O3w+/yD4P9tIRAnmNAKDPDpwm8hXOR5yw6wpJqH13j3S4MACgqCsI
hzLEYiHYbxY28Wb4Lu6B0Jg=
=7X2i
-----END PGP SIGNATURE-----
May 18, 2005
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hasan Aljudy schrieb am Wed, 18 May 2005 17:18:20 -0600:
> Thomas Kuehne wrote:
>> 
>> Nod schrieb am Wed, 18 May 2005 19:57:36 +0000 (UTC):
>> 
>>>In article <pan.2005.05.18.09.22.26.707525@wanadoo.fr>, G.Vidal says...
>>>
>>>>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:
>>>>}
>>>>
>> 
>> 
>> <snip>
>> 
>>>Hey, I like the [x..y[ inclusive/exclusive ranges.
>> 
>> <snip>
>> 
>> That syntax is a nightmare. Try to write a parser that generates a simple token tree and compare the complexity with and without exclusive-range support.
>> 
>> Is there any situation where exclusive ranges are neccesary and can't be replaced by inclusive ranges?
>
> hmm, I can suggest of the top of my head the following: assume initially that both ends are exclusive, unless these ends are explicitly used somewhere else by themselves

The borders should be inclusive, otherwise your run into problems with type.max/type.min.

> foo( 1..5 ) //initially inclusive
> { .. }
> foo( 5 ) //the previous declaration becomes exclusive

inclusive and without change of the border type
foo(1..4)
foo(5)

Why do you need to the change the border evaluation in dependency of another declaration?

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFCi/Ao3w+/yD4P9tIRAgzsAJ91TDsGM6ZwEfUjVUywtbvZEE3bOQCeJ28y
9YkhdMPGqpEXsxJowsgF06A=
=rUPG
-----END PGP SIGNATURE-----
May 19, 2005
In article <d6ghoo$for$1@digitaldaemon.com>, Hasan Aljudy says...
>
>Nod wrote:
>> In article <d6fkde$2i61$1@digitaldaemon.com>, Hasan Aljudy says...
>> 
>>>><snip>
>>> <snip>
>>> 
>> <snip>
>> 
>
>I see your point.
>I still think the general function should have a keyword associated with
>it to indicate that it has value-based overloaders (if that's what you'd
>call it),

That's the working name. :)

>otherwise it can cause serious ocnfusion and headechs when debugging, where you look at a function, expect certain results, but see
>  that the actual results are totally different than what you expected.
>Then you're not so sure which values are overloaded and which are not, and unless you have a really good IDE, then you're gonna spend (read: waste) some time trying to figure out whether a specific value is overloaded or not.
>
>So I think some rules must be set to elliminate such problems.
>
>You can easily override library functions like this:
>
>file1.d
>----------------------
>import library;
>
>//we will override "foo" in the library
>void foo( 0 )
>{
>   //do something special ..
>}
>
>void foo( int i )
>{
>    library.foo( i );
>}
>--------------------
>
>file2.d
>-------------------
>//don't import the library, import your overloads
>import file1;
>
>foo(0); //value overloaded
>foo(4); //default library function
>-------------------
>
>Anyway, I think in most cases users aren't exactly aware of the details of library implementations, so I dunno, but I don't think that case would come up very often.
>

Hmm yes, I guess it's a call to be made based on design philosophy, and a weighting of programmer freedom vs. potential for trouble.

>However, the case of debugging code and not being sure which values are overloaded and which are not is very very likely to come up, infact I think it comes up all the time.

Yes, I can see your concern, but this seems like a somewhat hypothetical problem. Overloads based on type has existed for quite some time, and it really isn't hard to figure out which one is being called. For one, you simply have to step into the function instead of around it when debugging. And you can use watches to see the parameter types/values which is being passed to the function. But yes, I acknowledge that the problem will presumably be somewhat exacerbated with value-based overloading due to more widespread use and the fact that values change more easily.

A keyword may ease things a bit, I give you that. But is it strictly necessary? I believe good programming practises can go a long way, while not forcing all overloads to a single physical area, it would be good manors to keep the overloads together. It would be hard to read otherwise.

-Nod-


May 19, 2005
On Thu, 19 May 2005 03:37:18 +0200, Thomas Kuehne wrote:

> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> Derek Parnell schrieb am Thu, 19 May 2005 09:25:53 +1000:

[snip]
>>> Is there any situation where exclusive ranges are neccesary and can't be replaced by inclusive ranges?
>>> 
>>
>>    real x;
>>    . . .
>>    switch (x)
>>    {
>>        case 0.0 ... 0.9999999999:
>>            . . .
>>        break;
>>        case 1.0 ... 1.9999999999:
>>        . . .
>>
>>    }
>>
>> when what I really need is ...
>>
>>    if (x >= 0.0 and < 1.0)
>>    {
>>       . . .
>>    } else if (x >= 1.0 and x < 2.0)
>>    {
>>       . . .
>>    }
> 
> Floating types can't be used as switch conditionals.

Hey! Neither can ranges ;-)

We are brainstorming here, right? If we can consider ranges then I think we can consider switches using any type.

-- 
Derek
Melbourne, Australia
19/05/2005 10:25:43 AM