Thread overview | ||||||
---|---|---|---|---|---|---|
|
February 15, 2011 Array types not treated uniformly when passed as ranges | ||||
---|---|---|---|---|
| ||||
Hi all, Just curious as to the difference in the built-in variable length array vs. the std.container.Array and fixed length arrays when it comes to using them in functions that take Ranges. For instance the following does not compile: import std.algorithm; import std.stdio; import std.range; import std.conv; import std.container; import std.array; void main() { int[5] builtin_fixed; int[] builtin_variable; Array!(int) con_array; con_array.length(5); builtin_variable.length = 5; fill(builtin_variable, 9); //ok, no error isSorted(builtin_variable); //ditto //The following 4 statements produce errors fill(builtin_fixed, 9); fill(con_array, 9); isSorted(con_array); isSorted(builtin_fixed); } The errors are variations on: Error: template std.algorithm.fill(Range,Value) if (isForwardRange!(Range) && is(typeof(range.front = filler))) does not match any function template declaration Error: template std.algorithm.fill(Range,Value) if (isForwardRange!(Range) && is(typeof(range.front = filler))) cannot deduce template function from argument types !()(int[5LU],int) If I change those 4 statements to: fill(builtin_fixed[], 9); fill(con_array[], 9); isSorted(con_array[]); isSorted(builtin_fixed[]); effectively passing ranges (std.container.Array!(int).Array.Range in the case of con_array, and int[] for builtin_fixed) which then works as expected. This all makes sense, and it's easy enough to write wrappers, but I would (well and I did) expect the first way to just work. This may just be a nitpick I guess, but being new to the language this little detour involved quite a bit of time research (not a bad thing, I did learn quite a bit in the process), but makes me wonder if I am missing something fundamental regarding when I should be using these different array types. Cheers |
February 15, 2011 Re: Array types not treated uniformly when passed as ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to jam | On Mon, 14 Feb 2011 21:18:39 -0500, jam <gr0v3er@gmail.com> wrote:
> Hi all,
>
> Just curious as to the difference in the built-in variable length
> array vs. the std.container.Array and fixed length arrays when it
> comes to using them in functions that take Ranges.
>
> For instance the following does not compile:
>
> import std.algorithm;
> import std.stdio;
> import std.range;
> import std.conv;
> import std.container;
> import std.array;
>
> void main() {
>
> int[5] builtin_fixed;
> int[] builtin_variable;
> Array!(int) con_array;
>
> con_array.length(5);
> builtin_variable.length = 5;
>
> fill(builtin_variable, 9); //ok, no error
> isSorted(builtin_variable); //ditto
>
> //The following 4 statements produce errors
> fill(builtin_fixed, 9);
> fill(con_array, 9);
>
> isSorted(con_array);
> isSorted(builtin_fixed);
>
> }
>
> The errors are variations on:
>
> Error: template std.algorithm.fill(Range,Value) if
> (isForwardRange!(Range) && is(typeof(range.front = filler))) does not
> match any function template declaration
> Error: template std.algorithm.fill(Range,Value) if
> (isForwardRange!(Range) && is(typeof(range.front = filler))) cannot
> deduce template function from argument types !()(int[5LU],int)
>
> If I change those 4 statements to:
>
> fill(builtin_fixed[], 9);
> fill(con_array[], 9);
>
> isSorted(con_array[]);
> isSorted(builtin_fixed[]);
>
> effectively passing ranges (std.container.Array!(int).Array.Range in
> the case of con_array, and int[] for builtin_fixed) which then works
> as expected. This all makes sense, and it's easy enough to write
> wrappers, but I would (well and I did) expect the first way to just
> work. This may just be a nitpick I guess, but being new to the
> language this little detour involved quite a bit of time research (not
> a bad thing, I did learn quite a bit in the process), but makes me
> wonder if I am missing something fundamental regarding when I should
> be using these different array types.
This is because:
1. a fixed-sized array is not a range. It is passed by value, not by reference. The problem there is IFTI thinking you want to pass the fixed array as a fixed array and not as a slice.
2. a container is not a range. An Array is a container, so you must extract a range from it to use it in range-like activities.
The second point seems odd, since builtin arrays are ranges, but an Array is different because it's a true reference type (changing the length from one reference alters the length of another reference) and it "owns" the memory contained within, unlike a builtin array which just references the memory.
But it's also easy to consider other things. Consider a RedBlackTree container, should that be a range? What happens when you popFront?
-Steve
|
February 15, 2011 Re: Array types not treated uniformly when passed as ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Tue, 15 Feb 2011 09:00:54 -0500, Steven Schveighoffer wrote: > On Mon, 14 Feb 2011 21:18:39 -0500, jam <gr0v3er@gmail.com> wrote: > >> Hi all, >> >> Just curious as to the difference in the built-in variable length array vs. the std.container.Array and fixed length arrays when it comes to using them in functions that take Ranges. >> >> For instance the following does not compile: >> >> import std.algorithm; >> import std.stdio; >> import std.range; >> import std.conv; >> import std.container; >> import std.array; >> >> void main() { >> >> int[5] builtin_fixed; >> int[] builtin_variable; >> Array!(int) con_array; >> >> con_array.length(5); >> builtin_variable.length = 5; >> >> fill(builtin_variable, 9); //ok, no error >> isSorted(builtin_variable); //ditto >> >> //The following 4 statements produce errors fill(builtin_fixed, 9); >> fill(con_array, 9); >> >> isSorted(con_array); >> isSorted(builtin_fixed); >> >> } >> >> The errors are variations on: >> >> Error: template std.algorithm.fill(Range,Value) if >> (isForwardRange!(Range) && is(typeof(range.front = filler))) does not >> match any function template declaration Error: template >> std.algorithm.fill(Range,Value) if (isForwardRange!(Range) && >> is(typeof(range.front = filler))) cannot deduce template function from >> argument types !()(int[5LU],int) >> >> If I change those 4 statements to: >> >> fill(builtin_fixed[], 9); >> fill(con_array[], 9); >> >> isSorted(con_array[]); >> isSorted(builtin_fixed[]); >> >> effectively passing ranges (std.container.Array!(int).Array.Range in the case of con_array, and int[] for builtin_fixed) which then works as expected. This all makes sense, and it's easy enough to write wrappers, but I would (well and I did) expect the first way to just work. This may just be a nitpick I guess, but being new to the language this little detour involved quite a bit of time research (not a bad thing, I did learn quite a bit in the process), but makes me wonder if I am missing something fundamental regarding when I should be using these different array types. > > This is because: > > 1. a fixed-sized array is not a range. It is passed by value, not by reference. The problem there is IFTI thinking you want to pass the fixed array as a fixed array and not as a slice. 2. a container is not a range. An Array is a container, so you must extract a range from it to use it in range-like activities. > > The second point seems odd, since builtin arrays are ranges, but an Array is different because it's a true reference type (changing the length from one reference alters the length of another reference) and it "owns" the memory contained within, unlike a builtin array which just references the memory. > > > -Steve I'm glad I came to the same conclusions on my own after perusing the docs and src files some more. I still find it a bit odd that I'm not testing whether my data structure is sorted or not, but a full-length slice of the structure. Although, I guess when I really think about it, it's not that mechanically different than passing a pair of iterators. > But it's also easy to consider other things. Consider a RedBlackTree container, should that be a range? What happens when you popFront? Indeed, and operations like fill and isSorted also do not make sense on such containers. However, popFront makes a world of sense for a range representing a traversal. Thanks to both Jonathon and yourself for your help |
February 15, 2011 Re: Array types not treated uniformly when passed as ranges | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On 02/15/2011 03:00 PM, Steven Schveighoffer wrote: > On Mon, 14 Feb 2011 21:18:39 -0500, jam <gr0v3er@gmail.com> wrote: > >> Hi all, >> >> Just curious as to the difference in the built-in variable length >> array vs. the std.container.Array and fixed length arrays when it >> comes to using them in functions that take Ranges. >> >> For instance the following does not compile: >> >> import std.algorithm; >> import std.stdio; >> import std.range; >> import std.conv; >> import std.container; >> import std.array; >> >> void main() { >> >> int[5] builtin_fixed; >> int[] builtin_variable; >> Array!(int) con_array; >> >> con_array.length(5); >> builtin_variable.length = 5; >> >> fill(builtin_variable, 9); //ok, no error >> isSorted(builtin_variable); //ditto >> >> //The following 4 statements produce errors >> fill(builtin_fixed, 9); >> fill(con_array, 9); >> >> isSorted(con_array); >> isSorted(builtin_fixed); >> >> } >> >> The errors are variations on: >> >> Error: template std.algorithm.fill(Range,Value) if >> (isForwardRange!(Range) && is(typeof(range.front = filler))) does not >> match any function template declaration >> Error: template std.algorithm.fill(Range,Value) if >> (isForwardRange!(Range) && is(typeof(range.front = filler))) cannot >> deduce template function from argument types !()(int[5LU],int) >> >> If I change those 4 statements to: >> >> fill(builtin_fixed[], 9); >> fill(con_array[], 9); >> >> isSorted(con_array[]); >> isSorted(builtin_fixed[]); >> >> effectively passing ranges (std.container.Array!(int).Array.Range in >> the case of con_array, and int[] for builtin_fixed) which then works >> as expected. This all makes sense, and it's easy enough to write >> wrappers, but I would (well and I did) expect the first way to just >> work. This may just be a nitpick I guess, but being new to the >> language this little detour involved quite a bit of time research (not >> a bad thing, I did learn quite a bit in the process), but makes me >> wonder if I am missing something fundamental regarding when I should >> be using these different array types. > > This is because: > > 1. a fixed-sized array is not a range. It is passed by value, not by reference. > The problem there is IFTI thinking you want to pass the fixed array as a fixed > array and not as a slice. > 2. a container is not a range. An Array is a container, so you must extract a > range from it to use it in range-like activities. > > The second point seems odd, since builtin arrays are ranges, but an Array is > different because it's a true reference type (changing the length from one > reference alters the length of another reference) and it "owns" the memory > contained within, unlike a builtin array which just references the memory. > > But it's also easy to consider other things. Consider a RedBlackTree container, > should that be a range? What happens when you popFront? Isn't there a step to pass toward integration of builtin collections and ranges. Should be transparent from the language-side. There are still, I guess, far too many implementation details leaking into language semantics. Python is a model for that. Denis -- _________________ vita es estrany spir.wikidot.com |
Copyright © 1999-2021 by the D Language Foundation