Thread overview
Why 'in' works only for assoc arrays?
Dec 27
JN
Dec 28
JN
Dec 28
Sergey
Dec 28
IchorDev
December 27

Why not make 'in' work for arrays (and strings also)?

int[string] phonebook;
if ("John" in phonebook) // works

int[] numbers;
if (3 in numbers) // doesn't work, compiler recommends std.algorithm.find

string buildLog;
if ("build error" in buildLog) // doesn't work, compiler recommends std.algorithm.find

Good thing that compiler recommends what to use instead, but why not just make it work for any container?

December 27

On Friday, 27 December 2024 at 19:17:13 UTC, JN wrote:

>

Why not make 'in' work for arrays (and strings also)?

int[string] phonebook;
if ("John" in phonebook) // works

int[] numbers;
if (3 in numbers) // doesn't work, compiler recommends std.algorithm.find

string buildLog;
if ("build error" in buildLog) // doesn't work, compiler recommends std.algorithm.find

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

December 28

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...

December 27
On 12/27/24 6:14 PM, JN wrote:

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

[...]

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

That's not natural at all because if it worked that way, another user would complain about 'in's inconsistency between associative arrays and arrays: keys vs. values.

> onlineapp.d(7):        `in` is only allowed on associative arrays
> onlineapp.d(7):        perhaps use `std.algorithm.find("John", names)`

That help is not very useful but it escapes any criticism because of the clever user of the word "perhaps". Yes, std.algorithm.find could be used but the correct function to use in this case is std.algorithm.canFind.

Ali

December 28

On Friday, 27 December 2024 at 19:17:13 UTC, JN wrote:

>

Why not make 'in' work for arrays (and strings also)?

int[string] phonebook;
if ("John" in phonebook) // works

int[] numbers;
if (3 in numbers) // doesn't work, compiler recommends std.algorithm.find

string buildLog;
if ("build error" in buildLog) // doesn't work, compiler recommends std.algorithm.find

Good thing that compiler recommends what to use instead, but why not just make it work for any container?

Because in on associative arrays is a fast operation (O(1)).

On an array, searching for a value is a linear operation.

And Ali is right, really, you are talking about keys vs. values. For example, this doesn't work:

int[string] phonebook;
if(5551212 in phonebook) // error

which is the equivalent operation you are looking for.

-Steve

December 28

On Friday, 27 December 2024 at 19:17:13 UTC, JN wrote:

>

Why not make 'in' work for arrays (and strings also)?

int[string] phonebook;
if ("John" in phonebook) // works

int[] numbers;
if (3 in numbers) // doesn't work, compiler recommends std.algorithm.find

string buildLog;
if ("build error" in buildLog) // doesn't work, compiler recommends std.algorithm.find

Good thing that compiler recommends what to use instead, but why not just make it work for any container?

join the dark side of second best language :)

a = [1,2,3]
d = dict(zip(a, ['a','b','c']))

if 3 in a:
    print("found in array")
if 3 in d:
    print("found in keys")
if 'a' in d.values():
    print("found in values")
December 28

On Friday, 27 December 2024 at 19:17:13 UTC, JN wrote:

>
int[] numbers;
if (3 in numbers) // doesn't work, compiler recommends std.algorithm.find

string buildLog;
if ("build error" in buildLog) // doesn't work, compiler recommends std.algorithm.find

Good thing that compiler recommends what to use instead, but why not just make it work for any container?

Because looking up a key in an associative array is defined by its implementation. Associative arrays come with a lot of baggage, whereas slices (AKA dynamic arrays) really do not. Additionally, slices couldn't provide a succinct implementation for 'finding an item' or 'finding series of items' because there are various implementation-details for a search algorithm that the programmer (not the compiler) needs to decide, including:

  • How are you checking for equality? (e.g. is -0f in [0f] true or false?)
  • What kind of search are we using? Linear, Boyer-Moore, etc.?
  • Can we assume the array sorted?

std.algorithm.searching intelligently accounts for many of the various problems with having a one-size-fits-all 'search' function.
For example, if you want -0f in [0f] to be true:

[0f].canFind!"a == b"(-0f);

And if you want it to be false:

[0f].canFind!"a is b"(-0f);

You can get a lot out of such a versatile function, even making it do things it wasn't strictly intended to do:

[1f, 10f, 20f].canFind!"a > b"(10f); //checks if any of the items are greater than 10

You wouldn't be able to get the same flexibility out of in. It would either be too implementation-defined (i.e. unreliable); or too specific, thereby necessitating that you use canFind most of the time anyway for its superior expressive power.