www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - foreach and filter

reply Russel Winder <russel winder.org.uk> writes:
Doing something along the lines of:

	const a =3D array ( filter! ... ) ;
	foreach ( i ; a ) { ... }

works fine.  Question 1 though is why I can't use immutable here, why I
have to use const.  Question 2 is why I can't do:

	const a =3D filter! ... ;
	foreach ( i ; a ) { ... }

if I try this I get messages along the lines of:

./signatures_sequential.d(33): Error: function signatures_sequential.main.f=
ilter!(delegate  system bool(string item)
{
return isDir(cast(const(char[]))item);
}
).filter!(const(immutable(char)[])[]).filter.Result.empty () is not callabl=
e using argument types ()
./signatures_sequential.d(33): Error: function signatures_sequential.main.f=
ilter!(delegate  system bool(string item)
{
return isDir(cast(const(char[]))item);
}
).filter!(const(immutable(char)[])[]).filter.Result.popFront () is not call=
able using argument types ()
./signatures_sequential.d(33): Error: function signatures_sequential.main.f=
ilter!(delegate  system bool(string item)
{
return isDir(cast(const(char[]))item);
}
).filter!(const(immutable(char)[])[]).filter.Result.front () is not callabl=
e using argument types ()

which, it has to be said, isn't exactly informative to the user.

Thanks.

--=20
Russel.
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D
Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder ekiga.n=
et
41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel winder.org.uk
London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder
Apr 11 2012
next sibling parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Wednesday, 11 April 2012 at 16:08:25 UTC, Russel Winder wrote:
 Doing something along the lines of:

 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }

 works fine.  Question 1 though is why I can't use immutable 
 here, why I
 have to use const.
An array/slice has indirection, you can't implicitly convert it to immutable. (IIRC, there is actually an exception for the return type of strongly pure functions, but your instantiation of 'array' is evidently not pure enough)
 Question 2 is why I can't do:

 	const a = filter! ... ;
 	foreach ( i ; a ) { ... }

 if I try this I get messages along the lines of:

 ./signatures_sequential.d(33): Error: function 
 signatures_sequential.main.filter!(delegate  system bool(string 
 item)
 {
 return isDir(cast(const(char[]))item);
 }
 ).filter!(const(immutable(char)[])[]).filter.Result.empty () is 
 not callable using argument types ()
 ./signatures_sequential.d(33): Error: function 
 signatures_sequential.main.filter!(delegate  system bool(string 
 item)
 {
 return isDir(cast(const(char[]))item);
 }
 ).filter!(const(immutable(char)[])[]).filter.Result.popFront () 
 is not callable using argument types ()
 ./signatures_sequential.d(33): Error: function 
 signatures_sequential.main.filter!(delegate  system bool(string 
 item)
 {
 return isDir(cast(const(char[]))item);
 }
 ).filter!(const(immutable(char)[])[]).filter.Result.front () is 
 not callable using argument types ()

 which, it has to be said, isn't exactly informative to the user.
Ranges are iterated in-place. You can't mutate a const range, hence you cannot advance it by one (`popFront`), which is required by the lowering of foreach using the range interface.
 Thanks.
You should be using the D.learn group for these questions.
Apr 11 2012
parent reply Russel Winder <russel winder.org.uk> writes:
On Wed, 2012-04-11 at 18:32 +0200, Jakob Ovrum wrote:
[...]
 Ranges are iterated in-place. You can't mutate a const range,=20
 hence you cannot advance it by one (`popFront`), which is=20
 required by the lowering of foreach using the range interface.
[...] I think I am still trying to recover from the shock of this; it is very likely to turn anyone interested in any form of declarative expression away from D. Also the internal activity is being exposed at the API level. Not to mention the history of iteration being one of working with mutable object on immutable structures. Trying to create the smallest possible example: auto r =3D iota ( 0 , 10 ) ; writeln ( map ! ( i =3D> i * i ) ( r ) ) ; works fine. Let us try: const r =3D iota ( 0 , 10 ) ; writeln ( map ! ( i =3D> i * i ) ( r ) ) ; works fine. Great. Now=20 auto r =3D iota ( 0 , 10 ) ; writeln ( reduce ! ( ( a, b ) =3D> a + b ) ( 10 , r ) ) ; works fine. Let's try: const r =3D iota ( 0 , 10 ) ; writeln ( reduce ! ( ( a, b ) =3D> a + b ) ( 10 , r ) ) ; Oh dear: /home/users/russel/lib.Linux.x86_64/DMD2/bin64/../../src/phobos/std/algorit= hm.d(725): Error: function std.range.iota!(int,int).iota.Result.popFront ()= is not callable using argument types () /home/users/russel/lib.Linux.x86_64/DMD2/bin64/../../src/phobos/std/algorit= hm.d(725): Error: function std.range.iota!(int,int).iota.Result.front () is= not callable using argument types () example.d(7): Error: template instance example.main.reduce!(__lambda3).redu= ce!(int,const(Result)) error instantiating Not only is the error message incomprehensible to someone who doesn't know the details of the internal workings (OK not a killer blow), but the very inconsistency of behaviour between map and reduce is a violation of the Principle of Least Surprise, and seems like a killer blow. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Apr 16 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/16/2012 01:20 PM, Russel Winder wrote:
 On Wed, 2012-04-11 at 18:32 +0200, Jakob Ovrum wrote:
 [...]
 Ranges are iterated in-place. You can't mutate a const range,
 hence you cannot advance it by one (`popFront`), which is
 required by the lowering of foreach using the range interface.
[...] I think I am still trying to recover from the shock of this; it is very likely to turn anyone interested in any form of declarative expression away from D. Also the internal activity is being exposed at the API level. Not to mention the history of iteration being one of working with mutable object on immutable structures. Trying to create the smallest possible example: auto r = iota ( 0 , 10 ) ; writeln ( map ! ( i => i * i ) ( r ) ) ; works fine. Let us try: const r = iota ( 0 , 10 ) ; writeln ( map ! ( i => i * i ) ( r ) ) ; works fine. Great. Now auto r = iota ( 0 , 10 ) ; writeln ( reduce ! ( ( a, b ) => a + b ) ( 10 , r ) ) ; works fine. Let's try: const r = iota ( 0 , 10 ) ; writeln ( reduce ! ( ( a, b ) => a + b ) ( 10 , r ) ) ; Oh dear: /home/users/russel/lib.Linux.x86_64/DMD2/bin64/../../src/phobos/s d/algorithm.d(725): Error: function std.range.iota!(int,int).iota.Result.popFront () is not callable using argument types () /home/users/russel/lib.Linux.x86_64/DMD2/bin64/../../src/phobos/s d/algorithm.d(725): Error: function std.range.iota!(int,int).iota.Result.front () is not callable using argument types () example.d(7): Error: template instance example.main.reduce!(__lambda3).reduce!(int,const(Result)) error instantiating Not only is the error message incomprehensible to someone who doesn't know the details of the internal workings (OK not a killer blow), but the very inconsistency of behaviour between map and reduce is a violation of the Principle of Least Surprise, and seems like a killer blow.
Have you filed a bug report against Phobos for this?
Apr 16 2012
parent Russel Winder <russel winder.org.uk> writes:
On Mon, 2012-04-16 at 14:58 +0200, Timon Gehr wrote:
[...]
 Have you filed a bug report against Phobos for this?
Not as yet, after lunch 'twill be done. --=20 Russel. =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D Dr Russel Winder t: +44 20 7585 2200 voip: sip:russel.winder ekiga.n= et 41 Buckmaster Road m: +44 7770 465 077 xmpp: russel winder.org.uk London SW11 1EN, UK w: www.russel.org.uk skype: russel_winder
Apr 16 2012
prev sibling next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
On Wed, 11 Apr 2012 18:08:14 +0200, Russel Winder <russel winder.org.uk>  
wrote:

 Doing something along the lines of:

 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }

 works fine.  Question 1 though is why I can't use immutable here, why I
 have to use const.  Question 2 is why I can't do:

 	const a = filter! ... ;
 	foreach ( i ; a ) { ... }
popFront cannot be const. I have (long ago, probably not usable in this day and age), written an implementation of tail const for ranges, but it is invasive[1]. For now, the solution is simply to not use const/immutable with ranges other than arrays. Some solution really should be created for this problem. One simple solution would be for all ranges to support opSlice with an empty parameter list, which would return a non-const version of the range. The problems are: 1. The elements should still be const. 2. If this range wraps another range, that other range should also be sliced, and so on. [1]http://d.puremagic.com/issues/show_bug.cgi?id=5377
Apr 11 2012
parent reply "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Wednesday, 11 April 2012 at 16:33:42 UTC, Simen Kjaeraas wrote:
 On Wed, 11 Apr 2012 18:08:14 +0200, Russel Winder 
 <russel winder.org.uk> wrote:

 Doing something along the lines of:

 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }

 works fine.  Question 1 though is why I can't use immutable 
 here, why I
 have to use const.  Question 2 is why I can't do:

 	const a = filter! ... ;
 	foreach ( i ; a ) { ... }
immutable.
Value types with no indirection are implicitly convertible to immutable. ----------- void main() { int a = 2; immutable int b = a; } -----------
Apr 11 2012
parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jakob Ovrum:

 Value types with no indirection are implicitly convertible to 
 immutable.

 -----------
 void main()
 {
     int a = 2;
     immutable int b = a;
 }
 -----------
And far more, even with immutable reference types, in this program 'a' has to be immutable, no just const: int[] foo(immutable int[] a) pure { return a.dup; } void main() { immutable b = foo([1, 2]); } There is the desire to extend this idea a bit more, I think Hara has something on this. Bye, bearophile
Apr 11 2012
parent "Jakob Ovrum" <jakobovrum gmail.com> writes:
On Wednesday, 11 April 2012 at 17:00:43 UTC, bearophile wrote:
 Jakob Ovrum:

 Value types with no indirection are implicitly convertible to 
 immutable.

 -----------
 void main()
 {
    int a = 2;
    immutable int b = a;
 }
 -----------
And far more, even with immutable reference types, in this program 'a' has to be immutable, no just const: -snip-
I mentioned this as a side-note in my other reply in the thread. It's a truly neat feature which I feel has much potential, I hope to see some compelling use-cases with standard library functions in the future as Phobos becomes more pure-correct. If the parameter to `array` in the original problem had presented a pure interface, he should have been able to get an immutable result like he tried initially thanks to this feature and pure inference, which is exciting to think about. Of course, it's useless in this particular case as his parameter to `array` cannot have a pure interface (it's lazily evaluated, right?), and secondly, an immutable range is not usable with foreach.
Apr 11 2012
prev sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/11/2012 06:08 PM, Russel Winder wrote:
 Doing something along the lines of:

 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }

 works fine.  Question 1 though is why I can't use immutable here, why I
 have to use const.
'array' is not pure for some reason. This should be fixed.
  Question 2 is why I can't do:

 	const a = filter! ... ;
 	foreach ( i ; a ) { ... }
popFront cannot be const. (And Phobos is not very const correct anyways). You can try auto a = filter!foo(cast(const)data); foreach( i ; a ) { ... } (Assuming data is a built-in array slice)
Apr 12 2012
next sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 12 Apr 2012 13:44:36 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/11/2012 06:08 PM, Russel Winder wrote:
 Doing something along the lines of:

 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }

 works fine.  Question 1 though is why I can't use immutable here, why I
 have to use const.
'array' is not pure for some reason. This should be fixed.
It's implied pure if filter is pure. Templates are auto-pure if all the functions they call are pure. array should not be specifically marked pure. This may be what you meant (i.e. it's not being implied as pure), but I want to be clear what it *should* be. -Steve
Apr 12 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/12/2012 08:08 PM, Steven Schveighoffer wrote:
 On Thu, 12 Apr 2012 13:44:36 -0400, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 04/11/2012 06:08 PM, Russel Winder wrote:
 Doing something along the lines of:

 const a = array ( filter! ... ) ;
 foreach ( i ; a ) { ... }

 works fine. Question 1 though is why I can't use immutable here, why I
 have to use const.
'array' is not pure for some reason. This should be fixed.
It's implied pure if filter is pure. Templates are auto-pure if all the functions they call are pure. array should not be specifically marked pure. This may be what you meant (i.e. it's not being implied as pure), but I want to be clear what it *should* be. -Steve
Yes, that is what I meant.
Apr 12 2012
prev sibling parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Thursday, April 12, 2012 19:44:36 Timon Gehr wrote:
 On 04/11/2012 06:08 PM, Russel Winder wrote:
 Doing something along the lines of:
 	const a = array ( filter! ... ) ;
 	foreach ( i ; a ) { ... }
 
 works fine.  Question 1 though is why I can't use immutable here, why I
 have to use const.
'array' is not pure for some reason. This should be fixed.
Probably a result of various array-related stuff which should be pure but isn't (e.g. Appender and some of what's in object_.d), but I'd have to go dig through the implementation to see. We have some pull requests though that should improve that situation for 2.060, and a number of them _must_ be sorted out for 2.060, because we're looking at making toString pure, and too many string-related functions (particularly format, text, and to) can't be pure yet for that to work. - Jonathan M Davis
Apr 12 2012