Skip to content

Objects mutability

If the Condorcet API is highly flexible and accepts many input formats, its object-oriented mode enables the most advanced and elegant use cases. Users can interact with certain objects in user space that are shared with the Condorcet engine, resulting in immediate and fully supported outcomes. The philosophy behind Condorcet PHP is that nearly everything is mutable—only the Result object exhibits some degree of partial immutability. While this approach may be debated, given the need for strong integrity in voting procedures, it also allows for powerful manipulation and simulation capabilities. Achieving immutability in your implementation is simply a matter of avoiding mutation methods and/or not retaining references to objects passed to Condorcet (or allowing Condorcet to create them itself). The responsibility for this lies with the implementer. To provide a safety net, the API maintains a history of changes for Votes and Candidates objects, ensuring that no modification is forgotten. This is similar to the cryptographic checksum (see the dedicated section).

Overview

It should be noted that internally Condorcet only works with objects. When another input method is used, it creates the objects itself, for the Candidate objects it tries to match them to pre-existing objects. Here is an example. <<< @/code_snippets/mutability_overview.php

Keeping the previous example, look what happens if I change a candidate name. <<< @/code_snippets/candidate_name_changes.php

Or the Ranking: The results of my election are modified instantly (only new results objects). <<< @/code_snippets/vote_ranking_changes.php

Multiples elections per object

php
use \CondorcetPHP\Condorcet\{Candidate, Election, Vote};

// Create objetcs
$candidateA = new Candidate('A');
$candidateB = new Candidate('B');
$candidateC = new Candidate('C');

$election1 = new Election;
$election1->allowsVoteWeight(true);

$election1->addCandidate($candidateA);
$election1->addCandidate($candidateB);
$election1->addCandidate($candidateC);

$election2 = clone $election1;

$voteUnique1 = new Vote([1 => $candidateA, 2=> $candidateB, 3 => $candidateC]);
$voteUnique2 = clone $voteUnique1;
$voteMix = clone $voteUnique1;

$voteMix->setWeight(2);
$voteUnique1->setWeight(3);
$voteUnique2->getWeight(); // 1

// register candidates + $voteMix in both elections
foreach([$election1, $election2] as $e) {
    $e->addVote($voteMix); // In both election
}

// Add other vote to their elections
$election1->addVote($voteUnique1);
$election2->addVote($voteUnique2);

// Count Links for Votes
$voteUnique1->countLinks(); // 1
$voteUnique1->getLinks()[0] === $election1; // True
$voteUnique2->countLinks(); // 1
$voteUnique2->getLinks()[0] === $election2; // True
$voteMix->countLinks(); // 2
$voteMix->getLinks()[0] === $election1; // True
$voteMix->getLinks()[1] === $election2; // True

// Count Links for Candidates
$candidateA->countLinks(); // 2
$candidateA->getLinks()[0] === $election1; // True
$candidateA->getLinks()[1] === $election2; // True

$election1->getWinner() === $election2->getWinner(); // True

$voteMix->setRanking([1 => $candidateB, 2=> $candidateC, 3 => $candidateA]);

$election1->getWinner() === $election2->getWinner(); // False
$election1->getWinner() === $candidateA; // True
$election2->getWinner() === $candidateB; // True

Limitations

In the case of using an external data handler, used to manage up to billions of votes in an election, the correspondence between your objects and those used internally by Condorcet is no longer guaranteed, as these are destroyed during storage and then recreated. However, your objects in user space are properly unlinked from the election.

Released under the MIT License.