[Ethereum] How to access the length of a public array

arrayssolidity

Say I have the following contract:

contract A {
     uint[1] public MyArray;
     constructor() public {
         MyArray[0] = 56;
     }
}

And I want to know the size of MyArray by looking it up from another contract. Naively, I would have thought that this would work:

contract B {
    
    function getsize() public view returns (uint) {
        A contr = A(addressOfA);
        uint size = contr.MyArray.length;
        return size;
    }
} 

The error I get is:

TypeError: Member "length" not found or not visible after argument-dependent lookup in function (uint256) view external returns (uint256). uint size = contr.MyArray.length;

Does this mean that contr.MyArray is not considered as an array? Is there a way to get the length like this? I would ideally want to avoid writing any getter in contract A because I am trying to reduce the code size in contract A.

Thank you

Best Answer

Solidity creates getter functions for public state variables automatically. For example, the following will work:

contract A {
  uint256 public foo = 1;
}

contract B {
  A a;

  function getFoo() public view returns (uint256) {
    return a.foo();
  }
}

In the case of arrays however, you can only get a single element from the array, rather than the entire array. From the Solidity documentation:

If you have a public state variable of array type, then you can only retrieve single elements of the array via the generated getter function. This mechanism exists to avoid high gas costs when returning an entire array. You can use arguments to specify which individual element to return, for example data(0). If you want to return an entire array in one call, then you need to write a function.

Basically, while you can do the following:

contract A {
  uint256[] public foo;
}

contract B {
  A a;

  function getFoo() public view returns (uint256) {
    return a.foo(0); // Get item at index 0 from the array
  }
}

You cannot use a.foo() to read the entire array, and you will have to use a getter function like this for example:

contract A {
  uint256[] public foo;

  function getFooLength() public view returns (uint256) {
    return foo.length;
  }
}

contract B {
  A a;

  function getFoo() public view returns (uint256) {
    return a.getFooLength();
  }
}