I'm going to go out on a limb here and say you probably don't want to do that, even if you could, which you can't, at least for now.
The blockchain is not like other platforms. Some of the changes are hard to accept because they're opposite of what experience teaches.
Iteration over a set is almost always a client-side concern. It's easy to see how a client with the whole data set can figure that out on its own. You shouldn't burden the contract with a concern the clients can address without assistance.
This might help explain where I'm coming from. https://medium.com/p/2303010c8b09/
In Solidity you can return values from functions to the user if these functions are declared view(/constant).
When they are not declared as view you can still get a return value by using .call() this will execute the call locally and not mine it onto the blockchain however.
Return values do play a big role as they can be returned to other functions even when the function is not view/constant. I'll give a real world example.
The following function creates a new 'bounty' on a bounty contract, it returns a bytes32 value.
function createBounty(
BountyInterface.Bounty storage _bounty,
string _title,
string _issueURL,
string _reference,
uint _deadline,
address _issuer,
uint _reward
) external returns (bytes32) {
bytes32 _index = keccak256(abi.encodePacked(_issueURL));
_bounty.bounties[_index].title = _title;
_bounty.bounties[_index].issueURL = _issueURL;
_bounty.bounties[_index].reference = _reference;
_bounty.bounties[_index].timestamp = block.timestamp;
_bounty.bounties[_index].deadline = _deadline;
_bounty.bounties[_index].status = BountyInterface.statusOptions.ACTIVE;
_bounty.bounties[_index].issuer = _issuer;
_bounty.bounties[_index].reward = _reward;
_bounty.bounty_indices.push(_index);
emit logCreateBounty(_issuer, msg.sender, _title, _reward);
return _index;
}
The return value is then sent to this function on another contract. This will store the return value in an array so that the newly created bounty is associated with a user as well:
function createBounty(address _group, string _title, string _issueURL, string _reference, uint _deadline, uint _reward) external {
bytes32 _index = Group(_group).createBounty(_title, _issueURL, _reference, _deadline, msg.sender, _reward);
People(ContractProvider(CMC).contracts("people-storage")).addBounty(_group, _index, msg.sender);
}
Best Answer
Your unbounded
for
loop is an anti-pattern because it will cease to operate at scale when the gas cost exceeds the block gas limit. Ouch.Break it up into multiple fixed-cost operations. Iteration is the caller's responsibility.
I also noticed you're declaring a storage variable inside a function. Not conventional. Below will give you "free" getters
voteList(uint row)
andvoteStructs[bytes32 key]
. The client can 1) get the list length, 2) get the keys one at a time, and 3) get the complete structure for any key.In case it helps, there some patterns that combine mappings with key lists over here: Are there well-solved and simple storage patterns for Solidity?
Your snippet refers to a
candidatesList
and does some computation that you might want the smart contract to tally as the votes come in so you aren't tempted to iterate later.Hope it helps.