List of struct error

This code gives me an error. Can anyone help me fix it?

struct MyInt:
    var n: Int

    fn __init__(out self, x: Int):
        self.n = x

    fn __copyinit__(out self, existing: Self):
        self.n = existing.n

    fn __moveinit__(out self, owned existing: Self):
        self.n = existing.n

    fn __contains__(self, other: MyInt) -> Bool:
        if self.n == other.n:
            return True
        else:
            return False
            
def main():            
    var list1: List [MyInt] = []
    var myint: MyInt = MyInt(1)
    print(myint in list1)            

Error:

life.mojo:100:17: error: invalid call to '__contains__': could not deduce positional-only parameter #2 of callee '__contains__'
    print(myint in list1)
          ~~~~~~^~~~~~~~
life.mojo:100:20: note: failed to infer parameter #2, argument type 'MyInt' does not conform to trait 'EqualityComparable & Copyable & Movable'
    print(myint in list1)
                   ^~~~~

The error message is giving you the correct direction. The signature for __contains__ should look like this: List | Modular

I don’t believe there is a trait that corresponds to __contains__ yet, (stdlib traits enumerated here). I don’t believe there is another way to get the expected signature of a “special method” other than looking for an example in the stdlib yet. Discussed in docs here.

Implementing the suggested traits on your struct fixes the problem:

struct MyInt(EqualityComparable, Copyable, Movable):
    var n: Int

    fn __init__(out self, x: Int):
        self.n = x

    fn __eq__(read self, read other: Self) -> Bool:
        return self.n == other.n

    fn __ne__(read self, read other: Self) -> Bool:
        return not self == other

    fn __copyinit__(out self, existing: Self):
        self.n = existing.n

    fn __moveinit__(out self, owned existing: Self):
        self.n = existing.n

    fn __contains__(self, other: MyInt) -> Bool:
        if self.n == other.n:
            return True
        else:
            return False


def main():
    var list1: List[MyInt] = []
    var myint: MyInt = MyInt(1)
    print(myint in list1)

__ne__ and __eq__ satisfy EqualityComparable, which means that self type now satisfies the signature for contains: __contains__[U: EqualityComparable & Copyable & Movable, //](self: List[U, hint_trivial_type], value: U) -> Bool which has the infer-only parameter U that must implement EqualityComparable & Copyable & Movable.

2 Likes

Submitted an issue about the unkownability of the special method signatures

Close issue, see reply below this.

I was wrong!

When you use syntax that invokes special methods (in, [index], +, etc.), it’s equivalent to calling a method on the left-hand side (LHS) operand. Example: lhs.__special__(rhs) in the case of binary operators.

The expected method signature is defined by the type of the LHS and varies by type (but sometimes by the RHS when it’s reversable.

What I said earlier is misleading. To determine how in works for a given type like List, you should check the docs for List itself. There is no universal signature for __contains__—it is type-specific.