Why 'in' works only for assoc arrays?

JN 666total at wp.pl
Sat Dec 28 02:14:34 UTC 2024


On Friday, 27 December 2024 at 19:55:41 UTC, Andy Valencia wrote:
>
> One thing I learned which is somewhat topical--"x in y" is not 
> a boolean expression; its value of the expression is a pointer 
> to the value in the AA.  This would break for "string in 
> string" searches, but seems OK for regular arrays.
>
> Andy

"in" only works for associative arrays by checking for existence 
of a provided key in an associative array. E.g.:

     ```
     void main()
     {
         string[string] nameAddressMapping = ["John": "New York"];
         assert("John" in nameAddressMapping);
         assert("Mary" in nameAddressMapping); // assert failure
     }
     ```

Naturally, a user will try to use it to check for existence of a 
value in an array, such as:

     ```
         string[] names = ["John", "Alice", "Bob"];
         assert("John" in names);
     ```

But that won't work, because:

```
onlineapp.d(7): Error: incompatible types for `("John") in 
(names)`: `string` and `string[]`
onlineapp.d(7):        `in` is only allowed on associative arrays
onlineapp.d(7):        perhaps use `std.algorithm.find("John", 
names)` instead
```

Okay, so the user will try the suggestion of the compiler:

     ```
         string[] names = ["John", "Alice", "Bob"];
         assert(std.algorithm.find("John", names));
     ```

This will fail in compilation, because in std.algorithm.find, the 
haystack comes first, then the needle. And the error isn't even 
obvious, because it's a template spew.

     ```
     onlineapp.d(6): Error: none of the overloads of template 
`std.algorithm.searching.find` are callable using argument types 
`!()(string, string[])`
     
/dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1598):        Candidates are: `find(alias pred, InputRange)(InputRange haystack)`
     
/dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1685):                        `find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)`
       with `pred = "a == b",
            InputRange = string,
            Element = string[]`
       must satisfy the following constraint:
     `       is(typeof(binaryFun!pred(haystack.front, needle)) : 
bool)`
     
/dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(1953):                        `find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)`
       with `pred = "a == b",
            R1 = string,
            R2 = string[]`
       must satisfy the following constraint:
     `       is(typeof(binaryFun!pred(haystack.front, 
needle.front)) : bool)`
     
/dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(2412):                        `find(alias pred = "a == b", Range, Needles...)(Range haystack, Needles needles)`
       with `pred = "a == b",
            Range = string,
            Needles = (string[])`
       must satisfy the following constraint:
     `       Needles.length > 1`
     
/dlang/dmd/linux/bin64/../../src/phobos/std/algorithm/searching.d(2527):                        `find(RandomAccessRange, alias pred, InputRange)(RandomAccessRange haystack, scope BoyerMooreFinder!(pred, InputRange) needle)`
     ```

So let's try to re-order the function arguments so it's as it 
should be:

     ```
         string[] names = ["John", "Alice", "Bob"];
         assert(std.algorithm.find(names, "John"));
     ```

It's fine now, right? Oh wait, it isn't.

     ```
         string[] names = ["John", "Alice", "Bob"];
         assert(std.algorithm.find(names, "Mary")); // no assert 
failure
     ```

find returns empty haystack when no match is found and empty 
arrays in D evaluate to true. So the find replacement proposed by 
the compiler doesn't do what we wanted in the first place.

At the very least, the compiler message should be fixed, the args 
to std.algorithm.find should be swapped

Still, the fix with find doesn't exactly work how the user would 
expect it. I think the compiler message should recommend 
std.algorithm.canFind instead.

Can we make "in" to just work for arrays? things like if (3 in 
[1,2,3]) and if ("abc" in "abcdef") should just work...



More information about the Digitalmars-d-learn mailing list