Skip to content

(Re: #1) Z_mod_ related code issue #2

@1343922569-webmail-hzau

Description

Re: #1

But now I think that, the revisions I suggested earlier still have some flaws!

While the recent fix adding _n=None to Z_.__init__ successfully resolves the TypeError, it introduces a minor design flaw: it exposes a meaningless second argument to the outside world, allowing unintuitive instantiations like Z100(22, 666). To maintain the encapsulation and prevent potential misuse, you can further improve this by removing the dummy parameter and handling the argument compatibility dynamically within the base class instead.

New proposed Fix:
Instead of modifying the Z_ subclass to accept an unnatural dummy parameter _n=None (which would incorrectly allow users to initialize it with two arguments like Z100(22, 666)), the fix should be applied to the parent Z_n class's arithmetic methods (__add__, __mul__, __neg__, __pow__ and inverse).
In Z_n class's arithmetic methods, you can use a try ... except TypeError: ... block to attempt initialization with two arguments, falling back to one argument if it fails. For example, in __add__:
Old:

def __add__(self, b: Self) -> Self:
    if not self.n == b.n:
        raise Exception("unsupported operation")
    return self.__class__(self.z + b.z, self.n)

New:

def __add__(self, b: Self) -> Self:
    if not self.n == b.n:
        raise Exception("unsupported operation")
    result_z = self.z + b.z
    try:
        return self.__class__(result_z, self.n)
    except TypeError:
        return self.__class__(result_z)

This same fallback logic should be applied to __mul__, __neg__, __pow__, and inverse as well.

By catching the TypeError and falling back to self.__class__(...) with a single argument, it can achieve compatibility for both Z_n and Z_ objects. The advantage of this method is that it maintains encapsulation, so that the parameter list of the constructor of the dynamic Z_ class isn't "polluted" with unnecessary arguments _n that could be misused externally.

Note: While you could technically resolve this by directly overriding all arithmetic methods within the Z_ class, doing so would introduce significant code duplication and verbosity. Instead, applying the try ... except ... method in the parent Z_n class provides a slightly more indirect but far more elegant and maintainable solution.

Additionally, the inverse method in Z_n currently hardcodes its return type to Z_n instead of dynamically returning the instance's actual class (self.__class__(...)), which violates the -> Self type hint and breaks consistency with __add__, __mul__, __neg__and __pow__. The logic which returns self.__class__(...) here maintains the consistency and ensures it returns the appropriate type.
Old return logic in method invrese:

return Z_n(PrimalityTesting.extended_euclidean(int(self.z), int(self.n))[0], self.n)

The new return logic in method invrese can be like this:

result_z = PrimalityTesting.extended_euclidean(int(self.z), int(self.n))[0]
try:
    return self.__class__(result_z, self.n)
except TypeError:
    return self.__class__(result_z)

The new proposed fix code and its relevant change can be referenced at the following link:
1343922569-webmail-hzau@685542d

Thanks!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions