0

I have the following code:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) public venues;

}

I get the following error:

TypeError: Internal or recursive type is not allowed for public state variables. mapping (uint => Venue) public venues;

So I made the venues private and wrote a getter:

// SPDX-License-Identifier: MIT
pragma solidity >=0.4.22 <0.7.0;
pragma experimental ABIEncoderV2; 

contract VenueRegistry{
    struct Queue{
        uint head;
        uint tail;
        mapping(uint => address) queue;
    }

    struct Venue{
        uint id;
        Queue queue;
    }

    mapping (uint => Venue) venues;

    function getVenue(uint _index) public view returns(Venue memory){
        return venues[_index];
    }
}

Then I get the following error:

Only libraries are allowed to use the mapping type in public or external functions.

The problem seems to be with the mapping inside of struct Queue. When I remove the mapping it works. Is there a way to have nested structs with mappings inside them?

1

The issue is your use of public with incompatible data structures, in two places.

First, this line:

pragma solidity >=0.4.22 <0.7.0;

It makes it impossible to replicate your results because no one is sure what compiler you are using. For this reason, it's good to be specific in a main contract, to force a certain version. It's okay if inherited contracts, libraries, etc., have more flexibility because the main contract will still force the issue.

I used Solc 6.6.

At line 16:

public does several things to a state variable. It's all-or-nothing - highly convenient if you want them all, but you can manually code things if you don't want everything. One of those things is a "free" getter that looks like function variable(args) public returns(....

It works with scalar variables, arrays and mappings, so uint public x; is okay and uint[] public x; is okay, but myComplexStructWithMoreIndexedStuff[] public x; is not compatible. In summary, this is because the compiler is not sure how to construct the getter for you.

No problem. Just make it's private or internal and code your own getter function to ask for the arguments, fetch the elements and return a response.

So:

mapping (uint => Venue) private venues;

At line 18:

Again, public and you're trying to return a struct with a mapping inside. A struct alone would be enough to cause a problem in conjunction with public.

For structs, arrays and mappings, function arguments are storage pointers, meaning a 32-byte reference to a storage location, not the actual data. This works fine for internal and private contexts where the contract trusts itself. However, storage pointers cannot be passed in or out.

Note that the system will not iterate over the data to produce a long-winded response about the values of the variable, and probably never will, because that would O(n) complexity - high CPU and I/O activity on the chain, which you don't want. Since it can't return all the elements of an array and it can't return a simple pointer to the storage there is nothing it can do.

You could rewrite it to return one element, and anything that element, like this:

function getVenueQueueElement(uint id, uint row) public view returns(address) {
  return venues[id].queue[row];
}

You could consider a better data structure to facilitate enumerating the venues and queue members that exist so clients shouldn't request nonsense and the contract objects if they do.

Have a look at this updated explainer and be sure to read parts 1 and 2 to really understand what's going on and the issues addressed: https://medium.com/robhitchens/solidity-crud-epilogue-e563e794fde

It uses storage pointers internally. They are mysterious things, so this might helps: https://blog.b9lab.com/storage-pointers-in-solidity-7dcfaa536089

Hope it helps.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.