digitalmars.D.learn - Choice ranges?
- H. S. Teoh (20/20) Mar 28 2014 Today I ran into an interesting situation where I have a function f that
- Meta (3/26) Mar 28 2014 You could try using std.variant.Algebraic. I've used it
- bearophile (5/6) Mar 28 2014 One option is to wrap those ranges in classes. See std.range for
- =?UTF-8?B?QWxpIMOHZWhyZWxp?= (13/17) Mar 28 2014 Link:
- Timon Gehr (66/84) Mar 29 2014 The following is as close as I got. I think the definite initialization
- H. S. Teoh (10/32) Mar 29 2014 [...]
Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types): auto f(A...)(A args) { ... if (someCondition) return cartesianProduct(x, y) .joiner; else return cartesianProduct(x, y) .joiner .filter!someFilter; } This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical. So how would I implement something like this? T -- The fact that anyone still uses AOL shows that even the presence of options doesn't stop some people from picking the pessimal one. - Mike Ellis
Mar 28 2014
On Friday, 28 March 2014 at 19:02:48 UTC, H. S. Teoh wrote:Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types): auto f(A...)(A args) { ... if (someCondition) return cartesianProduct(x, y) .joiner; else return cartesianProduct(x, y) .joiner .filter!someFilter; } This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical. So how would I implement something like this? TYou could try using std.variant.Algebraic. I've used it successfully before, but it's a bit clumsy and out of date.
Mar 28 2014
H. S. Teoh:So how would I implement something like this?One option is to wrap those ranges in classes. See std.range for the adapters. (I have not used them yet). Bye, bearophile
Mar 28 2014
On 03/28/2014 01:46 PM, bearophile wrote:H. S. Teoh:Link: Short examples here as well under "Run-time polymorphism with inputRangeObject() and outputRangeObject()": http://ddili.org/ders/d.en/ranges_more.html <quote> inputRangeObject() is flexible enough to support all of the non-output ranges: InputRange, ForwardRange, BidirectionalRange, and RandomAccessRange. Because of that flexibility, the object that it returns cannot be defined by auto. </quote> AliSo how would I implement something like this?One option is to wrap those ranges in classes. See std.range for the adapters. (I have not used them yet).
Mar 28 2014
On 03/28/2014 08:00 PM, H. S. Teoh wrote:Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types): auto f(A...)(A args) { ... if (someCondition) return cartesianProduct(x, y) .joiner; else return cartesianProduct(x, y) .joiner .filter!someFilter; } This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical. So how would I implement something like this? TThe following is as close as I got. I think the definite initialization checks DMD implements are horribly broken for union fields. import std.range, std.algorithm, std.typetuple, std.traits; template CommonElementType(T...)if(allSatisfy!(isInputRange,T)){ alias CommonElementType = CommonType!(staticMap!(ElementType,T)); } private template Neg(alias a){ enum Neg(T...)=!a!T; } struct SumRange(T...)if(allSatisfy!(isInputRange,T)&&!is(void==CommonElementType!T)&&allSatisfy!(Neg!hasElaborateDestructor,T)&&allSatisfy!(Neg!hasElaborateCopyConstructor,T)){ size_t tag; private union{ T rs=void; } // private this(); property front() trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].front; default: assert(0); } } property bool empty() trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].empty; default: assert(0); } } void popFront() trusted{ switch(tag){ foreach(i,_;T) case i: return rs[i].popFront(); default: assert(0); } } } private T buildSum(T, size_t tag,S)(S arg) trusted{ T r; r.tag=tag; r.rs[tag]=arg; return r; } auto inl(T,S)(S arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),0)(arg); } auto inr(S,T)(T arg)if(!hasElaborateDestructor!S&&!hasElaborateDestructor!T&&!hasElaborateCopyConstructor!S&&!hasElaborateCopyConstructor!T){ return buildSum!(SumRange!(S,T),1)(arg); } auto f(R,S)(bool condition,R x,S y){ auto r1(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner; } auto r2(){ return cartesianProduct(x, y).map!(a=>[a.expand]) .joiner .filter!(a=>a>2); } if(condition) return r1().inl!(typeof(r2())); else return r2().inr!(typeof(r1())); } void main(){ import std.stdio; writeln(f(true, [1,2,3], [4,5,6])); writeln(f(false, [1,2,3], [4,5,6])); }
Mar 29 2014
On 03/28/2014 08:00 PM, H. S. Teoh wrote:[...] Well, eventually I settled on using inputRangeObject() from std.range. While not the most performant (f would have to return InputRangeObject interface, which adds indirection), it was simplest to use and didn't require excessively ugly code. If this part of the code turns out to be a bottleneck, I'll rethink this decision, but for now it works nicely. :) T -- The easy way is the wrong way, and the hard way is the stupid way. Pick one.Today I ran into an interesting situation where I have a function f that needs to return ranges of different types (but identical element types): auto f(A...)(A args) { ... if (someCondition) return cartesianProduct(x, y) .joiner; else return cartesianProduct(x, y) .joiner .filter!someFilter; } This obviously can't compile, because the return types are not the same. (Note that someCondition is only known at runtime.) But abstractly speaking, it *should* work, because the element type of the returned range is identical. So how would I implement something like this?
Mar 29 2014