When a function's visibility is external, trying to modify the function parameters within that function gives the error:

TypeError: Expression has to be an lvalue.

However, if I change the visibility to anything else, Remix gives no errors.

An example function which causes the error:

function d(uint num) external pure {
    num += 2; //<-- This line causes the error

But changing the visibility to public removes the error:

function d(uint num) public pure {
    num += 2; 

Why does external visibility cause function parameters to not be lvalues?


A public function need to write all of the arguments to memory and may be called internally, which is actually an entirely different process than external calls. Internal calls are executed via jumps in the code.

For external functions, the compiler doesn't need to allow internal calls, and so it allows arguments to be read directly from calldata, which I believe is readonly.

Because you can't use internal call from an external function, you don't need to save in memory the state of your argument and your argument num become immutable.

In the following example, you don't have an assignation to the argument variable and return the uint without any errors.

function d(uint num) external pure returns(uint) {
    return num + 2;

function d2(uint num) public pure returns(uint) {
    return num + 2;
| improve this answer | |
  • Thanks for your answer, the readonly thing seems to explain it. I'm actually doing some manipulation with some bytes variables, the uint example was just for simplification of the question, but I think your examples might help others that stumble upon this problem. – AnAllergyToAnalogy May 9 '18 at 1:11

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.