0

This is my first contract ever (building on an own example learning case I made up).

Given this Contract (simplified):

unit gEval = 0;

contract Group {
  struct Grp {
    string    name;
    uint      orgId;
    Contrib[] contribs;
  }

  struct Contrib {
     uint id;
     uint grpId;
     Evals[] evals;  
  }

  struct Eval {
    uint id;
    address evaluator;
    uint result;

  }


  function  evalContrib(Contrib c, uint res) public {
    require(msg.sender != c.contributor);

    Eval eval = Eval(gEval++,msg.sender, res);

    c.evals.push(eval);
  }
}

I get :

Error: Member "push" is not available in struct Group.Eval memory[] memory outside of storage. c.evals.push(eval); ^----------------^

This is what I understand: The Contrib c param in the evalContrib function is a memory parameter, as it is a function parameter, while I am trying to call c.evals.push(eval) which would be storage I guess.

I tried several combinations of assigning storage or memory pointer but I haven't been able to solve this.

How can I implement something like that? Can I only get a reference by Id maybe, e.g. contribs[id].evals.push(eval)?

Note: My design may be utterly inefficient for solidity (lots of structs with arrays), so I am happy for any suggestion.

  • 1
    I only have time for a brief comment. It looks like you're on this path. The structs look appropriate but it starts falling apart in when accessing the data in the structs. "rabbit hole" warning: It's a fairly complete description of a pattern I think you can use: medium.com/@robhitchens/… – Rob Hitchens - B9lab Nov 28 '17 at 15:27
  • thanks @RobHitchens, that looks like a way to go for this case! – faboolous Nov 28 '17 at 19:31
3

You should definitely follow Rob Hitchens recommendation.

Now to fix the warning a few things to note:

  • You cannot use struct in public functions, it is a limitation in the ABI specification (perhaps it will be supported in a future version).
  • You can only use push for arrays in storage.

If the function is not for use from outside of the contract you can declare it as internal, so you can pass structures

Struct are passed as memory references, but you can specify the location with memory or storage.

function  evalContrib(Contrib storage c, uint res) internal {
    require(msg.sender != c.contributor);

    Eval memory eval = Eval(gEval++, msg.sender, res);

    c.evals.push(eval);
}

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.