www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - delegate object instead of a literal

reply Joel Christensen <joelcnz gmail.com> writes:
Hi,

This program loops through a string until it finds a number and gives 
the position of it.

The first assert works, but not the second one.

import std.algorithm;

void main() {
	static bool isNumber( char input, char dummy ) {
		if ( ( input >= '0' && input <= '9' ) || input == '.' )
			return true;
		else
			return false;
	}
	
	string str = "abc123";
	assert( countUntil!( ( input, b ) {
		if ( ( input >= '0' && input <= '9' ) || input == '.' ) return true; 
else return false;
		} )(str, 0) == 3 ); // works
	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
}

This is the error:
parse.d(15): Error: template instance 
countUntil!(isNumber,string,string) does not match template declaration 
countUntil(alias pred = "a == b",R1,R2) if 
(is(typeof(startsWith!(pred)(haystack,needle))))

- Joel
Aug 14 2011
next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,
 
 This program loops through a string until it finds a number and gives
 the position of it.
 
 The first assert works, but not the second one.
 
 import std.algorithm;
 
 void main() {
 	static bool isNumber( char input, char dummy ) {
 		if ( ( input >= '0' && input <= '9' ) || input == '.' )
 			return true;
 		else
 			return false;
 	}
 
 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 		if ( ( input >= '0' && input <= '9' ) || input == '.' ) return true;
 else return false;
 		} )(str, 0) == 3 ); // works
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 }
 
 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

Okay. Several things here. One, don't ever declare an individual char. char is a UTF-8 code unit, not a code point. And characters are code points. ASCII characters only require one UTF-8 code unit, so they can be held in a single char, but that's not true of characters in general. When dealing with individual characters, always use dchar. So, if you're using foreach for a string, use dchar as the iteration type. e.g. foreach(dchar c; str) {...} Youre code will be wrong if it iterates over char or wchar, since those aren't full characters. And because of that, _all_ strings are ranges of dchar, not char or wchar. So, the fact that you're using string instead of dstring with a range-based function like countUntil is irrelevant. You're still dealing with a range of dchars. So, isNumber should definitely be taking dchars, not chars. Two, don't pass 0 as a string. 0 is an int. _None_ of those countUntil calls shouldn't be compiling at all. It's actually a bit disturbing thath the first one compiles. It definitely looks like a bug. countUntil takes two ranges with the same element type. 0 is not a range, let alone a range of dchars. 0 shouldn't even really be used as a dchar, since 0 is an int, not a character. Third, you really shouldn't be using if statements like that. It looks like you don't know what you're doing if you do if(condition) return true; else return false; The condition is already a bool. You can simply do return condition; Plenty of newbie programmers make that mistake, and I don't know how experienced a programmer you are, but I'd advise you not to do that anymore. In any case, I'm a bit shocked that the first call to countUntil compiles, let alone works. That's quite disturbing actually. It looks like countUntil has a bug. However, your usage of countUntil here does imply that it could use an overload which takes a unary function and only one range. - Jonathan M Davis
Aug 14 2011
prev sibling next sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 14, 2011 03:23:39 Jonathan M Davis wrote:
 On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,
 
 This program loops through a string until it finds a number and gives
 the position of it.
 
 The first assert works, but not the second one.
 
 import std.algorithm;
 
 void main() {
 
 	static bool isNumber( char input, char dummy ) {
 	
 		if ( ( input >= '0' && input <= '9' ) || input == '.' )
 		
 			return true;
 		
 		else
 		
 			return false;
 	
 	}
 	
 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 	
 		if ( ( input >= '0' && input <= '9' ) || input == '.' ) return true;
 
 else return false;
 
 		} )(str, 0) == 3 ); // works
 	
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 
 }
 
 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

Okay. Several things here. One, don't ever declare an individual char. char is a UTF-8 code unit, not a code point. And characters are code points. ASCII characters only require one UTF-8 code unit, so they can be held in a single char, but that's not true of characters in general. When dealing with individual characters, always use dchar. So, if you're using foreach for a string, use dchar as the iteration type. e.g. foreach(dchar c; str) {...} Youre code will be wrong if it iterates over char or wchar, since those aren't full characters. And because of that, _all_ strings are ranges of dchar, not char or wchar. So, the fact that you're using string instead of dstring with a range-based function like countUntil is irrelevant. You're still dealing with a range of dchars. So, isNumber should definitely be taking dchars, not chars. Two, don't pass 0 as a string. 0 is an int. _None_ of those countUntil calls shouldn't be compiling at all. It's actually a bit disturbing thath the first one compiles. It definitely looks like a bug. countUntil takes two ranges with the same element type. 0 is not a range, let alone a range of dchars. 0 shouldn't even really be used as a dchar, since 0 is an int, not a character. Third, you really shouldn't be using if statements like that. It looks like you don't know what you're doing if you do if(condition) return true; else return false; The condition is already a bool. You can simply do return condition; Plenty of newbie programmers make that mistake, and I don't know how experienced a programmer you are, but I'd advise you not to do that anymore. In any case, I'm a bit shocked that the first call to countUntil compiles, let alone works. That's quite disturbing actually. It looks like countUntil has a bug. However, your usage of countUntil here does imply that it could use an overload which takes a unary function and only one range.

Oh and by the way, isNumber isn't a delegate. It's a function. A delegate has access to its outer scope, which is what you get when you don't use static. - Jonathan M Davis
Aug 14 2011
prev sibling next sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 14, 2011 03:23:39 Jonathan M Davis wrote:
 On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,
 
 This program loops through a string until it finds a number and gives
 the position of it.
 
 The first assert works, but not the second one.
 
 import std.algorithm;
 
 void main() {
 
 	static bool isNumber( char input, char dummy ) {
 	
 		if ( ( input >= '0' && input <= '9' ) || input == '.' )
 		
 			return true;
 		
 		else
 		
 			return false;
 	
 	}
 	
 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 	
 		if ( ( input >= '0' && input <= '9' ) || input == '.' ) return true;
 
 else return false;
 
 		} )(str, 0) == 3 ); // works
 	
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 
 }
 
 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

Okay. Several things here. One, don't ever declare an individual char. char is a UTF-8 code unit, not a code point. And characters are code points. ASCII characters only require one UTF-8 code unit, so they can be held in a single char, but that's not true of characters in general. When dealing with individual characters, always use dchar. So, if you're using foreach for a string, use dchar as the iteration type. e.g. foreach(dchar c; str) {...} Youre code will be wrong if it iterates over char or wchar, since those aren't full characters. And because of that, _all_ strings are ranges of dchar, not char or wchar. So, the fact that you're using string instead of dstring with a range-based function like countUntil is irrelevant. You're still dealing with a range of dchars. So, isNumber should definitely be taking dchars, not chars. Two, don't pass 0 as a string. 0 is an int. _None_ of those countUntil calls shouldn't be compiling at all. It's actually a bit disturbing thath the first one compiles. It definitely looks like a bug. countUntil takes two ranges with the same element type. 0 is not a range, let alone a range of dchars. 0 shouldn't even really be used as a dchar, since 0 is an int, not a character. Third, you really shouldn't be using if statements like that. It looks like you don't know what you're doing if you do if(condition) return true; else return false; The condition is already a bool. You can simply do return condition; Plenty of newbie programmers make that mistake, and I don't know how experienced a programmer you are, but I'd advise you not to do that anymore. In any case, I'm a bit shocked that the first call to countUntil compiles, let alone works. That's quite disturbing actually. It looks like countUntil has a bug. However, your usage of countUntil here does imply that it could use an overload which takes a unary function and only one range.

Okay. countUntil is _supposed_ to be able to take a single value as its second argument. However, the names for the templated types implied that it took a range for its second value (it could take either a range or just an element, just so long as startsWith(haystack, needle) compiles). So, that may need some clarifying in the documentation. I misread it. In any case, if you change isNumber to two dchars, your code will work. The problem you're having is because a string is a range of dchars, not chars. But still, you probably shouldn't be passing 0. Apparently, the compiler is doing an implicit conversion from int to dchar to allow it to work, but it's generally better to not do that. - Jonathan M Davis
Aug 14 2011
parent Joel Christensen <joelcnz gmail.com> writes:
On 14-Aug-11 10:44 PM, Jonathan M Davis wrote:
 On Sunday, August 14, 2011 03:23:39 Jonathan M Davis wrote:
 On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,

 This program loops through a string until it finds a number and gives
 the position of it.

 The first assert works, but not the second one.

 import std.algorithm;

 void main() {

 	static bool isNumber( char input, char dummy ) {
 	
 		if ( ( input>= '0'&&  input<= '9' ) || input == '.' )
 		
 			return true;
 		
 		else
 		
 			return false;
 	
 	}
 	
 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 	
 		if ( ( input>= '0'&&  input<= '9' ) || input == '.' ) return true;

 else return false;

 		} )(str, 0) == 3 ); // works
 	
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );

 }

 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

Okay. Several things here. One, don't ever declare an individual char. char is a UTF-8 code unit, not a code point. And characters are code points. ASCII characters only require one UTF-8 code unit, so they can be held in a single char, but that's not true of characters in general. When dealing with individual characters, always use dchar. So, if you're using foreach for a string, use dchar as the iteration type. e.g. foreach(dchar c; str) {...} Youre code will be wrong if it iterates over char or wchar, since those aren't full characters. And because of that, _all_ strings are ranges of dchar, not char or wchar. So, the fact that you're using string instead of dstring with a range-based function like countUntil is irrelevant. You're still dealing with a range of dchars. So, isNumber should definitely be taking dchars, not chars. Two, don't pass 0 as a string. 0 is an int. _None_ of those countUntil calls shouldn't be compiling at all. It's actually a bit disturbing thath the first one compiles. It definitely looks like a bug. countUntil takes two ranges with the same element type. 0 is not a range, let alone a range of dchars. 0 shouldn't even really be used as a dchar, since 0 is an int, not a character. Third, you really shouldn't be using if statements like that. It looks like you don't know what you're doing if you do if(condition) return true; else return false; The condition is already a bool. You can simply do return condition; Plenty of newbie programmers make that mistake, and I don't know how experienced a programmer you are, but I'd advise you not to do that anymore. In any case, I'm a bit shocked that the first call to countUntil compiles, let alone works. That's quite disturbing actually. It looks like countUntil has a bug. However, your usage of countUntil here does imply that it could use an overload which takes a unary function and only one range.

Okay. countUntil is _supposed_ to be able to take a single value as its second argument. However, the names for the templated types implied that it took a range for its second value (it could take either a range or just an element, just so long as startsWith(haystack, needle) compiles). So, that may need some clarifying in the documentation. I misread it. In any case, if you change isNumber to two dchars, your code will work. The problem you're having is because a string is a range of dchars, not chars. But still, you probably shouldn't be passing 0. Apparently, the compiler is doing an implicit conversion from int to dchar to allow it to work, but it's generally better to not do that. - Jonathan M Davis

Hi, Thanks Jonathan for your help. I've taken the things you've said on board. I think I'm getting some where with D. I also mean to work more at C# too. So this works: import std.algorithm; bool isNumber( dchar chr, dchar dummy ) { return ( ( chr >= '0' && chr <= '9' ) || chr == '.' || chr == '-' || chr == '+' || chr == '"' ); } void fun() { dchar dummy = '\0'; auto indexEnd = countUntil!( isNumber )( input, dummy ); } - Joel
Aug 14 2011
prev sibling parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,
 
 This program loops through a string until it finds a number and gives
 the position of it.
 
 The first assert works, but not the second one.
 
 import std.algorithm;
 
 void main() {
 	static bool isNumber( char input, char dummy ) {
 		if ( ( input >= '0' && input <= '9' ) || input == '.' )
 			return true;
 		else
 			return false;
 	}
 
 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 		if ( ( input >= '0' && input <= '9' ) || input == '.' ) return true;
 else return false;
 		} )(str, 0) == 3 ); // works
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 }
 
 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

By the way, it looks like std.algorithm.count will do what you want to do (though you'll have to negate the predicate for it to work - either with std.functional.not or by changing it appropriately). - Jonathan M Davis
Aug 14 2011
parent reply Joel Christensen <joelcnz gmail.com> writes:
On 15-Aug-11 2:55 PM, Jonathan M Davis wrote:
 On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,

 This program loops through a string until it finds a number and gives
 the position of it.

 The first assert works, but not the second one.

 import std.algorithm;

 void main() {
 	static bool isNumber( char input, char dummy ) {
 		if ( ( input>= '0'&&  input<= '9' ) || input == '.' )
 			return true;
 		else
 			return false;
 	}

 	string str = "abc123";
 	assert( countUntil!( ( input, b ) {
 		if ( ( input>= '0'&&  input<= '9' ) || input == '.' ) return true;
 else return false;
 		} )(str, 0) == 3 ); // works
 	assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 }

 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

By the way, it looks like std.algorithm.count will do what you want to do (though you'll have to negate the predicate for it to work - either with std.functional.not or by changing it appropriately). - Jonathan M Davis

Ok, cool. I think this is nice: immutable isNum = `a >= '0' && a <= '9' && a != '"'`; auto input = "abc123"; auto indexEnd = count!( not!isNum )( input ); assert( indexEnd == 3 ); - Joel
Aug 14 2011
parent reply Joel Christensen <joelcnz gmail.com> writes:
On 15-Aug-11 5:21 PM, Joel Christensen wrote:
 On 15-Aug-11 2:55 PM, Jonathan M Davis wrote:
 On Sunday, August 14, 2011 20:50:03 Joel Christensen wrote:
 Hi,

 This program loops through a string until it finds a number and gives
 the position of it.

 The first assert works, but not the second one.

 import std.algorithm;

 void main() {
 static bool isNumber( char input, char dummy ) {
 if ( ( input>= '0'&& input<= '9' ) || input == '.' )
 return true;
 else
 return false;
 }

 string str = "abc123";
 assert( countUntil!( ( input, b ) {
 if ( ( input>= '0'&& input<= '9' ) || input == '.' ) return true;
 else return false;
 } )(str, 0) == 3 ); // works
 assert( countUntil!( isNumber, string, string )( str, 0 ) == 3 );
 }

 This is the error:
 parse.d(15): Error: template instance
 countUntil!(isNumber,string,string) does not match template declaration
 countUntil(alias pred = "a == b",R1,R2) if
 (is(typeof(startsWith!(pred)(haystack,needle))))

By the way, it looks like std.algorithm.count will do what you want to do (though you'll have to negate the predicate for it to work - either with std.functional.not or by changing it appropriately). - Jonathan M Davis

Ok, cool. I think this is nice: immutable isNum = `a >= '0' && a <= '9' && a != '"'`; auto input = "abc123"; auto indexEnd = count!( not!isNum )( input ); assert( indexEnd == 3 ); - Joel

Oops, should be. -- immutable isNum = `( a >= '0' && a <= '9' ) || a == '.'`; But that's the idea any way. Also forgot to have the variable 'input' declared in a post. - Joel
Aug 14 2011
next sibling parent reply Joel Christensen <joelcnz gmail.com> writes:
Ok, this is a good one I think.

import std.string, std.algorithm, std.functional;

bool isANum( dchar chr ) {
         return inPattern( chr, digits ~ `"+-.` );
}

void main() {
     auto input = `abc123`;
     auto indexEnd = -1;

     indexEnd = count!( not!isANum )( input );
     assert( indexEnd == 3 );
}
Aug 15 2011
parent reply "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, August 15, 2011 14:28 Jonathan M Davis wrote:
 On Monday, August 15, 2011 02:25 Joel Christensen wrote:
 Ok, this is a good one I think.
 
 import std.string, std.algorithm, std.functional;
 
 bool isANum( dchar chr ) {
 return inPattern( chr, digits ~ `"+-.` );
 }
 
 void main() {
 auto input = `abc123`;
 auto indexEnd = -1;
 
 indexEnd = count!( not!isANum )( input );
 assert( indexEnd == 3 );
 }

Actually, it looks like count counts it for the whole range, not just how many before it finds one which doesn't match. So, it's not quite what you were looking for. I misread what it did.

The next release will have a version of countUntil that does what you want though. - Jonathan M Davis
Aug 15 2011
parent Joel Christensen <joelcnz gmail.com> writes:
On 16-Aug-11 10:22 AM, Jonathan M Davis wrote:
 On Monday, August 15, 2011 14:28 Jonathan M Davis wrote:
 On Monday, August 15, 2011 02:25 Joel Christensen wrote:
 Ok, this is a good one I think.

 import std.string, std.algorithm, std.functional;

 bool isANum( dchar chr ) {
 return inPattern( chr, digits ~ `"+-.` );
 }

 void main() {
 auto input = `abc123`;
 auto indexEnd = -1;

 indexEnd = count!( not!isANum )( input );
 assert( indexEnd == 3 );
 }

Actually, it looks like count counts it for the whole range, not just how many before it finds one which doesn't match. So, it's not quite what you were looking for. I misread what it did.

The next release will have a version of countUntil that does what you want though. - Jonathan M Davis

Ok, good. Thanks Jonathan. - Joel
Aug 15 2011
prev sibling parent "Jonathan M Davis" <jmdavisProg gmx.com> writes:
On Monday, August 15, 2011 02:25 Joel Christensen wrote:
 Ok, this is a good one I think.
 
 import std.string, std.algorithm, std.functional;
 
 bool isANum( dchar chr ) {
 return inPattern( chr, digits ~ `"+-.` );
 }
 
 void main() {
 auto input = `abc123`;
 auto indexEnd = -1;
 
 indexEnd = count!( not!isANum )( input );
 assert( indexEnd == 3 );
 }

Actually, it looks like count counts it for the whole range, not just how many before it finds one which doesn't match. So, it's not quite what you were looking for. I misread what it did. - Jonathan M Davis
Aug 15 2011