Thread overview | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
October 11, 2016 Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
I get "Error: mismatched function return type inference" errors with choosing the return type for functions that work on ranges using, e.g, std.algorithm or std.range functions, but have different behavior based on runtime values. The return type is always a range with the same underlying type. Here's an example: auto foo(int[] ints) { import std.range; if (ints.length > 10) { return chain(ints[0..5], ints[8..$]); } else { //return ints; // Error: mismatched function return type inference of int[] and Result return chain(ints[0..0], ints[0..$]); // This workaround compiles } } Is there a compatible return type that can be used, or some other workaround? I couldn't find one when searching for the error or looking at the phobos source code. Thanks! orip |
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to orip | On Tuesday, 11 October 2016 at 07:55:36 UTC, orip wrote:
> I get "Error: mismatched function return type inference" errors with choosing the return type for functions that work on ranges using, e.g, std.algorithm or std.range functions, but have different behavior based on runtime values. The return type is always a range with the same underlying type.
>
> Here's an example:
>
> auto foo(int[] ints) {
> import std.range;
> if (ints.length > 10) {
> return chain(ints[0..5], ints[8..$]);
> } else {
> //return ints; // Error: mismatched function return type inference of int[] and Result
> return chain(ints[0..0], ints[0..$]); // This workaround compiles
> }
> }
>
> Is there a compatible return type that can be used, or some other workaround?
> I couldn't find one when searching for the error or looking at the phobos source code.
>
> Thanks! orip
Rewrite `return chain(ints[0..5], ints[8..$]);` as `return ints[0..5] ~ ints[8..$];`
The `chain` function doesn't return an array, it returns a lazily-evaluated sequence of an entirely different type from `int[]`.
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to pineapple | On Tuesday, 11 October 2016 at 13:06:37 UTC, pineapple wrote:
> Rewrite `return chain(ints[0..5], ints[8..$]);` as `return ints[0..5] ~ ints[8..$];`
>
> The `chain` function doesn't return an array, it returns a lazily-evaluated sequence of an entirely different type from `int[]`.
Of course it does! I would like the function to return an "input range of int", no matter which one specifically. Is this possible?
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to orip | 11.10.2016 18:46, orip пишет:
> On Tuesday, 11 October 2016 at 13:06:37 UTC, pineapple wrote:
>> Rewrite `return chain(ints[0..5], ints[8..$]);` as `return ints[0..5]
>> ~ ints[8..$];`
>>
>> The `chain` function doesn't return an array, it returns a
>> lazily-evaluated sequence of an entirely different type from `int[]`.
>
> Of course it does! I would like the function to return an "input range
> of int", no matter which one specifically. Is this possible?
it doesn't. Using runtime argument you can't choose compile time parameter - returned type. So it's impossible. Almost - b/c you can use Algebraic. Again you can do the following:
```D
return chain(ints[0..5], ints[8..$]).array; // it returns int[]
```
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to orip | On Tuesday, 11 October 2016 at 15:46:20 UTC, orip wrote: > On Tuesday, 11 October 2016 at 13:06:37 UTC, pineapple wrote: >> Rewrite `return chain(ints[0..5], ints[8..$]);` as `return ints[0..5] ~ ints[8..$];` >> >> The `chain` function doesn't return an array, it returns a lazily-evaluated sequence of an entirely different type from `int[]`. > > Of course it does! I would like the function to return an "input range of int", no matter which one specifically. Is this possible? It is, but you will have to use an interface / class to achieve this behavior (or use some sort of polymorphic struct). Something like this will do the trick: import std.range; import std.stdio; interface IInputRange(T) { bool empty(); T front(); void popFront(); } final class InputRange(Range) if(isInputRange!Range) : IInputRange!(ElementType!Range) { Range r; this(Range r) { this.r = r; } bool empty() { return r.empty; } ElementType!Range front() { return r.front; } void popFront() { r.popFront; } } auto inputRange(Range)(Range r) { return new InputRange!Range(r); } IInputRange!int foo(int[] ints) { import std.range; if(ints.length > 10) { return inputRange(chain(ints[0 .. 5], ints[8 .. $])); } else { return inputRange(ints); } } void main() { auto ir = foo([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); auto ir2 = foo([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); writeln(ir); writeln(ir2); } |
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to TheFlyingFiddle | On 10/11/2016 10:28 AM, TheFlyingFiddle wrote: > On Tuesday, 11 October 2016 at 15:46:20 UTC, orip wrote: >> On Tuesday, 11 October 2016 at 13:06:37 UTC, pineapple wrote: >>> Rewrite `return chain(ints[0..5], ints[8..$]);` as `return ints[0..5] >>> ~ ints[8..$];` >>> >>> The `chain` function doesn't return an array, it returns a >>> lazily-evaluated sequence of an entirely different type from `int[]`. >> >> Of course it does! I would like the function to return an "input range >> of int", no matter which one specifically. Is this possible? > > It is, but you will have to use an interface / class to achieve this > behavior (or use some sort of polymorphic struct). Something like this > will do the trick: > > import std.range; > import std.stdio; > > interface IInputRange(T) > { > bool empty(); > T front(); > void popFront(); > } > > final class InputRange(Range) if(isInputRange!Range) > : IInputRange!(ElementType!Range) > { > Range r; > this(Range r) > { > this.r = r; > } > > bool empty() { return r.empty; } > ElementType!Range front() { return r.front; } > void popFront() { r.popFront; } > } > > auto inputRange(Range)(Range r) > { > return new InputRange!Range(r); > } > > IInputRange!int foo(int[] ints) > { > import std.range; > if(ints.length > 10) { > return inputRange(chain(ints[0 .. 5], ints[8 .. $])); > } else { > return inputRange(ints); > } > } > > void main() > { > auto ir = foo([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); > auto ir2 = foo([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); > writeln(ir); > writeln(ir2); > } > > > Those interfaces already exist in Phobos: :) https://dlang.org/phobos/std_range_interfaces.html auto foo(int[] ints) { import std.range; if (ints.length > 10) { return cast(RandomAccessFinite!int)inputRangeObject(chain(ints[0..5], ints[8..$])); } else { return cast(RandomAccessFinite!int)inputRangeObject(ints); } } void main() { import std.stdio; import std.range; import std.algorithm; writeln(foo([1, 2, 3])); writeln(foo(iota(20).array)); } Ali |
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to orip | On Tuesday, October 11, 2016 07:55:36 orip via Digitalmars-d-learn wrote:
> I get "Error: mismatched function return type inference" errors with choosing the return type for functions that work on ranges using, e.g, std.algorithm or std.range functions, but have different behavior based on runtime values. The return type is always a range with the same underlying type.
>
> Here's an example:
>
> auto foo(int[] ints) {
> import std.range;
> if (ints.length > 10) {
> return chain(ints[0..5], ints[8..$]);
> } else {
> //return ints; // Error: mismatched function return type
> inference of int[] and Result
> return chain(ints[0..0], ints[0..$]); // This workaround
> compiles
> }
> }
>
> Is there a compatible return type that can be used, or some other
> workaround?
> I couldn't find one when searching for the error or looking at
> the phobos source code.
>
> Thanks! orip
You're workaround is basically doing what you need to do. A function can only return one type. The fact that both return statements are returning ranges over the same kind of elements is irrelevant. They have to be _exactly_ the same type. So, either you need to convert the range for the first return statement into int[] so that it matches the second (e.g. by calling array on the result or just using ~), or you need to call chain on two int[]s for the second return statement so that it matches the first.
The second option (which your workaround does) is better if you don't intend to convert the result to an array, since it avoids allocating an array, but if you're just going to convert the result to int[] anyway, the first option would be better.
Regardless, you can't have a function returning different types from different return statements - even with auto. The compiler needs to know exactly what the return type is whether you type it or not; auto just infers it for you rather than requiring you to type it out.
- Jonathan M Davis
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to orip | On 10/11/2016 09:55 AM, orip wrote:
> auto foo(int[] ints) {
> import std.range;
> if (ints.length > 10) {
> return chain(ints[0..5], ints[8..$]);
> } else {
> //return ints; // Error: mismatched function return type inference
> of int[] and Result
> return chain(ints[0..0], ints[0..$]); // This workaround compiles
> }
> }
>
> Is there a compatible return type that can be used, or some other
> workaround?
You've got some options:
1) OOP with std.range.interfaces. Ali already showed how this work. Comes at the cost of extra allocations and indirections.
2) std.range.choose wraps two different range types and uses forwards to one of them based on a condition. Should be cheap. But you need restructure your code a little:
----
auto foo(int[] ints) {
import std.range: chain, choose;
return choose(ints.length > 10,
chain(ints[0..5], ints[8..$]),
ints);
}
----
3) The workaround you already discovered: making a seemingly pointless call to `chain` to get the types to match. Possibly the most efficient solution. Looks a little odd.
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to ag0aep6g | On Tuesday, 11 October 2016 at 18:09:26 UTC, ag0aep6g wrote:
> You've got some options:
Wow, thanks everyone, great information! I think I understand my options now.
|
October 11, 2016 Re: Working with ranges: mismatched function return type inference | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | On Tuesday, October 11, 2016 10:42:42 Ali Çehreli via Digitalmars-d-learn wrote:
> Those interfaces already exist in Phobos: :)
>
> https://dlang.org/phobos/std_range_interfaces.html
>
> auto foo(int[] ints) {
> import std.range;
> if (ints.length > 10) {
> return
> cast(RandomAccessFinite!int)inputRangeObject(chain(ints[0..5], ints[8..$]));
> } else {
> return cast(RandomAccessFinite!int)inputRangeObject(ints);
> }
> }
>
> void main() {
> import std.stdio;
> import std.range;
> import std.algorithm;
> writeln(foo([1, 2, 3]));
> writeln(foo(iota(20).array));
> }
And in this case, if you were considering doing that, you might as well just concatenate the dynamic arrays rather than chaining them, because using interfaces means allocating on the heap just like you would with concatenating.
About the only time that using interfaces is the right solution with ranges is when you're dealing with virtual functions (which can't be templatized), and even then, it's not necessarily the best choice. Here, IMHO, it makes no sense at all.
- Jonathan M Davis
|
Copyright © 1999-2021 by the D Language Foundation