How to resolve "Incompatible return value type (got "FancyCat", expected "Self")"

154 Views Asked by At

Here's a minimal example I've written:

from __future__ import annotations

from typing import Protocol
from typing_extensions import Self


class Cat(Protocol):
    def add(self, other: Self) -> Self:
        ...
    def sub(self, other: Self) -> Self:
        ...


class FancyCat(Cat):
    def __init__(self, value: int):
        self._value = value

    def add(self, other: Self) -> Self:
        return FancyCat(self._value + other._value)

    def sub(self, other: Self) -> Self:
        return FancyCat(self._value - other._value)

fc = FancyCat(3)
fc2 = FancyCat(4)
fc.add(fc2)

If I try to type check it, I get

$ mypy t.py
t.py:19: error: Incompatible return value type (got "FancyCat", expected "Self")  [return-value]
t.py:22: error: Incompatible return value type (got "FancyCat", expected "Self")  [return-value]
Found 2 errors in 1 file (checked 1 source file)

I'm so confused - isn't Self FancyCat in this case?

How can I satisfy mypy here?

1

There are 1 best solutions below

3
On BEST ANSWER

Your code does not guarantee that Self will be returned. For example, child classes will still return FancyCat, therefore Self annotation is invalid.

To get rid of errors, you can either:

a) make sure it's always self.__class__ returned, which IS actual Self

def add(self, other: Self) -> Self:
    return self.__class__(self._value + other._value)

b) type with what you are actually returning, FancyCat

def sub(self, other: Self) -> FancyCat:
    return FancyCat(self._value - other._value)