'Solidity: Data location must be "memory" or "calldata" for return parameter in function

I am learning Ethereum dev in solidity and trying to run a simple HelloWorld program but run into the following error:

Data location must be "memory" or "calldata" for return parameter in function, but none was given.

Here is my code:

pragma solidity ^0.8.5;

contract HelloWorld {
  string private helloMessage = "Hello world";

  function getHelloMessage() public view returns (string){
    return helloMessage;
  }
}


Solution 1:[1]

You need to return string memory instead of string.

Example:

function getHelloMessage() public view returns (string memory) {
    return helloMessage;
}

The memory keyword is the variable data location.

Solution 2:[2]

use string memory instead of string.

  • storage - variable is a state variable (store on blockchain) memory - variable
  • List item - is in memory and it exists while a function is being called
  • calldata - special data location that contains function arguments, only available for external functions

example code : Data Locations

Solution 3:[3]

For those reading this who have similar code, 'memory' may not necessarily be the correct word to use for you. You may need to use the words 'calldata' or 'storage' instead. Here is an explanation:

Memory, calldata (and storage) refer to how Solidity variables store values.

For example:

1. Memory: here is an example using the word 'memory':

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import 'hardhat/console.sol'; // to use console.log

contract MemoryExample {
    uint[] public values;

    function doSomething() public
    {
        values.push(5);
        values.push(10);

        console.log(values[0]); // logged as: 5

        modifyArray(values);
    }

    function modifyArray(uint[] memory arrayToModify) pure private {
        arrayToModify[0] = 8888;

        console.log(arrayToModify[0]) // logged as: 8888 
        console.log(values[0]) // logged as: 5 (unchanged)
    }
}

Notice how the 'values' array was not changed in the private function because 'arrayToModify' is a copy of the array and does not reference (or point to the array that was passed in to the private function.

2. Calldata is different and can be used to pass a variable as read-only:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

contract CallDataExample {
    uint[] public values;

    function doSomething() public
    {
        values.push(5);
        values.push(10);

        modifyArray(values);
    }

    function modifyArray(uint[] calldata arrayToModify) pure private {
        arrayToModify[0] = 8888; // you will get an error saying the array is read only
    }
}

3. Storage: a third option here is to use the 'storage' keyword:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.9;

import 'hardhat/console.sol'; // to use console.log

contract MemoryExample {
    uint[] public values;

    function doSomething() public
    {
        values.push(5);
        values.push(10);

        console.log(values[0]); // logged as: 5

        modifyArray(values);
    }

    function modifyArray(uint[] storage arrayToModify) private {
        arrayToModify[0] = 8888;

        console.log(arrayToModify[0]) // logged as: 8888
        console.log(values[0]) // logged as: 8888 (modifed)
    }
}

Notice how by using the memory keyword, the arrayToModify variable references the array that was passed in and modifies it.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Richard K