Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parameter interface strictness #2

Open
LucidTaZ opened this issue Feb 15, 2017 · 4 comments
Open

Parameter interface strictness #2

LucidTaZ opened this issue Feb 15, 2017 · 4 comments

Comments

@LucidTaZ
Copy link
Owner

The Decision interface prescribes an apply method receiving a GameState parameter, which is itself also an interface. This makes sense from an interface standpoint, but it constrains an implementer that applies strict static analysis.

The reason is that a concrete MyDecision wants a concrete MyGameState as a parameter, in order to actually do something useful such as filling a field on the board. However, since the interface prescribes a GameState parameter, this is not possible without agitating static analysis tools. (Such as phpstan with a high enough strictness level.)

Conceptually this could be solved by templating in languages that support it. In PHP however we need to look to other solutions. Perhaps a concrete Decision can already take its original concrete GameState via the constructor so that the interface does not need to know about it? Since Decisions are constructed by concrete GameStates, this keeps all concreteness at the implementer's side.

@LucidTaZ
Copy link
Owner Author

The proposed solution has a drawback: PHP's type hints are currently invariant: an implementation must exactly match the interface. With contravariant parameter types and covariant return types, a clean solution becomes quite obvious. However, a totally clean solution that keeps static analysis happy, might not exist until we get at least covariant return types.

More information:

@LucidTaZ
Copy link
Owner Author

LucidTaZ commented Feb 22, 2017

Another good (and much simpler) example that exposes this problem is the Player::equals(Player): bool method. The method expects a "same class as implementer" parameter. However this cannot be done in PHP. Perhaps it is best to replace it with a getId(): string method, which is compared by the engine to determine equality. isFriendsWith() could be replaced by getTeamId() or something similar.

@LucidTaZ
Copy link
Owner Author

LucidTaZ commented Jun 2, 2017

This article might have some clues to deal with the problem: https://www.moxio.com/blog/17/on-type-safety-without-generics-and-the-role-of-package-design

We may use the Adapter Pattern to circumvent the need for templating and to cope with proper variance.

@LucidTaZ
Copy link
Owner Author

LucidTaZ commented Aug 2, 2017

Perhaps it's worth checking whether we can use a static annotation in a docblock, like so:

// (interface Player)
/**
 * @param static $player
 */
function equals(Player $player): bool;

// (interface GameState)
/**
 * @return static[]
 */
function getPossibleMoves(): array;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant