digitalmars.D.learn - Supporting and signature-checking all foreach variations
- Ashish Myles (40/40) Feb 25 2012 I want to define a general-purpose centroid computer for point container...
- =?ISO-8859-1?Q?Alex_R=F8nne_Petersen?= (4/44) Feb 25 2012 I think std.traits.isIterable(T) is what you want.
- Ashish Myles (11/19) Feb 25 2012 ach
- Dmitry Olshansky (5/45) Feb 25 2012 It's supposed to work.
- Jesse Phillips (7/26) Feb 25 2012 Is not implemented, not seeing a bug report
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (26/49) Feb 26 2012 supports this
- Ashish Myles (5/30) Feb 26 2012 Oh good to know. I had downgraded my dmd after some new CTFE bugs
I want to define a general-purpose centroid computer for point containers and ran into a couple of challenges. Firstly, here is the basic code Point3 computeCentroid(PointContainer)(const ref PointContainer C) if (...) // want a signature constraint for usability of foreach { Point3 c = Point3(0.0, 0.0, 0.0); size_t total = 0; foreach(Point3 p; C) { // enforce that the container supports this c += p; ++total; } if (total > 0) c /= cast(double)(total); return c; } I want to have the most generally-applicable version of this functionality (for const/immutable/etc containers supporting foreach in various ways), ideally without needing to write multiple versions of this function. 1. Since support for foreach can be added in many ways (with ref/non-ref/const variants), I wanted to check if there was any signature constraint that could check if the container supports foreach as above. I looked into the "compiles" traits, but that doesn't work for statements. For an opAssign version, I had tried if (is(typeof(C.opApply(delegate(const ref Point3) { return 1;})))) but this is unelegant because the container's opApply could have instead supplied delegate(Point3) or delegate(ref Point3) (although the latter would require me to not use a "const" on the parameter declaration). 2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments. However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature? 3. A more general question: Is there any by any chance a way to avoid the redundancy above of defining two opSlice() functions (or two opAssign() functions if I went that route -- one for const and another for ref)? I suspect that the answer is no, but I just wanted to verify.
Feb 25 2012
On 25-02-2012 17:25, Ashish Myles wrote:I want to define a general-purpose centroid computer for point containers and ran into a couple of challenges. Firstly, here is the basic code Point3 computeCentroid(PointContainer)(const ref PointContainer C) if (...) // want a signature constraint for usability of foreach { Point3 c = Point3(0.0, 0.0, 0.0); size_t total = 0; foreach(Point3 p; C) { // enforce that the container supports this c += p; ++total; } if (total> 0) c /= cast(double)(total); return c; } I want to have the most generally-applicable version of this functionality (for const/immutable/etc containers supporting foreach in various ways), ideally without needing to write multiple versions of this function. 1. Since support for foreach can be added in many ways (with ref/non-ref/const variants), I wanted to check if there was any signature constraint that could check if the container supports foreach as above. I looked into the "compiles" traits, but that doesn't work for statements. For an opAssign version, I had tried if (is(typeof(C.opApply(delegate(const ref Point3) { return 1;})))) but this is unelegant because the container's opApply could have instead supplied delegate(Point3) or delegate(ref Point3) (although the latter would require me to not use a "const" on the parameter declaration). 2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments. However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature? 3. A more general question: Is there any by any chance a way to avoid the redundancy above of defining two opSlice() functions (or two opAssign() functions if I went that route -- one for const and another for ref)? I suspect that the answer is no, but I just wanted to verify.I think std.traits.isIterable(T) is what you want. -- - Alex
Feb 25 2012
On Sat, Feb 25, 2012 at 11:37 AM, Alex R=F8nne Petersen <xtzgzorex gmail.com> wrote:On 25-02-2012 17:25, Ashish Myles wrote:ach1. Since support for foreach can be added in many ways (with =A0 ref/non-ref/const variants), I wanted to check if there was any =A0 signature constraint that could check if the container supports fore=for=A0 as above. I looked into the "compiles" traits, but that doesn't work=Great! Now that I know the answer to the first question, it is so easy to find the answer on google :P . Technically, I want something like isIterable(T,Point3); given the definition of isIterable, I can easily get this functionality. I am still looking for answers to the second question (which might indicate a bug in the frontend) and third question whose answer would be really enlightening if what I requested is possible.=A0 statements.I think std.traits.isIterable(T) is what you want.
Feb 25 2012
On 25.02.2012 20:25, Ashish Myles wrote:I want to define a general-purpose centroid computer for point containers and ran into a couple of challenges. Firstly, here is the basic code Point3 computeCentroid(PointContainer)(const ref PointContainer C) if (...) // want a signature constraint for usability of foreach { Point3 c = Point3(0.0, 0.0, 0.0); size_t total = 0; foreach(Point3 p; C) { // enforce that the container supports this c += p; ++total; } if (total> 0) c /= cast(double)(total); return c; } I want to have the most generally-applicable version of this functionality (for const/immutable/etc containers supporting foreach in various ways), ideally without needing to write multiple versions of this function. 1. Since support for foreach can be added in many ways (with ref/non-ref/const variants), I wanted to check if there was any signature constraint that could check if the container supports foreach as above. I looked into the "compiles" traits, but that doesn't work for statements. For an opAssign version, I had tried if (is(typeof(C.opApply(delegate(const ref Point3) { return 1;})))) but this is unelegant because the container's opApply could have instead supplied delegate(Point3) or delegate(ref Point3) (although the latter would require me to not use a "const" on the parameter declaration). 2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments. However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature?It's supposed to work. I think it's just not implemented yet.3. A more general question: Is there any by any chance a way to avoid the redundancy above of defining two opSlice() functions (or two opAssign() functions if I went that route -- one for const and another for ref)? I suspect that the answer is no, but I just wanted to verify.-- Dmitry Olshansky
Feb 25 2012
On Saturday, 25 February 2012 at 16:26:05 UTC, Ashish Myles wrote:2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments. However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature?Is not implemented, not seeing a bug report http://d.puremagic.com/issues/3. A more general question: Is there any by any chance a way to avoid the redundancy above of defining two opSlice() functions (or two opAssign() functions if I went that route -- one for const and another for ref)? I suspect that the answer is no, but I just wanted to verify.Not sure look into information on 'auto ref' and 'inout' these were built for removing duplications of const and ref functions. These have had some work done to make them functional, but could still have holes.
Feb 25 2012
On 02/25/2012 08:25 AM, Ashish Myles wrote:I want to define a general-purpose centroid computer for point containers and ran into a couple of challenges. Firstly, here is the basic code Point3 computeCentroid(PointContainer)(const ref PointContainer C) if (...) // want a signature constraint for usability offoreach{ Point3 c = Point3(0.0, 0.0, 0.0); size_t total = 0; foreach(Point3 p; C) { // enforce that the containersupports thisc += p; ++total; } if (total> 0) c /= cast(double)(total); return c; }...2. Secondly, TDPL on page 381 says that foreach iterates over C[], if C defines the opSlice() function without any arguments.Although what you describe also seems useful, that heading seems to be about ranges and specifically about the three InputRange functions. The feature has indeed been implemented recently: http://d.puremagic.com/issues/show_bug.cgi?id=5605However the code above doesn't seem to work and requires me to explicitly invoke the slice operator myself like foreach(p; C[]) { ... } when my data structure clearly defines the following functions. Point3[] opSlice() { return _cpts[]; } const (Point3)[] opSlice() const { return _cpts[]; } Is this a misunderstanding on my part or an unimplemented feature?But I've just verified that the following works with dmd 2.058: import std.stdio; struct Point3 {} struct MyCollection { Point3[] _cpts; Point3[] opSlice() { return _cpts; } // <-- _cpts[] works too const (Point3)[] opSlice() const { return _cpts; } } void main() { auto coll = MyCollection(); foreach (i; coll) { // ... } } Ali
Feb 26 2012
On Sun, Feb 26, 2012 at 5:25 AM, Ali =C7ehreli <acehreli yahoo.com> wrote:On 02/25/2012 08:25 AM, Ashish Myles wrote:?=A0 =A0However the code above doesn't seem to work and requires me to =A0 =A0explicitly invoke the slice operator myself like =A0 =A0 =A0foreach(p; C[]) { ... } =A0 =A0when my data structure clearly defines the following functions. =A0 =A0 =A0Point3[] opSlice() { return _cpts[]; } =A0 =A0 =A0const (Point3)[] opSlice() const { return _cpts[]; } =A0 =A0Is this a misunderstanding on my part or an unimplemented feature=But I've just verified that the following works with dmd 2.058: import std.stdio; struct Point3 {} struct MyCollection { =A0 =A0Point3[] _cpts; =A0 =A0Point3[] opSlice() { return _cpts; } =A0// <-- _cpts[] works too =A0 =A0const (Point3)[] opSlice() const { return _cpts; } } void main() { =A0 =A0auto coll =3D MyCollection(); =A0 =A0foreach (i; coll) { =A0 =A0 =A0 =A0// ... =A0 =A0} }Oh good to know. I had downgraded my dmd after some new CTFE bugs resulted in compilation errors on some of my code, and hadn't thought to check with the latest version.
Feb 26 2012