I want to grab my User out of the nested gameBoard array so that I can move it to a new index set of x and y. Remix IDE throws this error: TypeError: type struct Game.User storage ref[] storage ref is not implicitly convertible to expected type struct Game.User memory. I originally tried this without the memory, but not only does that go against the goal of not storing it permanently (if I understand it correctly), but also it threw less useful errors. Please help!
pragma solidity ^0.4.0;
contract Game {
struct User{
address owner;
uint currency;
uint left;
uint right;
uint top;
uint bottom;
}
User[][10][10] public gameBoard;
function addUser (uint _x, uint _y) public {
gameBoard[_x][_y].push(User(msg.sender, 10, 5, 5, 5, 5));
}
function moveUser (uint _fromX, uint _fromY, uint _toX, uint _toY) public {
User memory mover = gameBoard[_fromX][_fromY];
if (mover.owner != msg.sender)return;
// once I have 'mover', I will check whether
// I want its the msg.senders and then place
// it where I want it to go
}
}
Short Answer: You are indexing your array wrong, and need another set of [brackets].
So you created a 3 dimensional array of users called "gameboard". When adding a user you push a struct into the dynamic 3rd dimension of your array correctly. However when you access the structs, you only give two dimensions and so Solidity returns the dynamic user array. Since you are trying to store it into a struct rather than an array of structs the error is being thrown. The easiest way to fix it is to use:
User memory mover = gameBoard[_fromX][_fromY][0];
However this only returns the first user at that position on the game board so you'll probably need to do some sort of looping (which isn't ideal in contracts). Personally I prefer to stay away from multidimensional arrays, and honestly all arrays in general (although they have their uses) when working with Solidity. Mappings are usually a lot easier to work with, especially when working with addresses. Could you possibly elaborate on what you are attempting to do in case there is a better way of achieving it?
Related
I have a situation, where I have existing code that works with raw pointers, and I'm not permitted to smart-pointer-ify it. However, I am permitted to use smart pointers in any new code I develop.
For example.
I have an existing function like:
void processContent()
{
ContentObject * myContent = new ContentObject();
newFunction(myContent);
}
void newFunction(ContentObject * content)
{
// myVector is just a std::vector<ContentObject*>, defined elsewhere
myVector.push_back(content);
}
void doSomethingWithContent()
{
// There is some logic here, but ultimately based on this logic I want to remove entries, and free the memory they point to.
myVector.pop_back();
}
I have control over the content of "newFunction" and "doSomethingWithContent". But the argument passed into newFunction is fixed. Obviously I could manually delete the pointer in myVetor, before popping it, but I wondered if I can implement smart pointers here so that it happens "automatically" for me?
Can I take a raw pointer passed into a function, and turn it into a unique_ptr, then add this to a container, and have it delete the memory when it's popped from the container?
Thanks
Joey
Assume that you can define your myVector as the following:
std::vector<std::shared_ptr<ContentObject>> myVector;
In that case you can switch on smart pointers in your code and myVector will keep all your objects as you expected:
void newFunction(ContentObject * content)
{
myVector.push_back(std::shared_ptr<ContentObject>(content));
}
void doSomethingWithContent()
{
// There is some logic here, but ultimately based on this logic I want to remove entries, and free the memory they point to.
myVector.pop_back();
}
This code correctly compiles. It has a few unused code warnings, but that's okay for now.
use std::collections::BTreeMap;
enum Object<'a> {
Str(String),
Int(i32),
Float(f32),
Vector(Vec<&'a Object<'a>>),
Prim(fn(State) -> State)
}
struct State<'a> {
named: BTreeMap<String, &'a Object<'a>>,
stack: Vec<Object<'a>>
}
impl<'a> State<'a> {
fn push_int(&mut self, x: i32) {
self.stack.push(Object::Int(x));
}
}
fn main() {
println!("Hello, world!");
let obj = Object::Str("this is a test".to_string());
}
The important part of this code is push_int and stack: Vec<Object<'a>>.
I'm sort of trying to make a stack-based VM.
I want to pass the state to functions, which can take stuff off the stack, manipulate the stuff, and then put some stuff back on the stack; the named field is going to hold named objects.
I have a hunch that it would be better to have the stack represented as a Vec<&'a Object<'a>> instead.
The way I have it now, I fear I'm committing some inefficiency error. Is my hunch correct?
The second part of the problem is that I don't know how to get the vector of references version to work. Creating new value with the right lifetimes to push onto the stack is not working for me.
I'm a bit vague about this issue, so if I've been unclear, ask me questions to clear stuff up.
The reason you could not get it to work is that structs cannot have fields that refer to other fields. (See supporting links at the bottom.)
What you can do, is put all the Objects into your Vec, and have the HashMap contain the indices of the named elements it references.
struct State {
named: BTreeMap<String, usize>,
stack: Vec<Object>
}
I'd also remove all lifetimes from your example, as this can be done completely with owned objects.
enum Object {
Str(String),
Int(i32),
Float(f32),
Vector(Vec<Object>),
Prim(fn(State) -> State)
}
You can try out a working implementation in the Playground
Supporting links:
How to initialize struct fields which reference each other
using self in new constructor
How to design a struct when I need to reference to itself
How to store HashMap and its Values iterator in the same struct?
What lifetimes do I use to create Rust structs that reference each other cyclically?
How to store a SqliteConnection and SqliteStatement objects in the same struct in Rust?
Why can't I store a value and a reference to that value in the same struct?
https://stackoverflow.com/questions/33123634/reference-inside-struct-to-object-it-owns
Making a tile based game with a MVC design pattern. In my map model I have a 2D array of all of the game objects, so that deals with location. But I do have cases when an object needs to know its own location, such as range for a spell. Is it a good idea for the object to also store its own location? I see issues with both sides.
Object does not know its own location. Location data only stored in map. If I have a location I can find an object immediately. But to go from object to location I have to iterate through an array.
Object knows it own location. Location data stored in Map and Object. If I have an active object I can just pull the location right out of the object. But this may lead to inconsistency between the map array and the object's location. I am not sure to make sure one is not updated without changing the other. I could just have each controller (object and map) have a function for moving objects, and when one is called it looks to see if the other's model is consistent and updates it. However, this seems extremely inelegant.
I'd advise you to store the location in the GameObject and make sure the locations are consistent by using private fields and a single function to modify your locations. The location could be a private member of the GameObject, and the 2D array should be a private member of the Map-class. Then you define a function in the Map-class which allows you to move the object. This function should update the array as well as the location stored in the object. How you grant the Map class access to the GameObject's location depends on the programming language. In Java you could implement a package-private function (this is the default access level) and define the Map and GameObject in the same class, in C# you could define an internal function and define the Map and GameObject in the same assembly, in C++ you could make the Map.move function a friend of the GameObject, granting it access to the protected and private members of the GameObject.
The only downside of this approach, is that you could still accidentally modify the GameObject's location within the GameObject itself, without updating the array. If you want to prevent this, you could store the location of each object in a map/Dictionary in the Map-class. In C++ this would look roughly like this:
#include<map>
class GameObject {}; //don't store the location here
struct Location {
int x,y;
};
class Map {
private:
//the 2D array containing pointers to the GameObjects
GameObject* array[WIDTH][HEIGHT];
//a map containing the locations of all the GameObjects, indexed by a pointer to them.
std::map<GameObject*,Location> locations;
public:
//move an object from a given location to another
void move( int fromX, int fromY, int toX, int toY ) {
GameObject* obj = array[fromX][fromY;
array[toX][toY] = obj
array[fromX][fromY] = 0;
locations[obj].x = toX;
locations[obj].y = toY;
}
//move a given object to a location
void move( GameObject* obj, int toX, int toY ) {
Location loc = locations[obj];
move( loc.x, loc.y, toX, toY );
}
//get the location of a given object
Location getLocation( GameObject* obj ) const {
return locations[obj];
}
};
My struct class:
public struct PinAndRadius
{
public string pinID { get; set; }
public string radiusID { get; set; }
public string getPinID()
{
return pinID;
}
public string getRadiusID()
{
return radiusID;
}
}
the method with a problem:
void mapArea_VE_PinDragged(double latitude, double longitude, object id)
{
foreach (var pin in pinRadiusCollection)
{
string ID = id.ToString();
//string newID = ID.Substring(0, 18);
if (!pin.Key.pinID.Equals(ID))
{
continue;
}
else if (pin.Key.pinID.Equals(ID))
{
var newLoc = createNewSearchLocation(latitude, longitude);
mapArea.VE_DeleteRadius(pin.Key.radiusID);
drawPoly(newLoc, pin.Value.xar_Radius);
pin.Key.radiusID = pollyID;
break;
}
}
}
The problem is that when I try to set pin.key.radiusID to pollyID, I get an error saying
Cannot modify the return value of 'System.Collections.Generic.KeyValuePair.Key' because it is not a variable...
Any ideas?
Structure in .net is value-type. This mean you can't get reference to PinAndRadius using pin.Key. You will get copy of pin.Key of type PinAndRadius. Then you haven't access to this copy and compiler tell you about this. In C++ terms it not l-value.
If you create struct always try make it immutable. Mutable structs are evil.
Simplest way to solve this problem is to make PinAndRadius as class.
By the looks of it, your pinRadiusCollection is a generic dictionary keyed by PinAndRadius; the error you're getting is letting you know you can't modify that object because it's being used as the key in your dictionary.
If your pins are supposed to be mutable, you should probably revisit how you're storing them.
Collections in .net are not set up to allow convenient modification of struct-type items contained therein. Despite this, mutable structs still offer cleaner semantics than any other kind of data type. To edit a struct held in a collection, simply copy it to a variable, edit that variable, and store it back:
var temp = myList[someIndex];
temp.SomeVield = whatEver;
myList[someIndex] = temp;
Note that it's generally better to have mutable structs expose their contents as fields than as properties. Some people may say mutable structs are evil because their semantics differ from classes, but that's like saying screwdrivers are evil because they make lousy hammers. Exposed-field structs don't work like class types, but structs where all fields are exposed all have the same semantics as each other. Those semantics differ from classes, but for cases where they're useful, they have no equal.
Incidentally, much of the bad reps "mutable structs" got was a result of the fact that mutating struct members other than exposed fields would often generate bogus code if applied to read-only structures. If you avoid having struct members which modify fields of this [it's perfectly safe for static struct methods to modify fields of structures received as ref parameters], those dangers don't apply.
I simply just changed the struct definition to a class.
How do you use std.typecons.RefCounted!(T) to make a reference-counted object in D?
I've tried to figure out what std.array.Array does internally by looking at the source, but while I can read the source, I just can't figure what a "payload" is or how it all works when there's things like bitwise struct copying involved, as well as why some things are duplicated in the internal and external structure.
Could anyone provide an example or a link on how to use it to, say, wrap a simple Win32 HANDLE?
Thanks!
Disclaimer: I haven't tested my claims, just read the documentation.
Payload is referring to what is being stored. In your case the payload is the Win32 HANDLE. Since HANDLE is just an integer you wouldn't want to do:
auto refHandle = RefCounted!HANDLE(WhatGetsMeAHandle());
Because a Windows function will need to be called when the handle goes out of scope.
In std.containers.Array what you saw was a struct called Payload, which had a field called _payload. The structure is going to be the storage of the data, accessed through _payload. This provides a level of indirection to be utilized later.
You will notice that RefCounted is actually used on the Array structure. This means the destructor for that struct will only be called when the reference count is 0. So the ~this() inside of Payload is where you would want to clean up the your HANDLE.
What is happening: since struct is a value type, every time the structure goes out of scope the destructor is called, there isn't one for Array, but Payload is wrapped in a RefCounted, the destructor for RefCounted!Payload is also called. And only when the reference count reaches zero is the destructor for Payload itself called.
Now, RefCounted itself has reference semantics, this means that having an Array a, you can then assign to auto b = a; and everything will be copied over, but RefCounted has a postblits defined meaning the data will not be copied, but the reference count will be
incremented.
I will now try and provide you with a wrapper outline for what you want. It will probably help you visualize the information above, but it may not be entirely correct. Let me know if something needs fixing.
struct MyWinWrapper {
struct Payload {
HANDLE _payload;
this(HANDLE h) { _payload = h; }
~this() { freeHandleHere(_payload); }
// Should never perform these operations
this(this) { assert(false); }
void opAssign(MyWinWrapper.Payload rhs) { assert(false); }
}
private alias RefCounted!(Payload, RefCountedAutoInitialize.no) Data;
private Data _data;
this(HANDLE h) { _data = Data(h); }
}
Since there is no default constructor for a struct you will probably want to provide a free function that returns this structure.