digitalmars.D.learn - Polymorphic ranges?
- Andrej Mitrovic (21/21) Apr 30 2011 As an example I have a cyclic buffer (using std.range.Cycle) where I can...
- Dmitry Olshansky (6/27) May 01 2011 There is a polymorphic wrapper for any range in std.range, try
- Andrej Mitrovic (8/8) May 01 2011 I'm not sure how to use those wrappers though. Maybe I'm just doing it w...
- Dmitry Olshansky (7/15) May 01 2011 Well, this compiles, you just need to pick suitable type of range
- Andrej Mitrovic (6/6) May 01 2011 Yeah it seems a common interface is what I should have used. I've
- =?ISO-8859-1?Q?Ali_=C7ehreli?= (53/59) May 01 2011 To make it more convenient to others, I paste Andrej Mitrovic's code:
- Andrej Mitrovic (3/3) May 01 2011 The reason I've posted them online is because they snippets are not
- Andrej Mitrovic (1/1) May 01 2011 s/they/the
- Andrej Mitrovic (5/5) May 01 2011 Unfortunately as you can see I can't convert a Stride to a
- Andrej Mitrovic (4/4) May 01 2011 Actually that design of mine was bad because it creates a long chain
- Andrej Mitrovic (8/8) May 01 2011 Btw,
- Dmitry Olshansky (6/14) May 01 2011 One reason might be is that it was implemented under worse compiler
- Andrej Mitrovic (3/3) May 01 2011 opSlice isn't supported either. Gah.., so much for this being useful.
- =?ISO-8859-1?Q?Ali_=C7ehreli?= (30/47) May 01 2011 To make it more convenient to other, I paste Dmitry Olshansky's code:
- =?ISO-8859-1?Q?Ali_=C7ehreli?= (29/37) May 01 2011 To make it more convenient to others, I paste Andrej Mitrovic's code:
As an example I have a cyclic buffer (using std.range.Cycle) where I can set the lower and upper bounds of the buffer. I'd also like to enable a stepping mode, so I thought first about using std.range.Stride. The code: http://codepad.org/TR7NDWTC This line is commented out: //~ buffer = stride(buffer, newStep); Obviously I can't assign a Stride structure to a Cycle structure. Structures aren't polymorphic. The idea was that the private _buffer could be traversed in different ways, and the Work structure would allow reconfiguration on how the public "buffer" walks through the private _buffer array, this would be done at runtime via function calls like "setStep" which changes the buffer type. But this isn't possible since buffer can only be one type, since it's a structure. So the question is, how can I use std.range and its various types polymorphically, is that in any way possible? From what I can tell std.range functions all return structs. I was hoping of being able to do something like: class Work { float[256] _buffer; InfiniteRange buffer; this() { buffer = new InfiniteRange(_buffer); } // initialize void setStride() { buffer = new Stride(buffer); // now buffer has a dynamic type of Stride, which would be a subtype of InfiniteRange } } And then main would create a Work object, and call its buffer.front and buffer.popFront properties, and later call setStride to change how the object behaves by simply creating a new subtype which has the same interface but different behavior. But I can't do that here since pretty much everything in std.range returns a struct.
Apr 30 2011
On 01.05.2011 6:33, Andrej Mitrovic wrote:As an example I have a cyclic buffer (using std.range.Cycle) where I can set the lower and upper bounds of the buffer. I'd also like to enable a stepping mode, so I thought first about using std.range.Stride. The code: http://codepad.org/TR7NDWTC This line is commented out: //~ buffer = stride(buffer, newStep); Obviously I can't assign a Stride structure to a Cycle structure. Structures aren't polymorphic. The idea was that the private _buffer could be traversed in different ways, and the Work structure would allow reconfiguration on how the public "buffer" walks through the private _buffer array, this would be done at runtime via function calls like "setStep" which changes the buffer type. But this isn't possible since buffer can only be one type, since it's a structure. So the question is, how can I use std.range and its various types polymorphically, is that in any way possible? From what I can tell std.range functions all return structs. I was hoping of being able to do something like: class Work { float[256] _buffer; InfiniteRange buffer; this() { buffer = new InfiniteRange(_buffer); } // initialize void setStride() { buffer = new Stride(buffer); // now buffer has a dynamic type of Stride, which would be a subtype of InfiniteRange } } And then main would create a Work object, and call its buffer.front and buffer.popFront properties, and later call setStride to change how the object behaves by simply creating a new subtype which has the same interface but different behavior. But I can't do that here since pretty much everything in std.range returns a struct.There is a polymorphic wrapper for any range in std.range, try inputRangeObject & outputRangeObject. Every such range object is derived from the most suitable interface InputRange, ForwardRange etc. -- Dmitry Olshansky
May 01 2011
I'm not sure how to use those wrappers though. Maybe I'm just doing it wrong: http://codepad.org/eHIdhasc But it seems these wrappers have some problems, the docs say about the interfaces: Limitations: These interfaces are not capable of forwarding ref access to elements. Infiniteness of the wrapped range is not propagated. Length is not propagated in the case of non-random access ranges.
May 01 2011
On 01.05.2011 18:30, Andrej Mitrovic wrote:I'm not sure how to use those wrappers though. Maybe I'm just doing it wrong: http://codepad.org/eHIdhasc But it seems these wrappers have some problems, the docs say about the interfaces: Limitations: These interfaces are not capable of forwarding ref access to elements. Infiniteness of the wrapped range is not propagated. Length is not propagated in the case of non-random access ranges.Well, this compiles, you just need to pick suitable type of range 'interface', that's the subtle thingie: http://codepad.org/uE0nIwbk Limitations are caused by bug, that is going to get fixed eventually ;) -- Dmitry Olshansky
May 01 2011
Yeah it seems a common interface is what I should have used. I've tried it in numerous ways but I got the interface type wrong apparently. Thanks Dmitry. Here's a quick example: http://codepad.org/RhNiUHU2 I hope those bugs get squashed so I can have more fun with these ranges. :)
May 01 2011
On 05/01/2011 09:09 AM, Andrej Mitrovic wrote:Yeah it seems a common interface is what I should have used. I've tried it in numerous ways but I got the interface type wrong apparently. Thanks Dmitry. Here's a quick example: http://codepad.org/RhNiUHU2To make it more convenient to others, I paste Andrej Mitrovic's code: module cyclicBuffer; import std.stdio; import std.range; import core.thread; import std.random; enum BufferSize = 10; struct Work { private float[BufferSize] _buffer; InputRange!(float) buffer; this(T)(T unused) { _buffer[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; buffer = inputRangeObject(cycle(_buffer[])); } void setNewRange(size_t min, size_t max) { buffer = inputRangeObject(cycle(_buffer[min..max])); } void setStep(size_t newStep) { buffer = inputRangeObject(stride(buffer, newStep)); } } void main() { writeln(); auto work = Work(1); size_t count; int min; int max; size_t step; while (!work.buffer.empty) { write(work.buffer.front); stdout.flush(); work.buffer.popFront; if (++count == 20) { min = uniform(0, BufferSize / 2); max = uniform(BufferSize / 2, BufferSize); step = uniform(1, 5); work.setNewRange(min, max); work.setStep(step); writefln("\nmin: %s, max: %s, step: %s", min, max-1, step); count = 0; } Thread.sleep( dur!("msecs")(100) ); } }I hope those bugs get squashed so I can have more fun with these ranges. :)Ali
May 01 2011
The reason I've posted them online is because they snippets are not that short. And it's much easier to read them from a syntax-highlighted website than from a plaintext newsgroup reader.
May 01 2011
Unfortunately as you can see I can't convert a Stride to a RandomAccessInfinite object, so I've had to use an InputRange interface (I can also use ForwardRange which is more derived). I'm not sure why I can't use it (maybe it's that bug again?), because Stride itself does offer random access.
May 01 2011
Actually that design of mine was bad because it creates a long chain of virtual calls since setStep just wraps the buffer object and creates a new object every time. Here's an alternate implementation: https://gist.github.com/950647
May 01 2011
Btw, * Limitations: * * These interfaces are not capable of forwarding $(D ref) access to elements. Why not? I can use auto ref to make e.g. an input range interface that can return ref elements: http://codepad.org/kmenIDk7 Why aren't the interfaces defined like that in std.range?
May 01 2011
On 01.05.2011 21:40, Andrej Mitrovic wrote:Btw, * Limitations: * * These interfaces are not capable of forwarding $(D ref) access to elements. Why not? I can use auto ref to make e.g. an input range interface that can return ref elements: http://codepad.org/kmenIDk7 Why aren't the interfaces defined like that in std.range?One reason might be is that it was implemented under worse compiler condition ;) Seems worthy of a bug report, or better yet a pull request. -- Dmitry Olshansky
May 01 2011
opSlice isn't supported either. Gah.., so much for this being useful. I'll have to roll my own. Now I know why Tango was developed. <g>
May 01 2011
On 05/01/2011 08:04 AM, Dmitry Olshansky wrote:On 01.05.2011 18:30, Andrej Mitrovic wrote:To make it more convenient to other, I paste Dmitry Olshansky's code: import std.stdio; import std.range; import core.thread; import std.random; enum BufferSize = 10; struct Work { private float[BufferSize] _buffer; RandomAccessInfinite!(float) buffer; this(T)(T unused) { _buffer[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; buffer = inputRangeObject(cycle(_buffer[])); } void setNewRange(size_t min, size_t max) { buffer = inputRangeObject(cycle(_buffer[min..max])); } } void main(){} I also paste the compilation output: Line 6: enum declaration is invalid Line 6: Declaration expected, not '=' Line 13: semicolon expected following function declaration Line 13: Declaration expected, not '(' Line 17: no identifier for declarator buffer Line 24: unrecognized declarationI'm not sure how to use those wrappers though. Maybe I'm just doing it wrong: http://codepad.org/eHIdhasc But it seems these wrappers have some problems, the docs say about the interfaces: Limitations: These interfaces are not capable of forwarding ref access to elements. Infiniteness of the wrapped range is not propagated. Length is not propagated in the case of non-random access ranges.Well, this compiles, you just need to pick suitable type of range 'interface', that's the subtle thingie: http://codepad.org/uE0nIwbkLimitations are caused by bug, that is going to get fixed eventually ;)Ali
May 01 2011
On 05/01/2011 07:30 AM, Andrej Mitrovic wrote:I'm not sure how to use those wrappers though. Maybe I'm just doing it wrong: http://codepad.org/eHIdhascTo make it more convenient to others, I paste Andrej Mitrovic's code: import std.stdio; import std.range; import core.thread; import std.random; enum BufferSize = 10; struct Work { private float[BufferSize] _buffer; InputRangeObject!(float[]) buffer; this(T)(T unused) { _buffer[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; buffer = inputRangeObject(cycle(_buffer[])); } void setNewRange(size_t min, size_t max) { buffer = inputRangeObject(cycle(_buffer[min..max])); } } void main(){} /* Error: cannot implicitly convert expression (inputRangeObject(cycle(this._buffer[min..max]))) of type std.range.InputRangeObject!(Cycle!(float[])).InputRangeObject to std.range.InputRangeObject!(float[]).InputRangeObject */But it seems these wrappers have some problems, the docs say about the interfaces: Limitations: These interfaces are not capable of forwarding ref access to elements. Infiniteness of the wrapped range is not propagated. Length is not propagated in the case of non-random access ranges.Ali
May 01 2011