Thread overview
Cannot call find with haystack elements having a explicit copy constructors
Jul 15, 2021
Per Nordlöw
Jul 15, 2021
Per Nordlöw
Jul 15, 2021
Per Nordlöw
Jul 15, 2021
RazvanN
July 15, 2021

The adding of copy construtors to Service defined as

@safe struct Service {
    this(ref return scope typeof(this) rhs) {}
    this(const ref return scope typeof(this) rhs) const {}
}

@safe struct Session {
    void openAndGetService(in string key) scope {
        import std.algorithm.searching : find;
        auto hit = _pairs.find!((x) => x.key == key)();
    }
    private Pair[] _pairs;
    private struct Pair {
        string key;
        Service service;
    }
}

makes a call to find error as

copy_ctor_find_fail.d(9): Error: template `std.algorithm.searching.find` cannot deduce function from argument types `!((x) => x.key == key)(Pair[])`, candidates are:
auto hit = _pairs.find!((x) => x.key == key)();
^
std/algorithm/searching.d(1559):        `find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)`
InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
^
std/algorithm/searching.d(1827):        `find(alias pred, InputRange)(InputRange haystack)`
with `pred = __lambda2,
InputRange = Pair[]`
must satisfy the following constraint:
`       isInputRange!InputRange`
InputRange find(alias pred, InputRange)(InputRange haystack)
^
std/algorithm/searching.d(1881):        `find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)`
R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
^
std/algorithm/searching.d(2340):        `find(alias pred = "a == b", Range, Ranges...)(Range haystack, Ranges needles)`
with `pred = __lambda2,
Range = Pair[],
Ranges = ()`
must satisfy the following constraint:
`       Ranges.length > 1`
Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)
^
std/algorithm/searching.d(2455):        `find(RandomAccessRange, alias pred, InputRange)(RandomAccessRange haystack, scope BoyerMooreFinder!(pred, InputRange) needle)`
RandomAccessRange find(RandomAccessRange, alias pred, InputRange)(
^```
Using

```d
auto hit = _pairs.find!((scope const ref x) => x.key == key)();

fails in the same way. What's wrong?

July 15, 2021

On Thursday, 15 July 2021 at 11:08:25 UTC, Per Nordlöw wrote:

>

fails in the same way. What's wrong?

@safe struct Service {
    this(ref typeof(this) rhs) {}
    this(const ref typeof(this) rhs) const {}
}

also fails. On the other hand, using a postblit as

@safe struct Service {
    this(this) {}
}

passes.

July 15, 2021

On Thursday, 15 July 2021 at 11:08:25 UTC, Per Nordlöw wrote:

>

The adding of copy construtors to Service defined as

@safe struct Service {
    this(ref return scope typeof(this) rhs) {}
    this(const ref return scope typeof(this) rhs) const {}
}

Using inout as

@safe struct Service {
    this(inout ref typeof(this) rhs) inout {}
}

works.

July 15, 2021

On Thursday, 15 July 2021 at 11:08:25 UTC, Per Nordlöw wrote:

>

The adding of copy construtors to Service defined as

@safe struct Service {
    this(ref return scope typeof(this) rhs) {}
    this(const ref return scope typeof(this) rhs) const {}
}

@safe struct Session {
    void openAndGetService(in string key) scope {
        import std.algorithm.searching : find;
        auto hit = _pairs.find!((x) => x.key == key)();
    }
    private Pair[] _pairs;
    private struct Pair {
        string key;
        Service service;
    }
}

struct Pair will have an inout(inout) copy constructor defined the following way:

this(inout ref return scope typeof(this) rhs) inout
{
    key = rhs.key;
    service = rhs.service;
}

service = rhs.service will be rewritten to service.__cpctor(rhs.service), but since Service does not define an inout copy constructor it will fail to typecheck and the compiler will annotate it with @disable. Therefore, Pair will become uncopyable. This will result in isInputRange failing on Pair[] (more specifically, this constraints from isInputRange: is(typeof((return ref R r) => r.front)). If the copy constructor of Service is inout(inout), the generated copy constructor of Pair will be succesfully typechecked and everything will work.

For more context, please see this issue [1] and more specifically, this comment [2].

Cheers,
RazvanN

[1] https://issues.dlang.org/show_bug.cgi?id=20876
[2] https://issues.dlang.org/show_bug.cgi?id=20876#c4