5
pragma solidity >= 0.4.25 < 0.6;

contract Bank {
    struct Customer {
        uint age;
    }

    Customer[][] customers;

    function foo() public {
        if (customers.length > 0) {
            Customer[] storage northBranch = customers[0];
            if (northBranch.length > 1) {
                Customer storage customer = northBranch[1];
                customer.age = 23;
            }
        } else {
            Customer memory bob;
            bob.age = 34;
            customers.length += 1;
            customers[0].push(bob);
        }
    }
}

I´m looking for examples of function that return and a array when a function is called. There are many examples but I couldent find a function that return an array with arrays inside with struct inside.

I try this but it doesnt work.

function get() external view returns (Customer[][]) {
    /*Customer[][] memory resCustomer;

    for(uint i = 0; i<customers.length;i++) {
        resCustomer[i][] = customers[i][];

    }*/

    return (customers);
}

ERROR:

TypeError: This type is only supported in the new experimental ABI encoder. Use "pragma experimental ABIEncoderV2;" to enable the feature.

Any idea about how can I travel across the main array to get a inside array and the struct that is inside?

  • It doesn't work firstly because in the function declaration you should put returns (Customers[][]), not returns (customers[][]). Second, I bet that you can simply return your customers table, instead of replicating it first (i.e., inside the function, simply do return customers;). – goodvibration Dec 27 '18 at 8:00
  • I change the return and i comment the replication of the array. Bu appear this. imgur.com/a/Q4sb6A1 – UnexpectedCharacter Dec 27 '18 at 8:07
  • EDIT: imgur.com/a/5xOCVzj – UnexpectedCharacter Dec 27 '18 at 8:08
  • Please paste the error as text (not a dubious link, nor an image) in your question (not in the comment-section). – goodvibration Dec 27 '18 at 8:15
2
+25

As the error says, returning multi-dimensional dynamic arrays is only supported as an experimental feature using ABIEncoderV2 (see the Solidity documentation).

Add the following line to the top of your contract:

pragma experimental ABIEncoderV2;

Your full contract will then be:

pragma solidity >= 0.4.25 < 0.6;
pragma experimental ABIEncoderV2;

contract Bank {
    struct Customer {
        uint age;
    }

    Customer[][] customers;

    function foo() public {
        if (customers.length > 0) {
            Customer[] storage northBranch = customers[0];
            if (northBranch.length > 1) {
                Customer storage customer = northBranch[1];
                customer.age = 23;
            }
        } else {
            Customer memory bob;
            bob.age = 34;
            customers.length += 1;
            customers[0].push(bob);
        }
    }

    function get() external view returns (Customer[][] memory) {
        return (customers);
    }
}

Be sure to use Web3.js v1.0.0-beta.36 to make use of this functionality, as full decoding of mutli-dimensional dynamic arrays has only been added from that version onwards (See web3.js#1148). There is still no hard guarantee that it will work as expected though, since it is an experimental feature.

This is an experimental feature, so it is not recommended to use something like this in production environments. Perhaps you could re-evaluate whether you really need to store your data in such a structure, or if something simpler is also possible.

1

Since returning double dynamic array (such as string[] or bytes[]) or array of struct isn't supported yet unless you don't add the line pragma experimental ABIEncoderV2; at the top of your code, as answered by Rosco, what you can do in your get() function is to return multiple values (that is supported by solidity) by un-wrapping your struct.

For example, you have struct

Customer {
    uint age;
    address id;
    bytes32 name;
}

and state

Customer[] customers;

you can write the get() function as follow:

function get() external view returns (uint[] memory ages, uint[] memory ids, bytes32[] names) {

    ages = new uint[](customers.length);
    ids = new address[](customers.length);
    names = new bytes32[](customers.length);

    for(uint i = 0; i<customers.length;i++) {
        ages[i] = customers[i].age;
        ids[i] = customers[i].id;
        names[i] = customers[i].name;
    }
}

Since you have Customer[][] try to find a smart way to unwrap this structure for your needs.

Hope it helps!!

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.