0

I am writing code for a contract to keep track of Theatrical plays. I get this error on this line:

play1.PlayTitle   = PlayTitle; (line 62 below)

browser/teste.sol:62:13: TypeError: Member "PlayTitle" not found or not visible after argument-dependent lookup in struct Plays.PlayActionInfo storage ref[] storage ref play1.PlayTitle = PlayTitle;

        ^-------------^

I do have PlayTitle defined in both structs. I envision the user will enter the play title when the contract is created and when there are updates to the play information. The fact I define it twice may be part of the problem.

But I when I deleted the line containing PlayTitle, the next line ( play1.PlayWorkerName[numUpdates] = PlayWorkerName; ) got the error.

Could someone explanation the meaning of the error? Any other code suggestions would be appreciated.

I did see other questions with the same error but the solutions didn't seem relevant to my code.

For my environment configuration, I'm using Remix in a Chrome browser.

Here's all my code:

pragma solidity ^0.4.18;

contract Plays
{
    //used to store information about the owner of the Play
    struct TopLevelPlayInfo {
      address PlayOwnerAddress;
      bytes32 PlayOwnerName;
      bytes32 PlayTitle;
    }
//instance of the owner
TopLevelPlayInfo playi;

//map into the PlayOwner based upon the owner's address
mapping (address => TopLevelPlayInfo) public theTopLevelPlayInfo;

//used to store actions taken to complete Play
struct PlayActionInfo  {
  bytes32   PlayTitle;       
  bytes32   PlayWorkerName;
  address   PlayWorkerAddress;
  bytes32   PlayAction;
  bytes32   PlayActionDescription;
  uint256   PlayActionTimestamp;
  bytes32   PlayStatus;
}
//the instance of the struct
PlayActionInfo [] play1;

//map into the Play action
mapping (uint => PlayActionInfo) public thePlayActionInfo;

//State variables for storage - do I need these  
// as state variables since they are also in a struct? 
uint    numUpdates;
address theOwnerAddress;

//will be used to ensure only owner closes Play when work is accepted
modifier onlyOwner(){
  if(msg.sender != theOwnerAddress) revert();
  _;
}

//constructor for contract
function Plays(bytes32 thisPlayOwnerName, bytes32 thisPlayTitle) public  {
    //establish the owner
    playi.PlayOwnerAddress = msg.sender;
    theOwnerAddress        = msg.sender;
    playi.PlayOwnerName    = thisPlayOwnerName;
    playi.PlayTitle        = thisPlayTitle;
}

//used to enter a new action against thePlay
function PlayUpdate(
      bytes32   PlayTitle,
      bytes32   PlayWorkerName,
      bytes32   PlayAction,
      bytes32   PlayActionDescription,
      bytes32   PlayStatus)
      public {
        play1.PlayTitle                          = PlayTitle;
        play1.PlayWorkerName[numUpdates]         = PlayWorkerName;
        play1.PlayWorkerAddress[numUpdates]      = msg.sender;
        play1.PlayAction[numUpdates]             = PlayAction;
        play1.PlayActionDescription[numUpdates]  = PlayActionDescription;
        play1.PlayActionTimestamp[numUpdates]    = block.timestamp;
        play1.PlayStatus[numUpdates]             = PlayStatus;

        //update the number of updates to this contract
        numUpdates++;
}
}

Thank you

1

It looks like a struggle with appropriate data structures so I reduced it a simple interpretation. Lots of hints.

pragma solidity ^0.4.18;

contract Play {

    address public playOwnerAddress;
    bytes32 public playOwnerName;
    bytes32 public playTitle;

    // actions taken to complete Play

    struct PlayActionStruct  {
        bytes32   playTitle;       
        bytes32   playWorkerName;
        address   playWorkerAddress;
        bytes32   playAction;
        bytes32   playActionDescription;
        bytes32   playStatus;
    }

    // append-only list of actions

    PlayActionStruct [] public playActions;

    event LogInsertPlayAction(
        bytes32   _playTitle,
        bytes32   _playWorkerName,
        bytes32   _playAction,
        bytes32   _playActionDescription,
        bytes32   _playStatus);

    modifier onlyOwner(){
        require(msg.sender == playOwnerAddress);
        _;
    }

    function Play(bytes32 thisPlayOwnerName, bytes32 thisPlayTitle) public  {
        playOwnerAddress = msg.sender;
        playOwnerName    = thisPlayOwnerName;
        playTitle        = thisPlayTitle;
    }

    function appendPlayAction(
        bytes32   _playTitle,
        bytes32   _playWorkerName,
        bytes32   _playAction,
        bytes32   _playActionDescription,
        bytes32   _playStatus)
        public
        onlyOwner // restricts to contract deployer
        returns(bool success)
    {
        // Consider adding a series of require() guards here to validate inputs

        PlayActionStruct memory p;
        p.playAction            = _playTitle;
        p.playWorkerName        = _playWorkerName;
        p.playWorkerName        = _playWorkerName;
        p.playWorkerAddress     = msg.sender;
        p.playAction            = _playAction;
        p.playActionDescription = _playActionDescription;
        p.playStatus            = _playStatus;
        playActions.push(p);

        LogInsertPlayAction(
            _playTitle,
            _playWorkerName,
            _playAction,
            _playActionDescription,
            _playStatus);
        return true;
    }

    function getActionCount() public view returns(uint count) {
        return playActions.length;
    }
}

There's always more than one way to do things, so this might give you some ideas: Are there well-solved and simple storage patterns for Solidity?

Hope it helps.

  • Thanks everyone, I will try the answers and accept. I'm still learning about appropriate data types for what I'm trying to do. – Jazzmine Oct 25 '17 at 10:10
  • I get what you did but it does generate a number of questions that will further help my understanding. 1) Since I am only going to have one instance of the play per contract, I can just make them stand-alone state variables without being part of a struct? 2) This: PlayActionStruct [] is saying I can have multiple instances of the struct PlayActionStruct? I don't understand this line: PlayActionStruct memory p;. Is it saying, the data passed into the function will just be kept in memory but since PlayActionStruct is a state variable (array), playActions will be put in storage? – Jazzmine Oct 26 '17 at 2:21
  • 3) I don't understand prefacing function input parameters with a _, is that a way to denote that it is an input parameter? 4) Finally, if I want to retrieve all the playActionsTitles, would I do this: function getPlayActionsTitles() public returns (bytes32[]){ //create array to hold a list of playActions.playTitle bytes32[] memory playActionTitleArray; for (uint i = 0; i < playActions.length; i++) { playActionTitleArray[i] = playActions[i].playTitle; } return PlayActionArray; } BTW, thank you very much! You helped alot. – Jazzmine Oct 26 '17 at 2:23
  • This is set up as one contract per play, with many actions, so the properties I thought we one-time things are set up without a struct, the array handles n actions. PlayActionStruct memory p cats p as type PlayActionStruct. After some stuff is worked out in memory, then it is pushed to storage. – Rob Hitchens - B9lab Oct 26 '17 at 3:02
  • Prefix with _ just differentiates some compiler warnings about "shadowing" identical variable names. Nothing special about that character. To enumerate the actions, a client could first interrogate the getAcountCount() function I added, then yes, for(i=0; i< count; i++) ... contract.playActions(i, {from: address}).then(function(response) { // the struct is returned as an array console.log(response); }) There is also an event emitter. An event listener is quite handy on the UI side. They fire a callback every time a mined event arrives. – Rob Hitchens - B9lab Oct 26 '17 at 3:07
1

You are defining play1 as an array of PlayActionInfo.

PlayActionInfo [] play1;

But then you are trying to assign:

play1.PlayTitle = PlayTitle;

So, you either define play1 as PlayActionInfo (Without the []) Or you should assign PlayTitle and the other parameters in PlayUpdate to an element of the play1 array:

play1.PlayTitle = PlayTitle;

Is play1 supposed to be an array or just 1 instance of PlayActionInfo struct? Depending on the answer, do one of the above changes.

  • Hi: I want play1 to be like the master record so there would only be 1, and then there would be multiple actions against that play. So for one play there would be multiple actions like Design Set, Rehearse Play, Install Lightning. So essentially a 1:Many relationship. Thanks – Jazzmine Oct 26 '17 at 2:04
  • Have a look here. Rabbit hole warning: medium.com/@robhitchens/… – Rob Hitchens - B9lab Oct 26 '17 at 2:58

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.