Use a variable to access key in struct - struct

I have a struct like so :
struct test {
string a;
string b;
}
and a mapping like this:
mapping (address => test) public tests;
I want to have a function to update the struct like this:
function updateStruct (string _paramName, string _newValue) {
tests[msg.sender].(_paramName) = _newValue; // this is the line that shows the logic but doesn't work in compilation
}
How can I do this?

Solidity currently (v0.8) does not support accessing properties via magic variables.
You'll need to access the properties directly.
function updateStructA(string memory _newValue) public {
tests[msg.sender].a = _newValue;
}
function updateStructB(string memory _newValue) public {
tests[msg.sender].b = _newValue;
}

Related

Const struct in D

I am trying to pass a struct as a compile time argument to a function.
I think the code is self explanatory. I am fairly certain that this should work. But I don't know why it won't work.
void main(string[] args)
{
const FooStruct fooStruct = FooStruct(5);
barFunction!fooStruct();
}
public struct FooStruct()
{
private const int value_;
#property int value() { return value_; }
this(int value) const
{
value_ = value;
}
}
public static void barFunction(FooStruct fooStruct)
{
fooStruct.value; /// do something with it.
}
public struct FooStruct()
Here, you're declaring FooStruct to be a templated struct, with no variables. If that's what you want, you'll need to refer to FooStruct!() on this line:
public static void barFunction(FooStruct fooStruct)
Since FooStruct takes no template arguments, there's not really any need for it to be templated, and you should probably declare it like this:
public struct FooStruct
When you do that, the error message changes to constructor FooStruct.this (int value) const is not callable using argument types (int). That's because you're invoking the mutable constructor. To fix that, change line 3 to read const FooStruct fooStruct =constFooStruct(5);.
Finally, when you call barFunction, you are attempting to pass fooStruct as a template parameter (barFunction!fooStruct()). Since barFunction is not a templated function, this fails. You probably meant barFunction(fooStruct).

In Haxe, how do you pass Enum values in functions, and then convert them to Strings within the function?

I can't seem to get this working, but I'd be surprised if it wasn't possible in Haxe.
I'm trying to pass a couple of Enum values defined in my game to a function, so that it can then concatenate them as String types and pass that to other functions.
Example:
// In a general Entity class:
public override function kill():Void {
messages.dispatchCombined(entityType, ListMessages.KILLED);
super.kill();
}
And in my Messages.hx class:
package common;
import msignal.Signal.Signal1;
/**
* A Message / Event class using Signals bound to String names.
* #author Pierre Chamberlain
*/
class Messages{
var _messages:MessagesDef;
public function new() {
_messages = new MessagesDef();
}
public function add(pType:String, pCallback:FuncDef) {
if (_messages[pType] == null) {
_messages[pType] = new Signal1<Dynamic>();
}
var signals = _messages[pType];
signals.add( pCallback );
}
public function dispatch(pType:String, pArg:Dynamic):Bool {
var signals = _messages[pType];
if (signals == null) return false;
signals.dispatch(pArg);
return true;
}
//Compiler doesn't like passing enums :(
public inline function addCombined(pSource:Enum, pEvent:Enum, pCallback:FuncDef) {
add( combine(pSource, pEvent), pCallback );
}
public inline function dispatchCombined(pSource:Enum, pEvent:Enum, pArg:Dynamic):Bool {
return dispatch( combine(pSource, pEvent), pArg);
}
//How can I just pass the enum "names" as strings?
static inline function combine(a:Enum, b:Enum):String {
return String(a) + ":" + String(b);
}
}
typedef MessagesDef = Map<String, Signal1<Dynamic>>;
typedef FuncDef = Dynamic->Void;
Note how addCombined, dispatchCombined and combine expect an "Enum" type, but in this case I'm not sure if Haxe actually expects the entire Enum "class" to be passed (ie: ListMessages instead of ListMessages.KILLED) or if a value should work. Anyways, compiler doesn't like it - so I'm assuming another special Type has to be used.
Is there another way to go about passing enums and resolving them to strings?
I think you need EnumValue as parameter type (if it is only for enum values), and use Std.String to convert to String values.
static inline function combine(a:EnumValue, b:EnumValue):String {
return Std.string(a) + ":" + Std.string(b);
}
Of course that can be written smaller using String interpolation:
static inline function combine(a:EnumValue, b:EnumValue):String {
return '$a:$b';
}
Of course that can be 'more dynamic' using type parameters:
static inline function combine<A, B>(a:A, b:B):String {
return '$a:$b';
}
There is totally no need to use Dynamic as suggested. If you use Dynamic, you basically turn off the type system.
live example:
http://try.haxe.org/#a8844
Use Dynamic instead of Enum or pass them as Strings right away since you can always convert to enum from String if you need it later.
Anyway pass the enum as enum:Dynamic and then call Std.string(enum);
EDIT: Using EnumValue is definitely better approach than Dynamic, I use Dynamic in these functions because I send more than just Enums there and I am not worried about type safety in that case.

JNA non-const String member of struct

I have a C function that expects a struct that contains a non-const String.
typedef struct _A {
char* str;
} A;
void myFunc(A* aptr) { ... }
I've tried for a long time to pass this thing via JNA but didn't manage so far.
public class A extends Structure {
public String str;
protected List getFieldOrder() { ...
}
doesn't work because String will be turned into a const char* instead of char* which I need.
public class A extends Structure {
public byte[] str;
protected List getFieldOrder() { ...
}
doesn't work because the byte array inside a struct gets turned into contiguous memory and not a pointer.
I know I can do it by using Memory and copying the String over. But I can't imagine that this is the preferred way to do it.
I also tried something like
public class NonConstStringMember extends Structure {
public static class ByReference extends NonConstStringMember implements Structure.ByReference {}
public byte[] stringMember;
protected List getFieldOrder() { ...
}
public class A extends Structure {
public NonConstStringMember.ByReference str;
}
but it doesn't work either, maybe because of alignment issues.
What is the preferred way to do this with JNA?
Assuming you want this to point to an arbitrary buffer which you may write to, use Pointer (and assign it a Memory value if you're allocating the buffer).
You then use Pointer.getString(0) or Pointer.setString(0, s) to manipulate the buffer contents.
EDIT
Windows libraries usually have an ascii or unicode version of most functions. While in most cases you can define a single Structure for use in both cases, sometimes you need to provide a little additional handling to ensure the correct types are used. Since the two modes are rarely, if ever, used simultaneously, JNA sets up options to default to one or the other (automatically mapping to the right function suffix, and automatically mapping String to either native const char* or const wchar_t* depending on the mode).
Use setWideString() if using unicode mode and setString() otherwise, or make some accessors on your Structure to handle that for you automatically. For example:
class MyStructure extends Structure {
private static final boolean ASCII = Boolean.getBoolean("w32.ascii");
public Pointer stringBuffer = new Memory(X);
void setStringBuffer(String s) {
stringBuffer.setString(0, s, ASCII);
}
String getStringBuffer() {
return stringBuffer.getString(0, ASCII);
}
}
EDIT
Please note that in most cases you should use a String as the field type and rely on a TypeMapper to use WString behind the scenes where appropriate (e.g. User32 and W32APIOptions.DEFAULT_OPTIONS).

Casting Dynamic to an other class

I would like to know if that's possible to cast a Dynamic to an other class (partially or totally)
For example, this code breaks :
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = cast(x, Test);
}
}
with the following message
Class cast error
However, my "Test" class has an "id" field like the dynamic object. (That's an example, my use case is more complexe than that ^^)
So, I don't understand how to get an object from my Dynamic one.
This isn't exactly casting a dynamic to a class instance but may accomplish the same thing:
create an empty instance of the class with Type.createEmptyInstance
set all of the fields from the Dynamic object on the new class instance using Reflect
Example:
import haxe.Json;
class Test {
public function new() {}
public var id: String;
}
class Main {
public static function main() {
var x:Dynamic = Json.parse("{\"id\":\"sdfkjsdflk\"}");
var t:Test = Type.createEmptyInstance(Test);
for (field in Type.getInstanceFields(Test))
if (Reflect.hasField(x, field))
Reflect.setProperty(t, field, Reflect.getProperty(x, field));
trace(t.id);
}
}
You could use typedef
typedef Test = {
public var id: String;
}
class Main {
public static function main() {
var t:Test = JsonParser.parse("{\"id\":\"sdfkjsdflk\"}");
}
}
Json.parse returns anonymous structure(implementation platform dependent), typed as Dynamic. There isn't a single chance to cast it to anything but Dynamic, unless Json.parse returns Int, Float or String, which some parsers permit, but which isn't actually permitted by JSON specification.
That is this way because, the operation of casting doesn't check what fields some object have. Operation of casting only checks if the object is an instance of class you are casting to. Obviously, anonymous structure can't be an instance of any class(inside haxe abstractions at least).
However, the right way to perform the thing you seem to be trying to perform is the way stated by #Ben Morris, in his answer.

Can extension methods modify extended class values?

I was just trying to code the following extension method:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace _4Testing
{
static class ExtensionMethods
{
public static void AssignMe(this int me, int value)
{
me = value;
}
}
}
But it is not working, i mean, can I use an extension method to alter values from extended classes? I don't want to change void return type to int, just changing extended class value. Thanks in advance
Your example uses int, which is a value type. Classes are reference types and behaves a bit differently in this case.
While you could make a method that takes another reference like AssignMe(this MyClass me, MyClass other), the method would work on a copy of the reference, so if you assign other to me it would only affect the local copy of the reference.
Also, keep in mind that extension methods are just static methods in disguise. I.e. they can only access public members of the extended types.
public sealed class Foo {
public int PublicValue;
private int PrivateValue;
}
public static class FooExtensions {
public static void Bar(this Foo f) {
f.PublicValue = 42;
// Doesn't compile as the extension method doesn't have access to Foo's internals
f.PrivateValue = 42;
}
}
// a work around for extension to a wrapping reference type is following ....
using System;
static class Program
{
static void Main(string[] args)
{
var me = new Integer { value = 5 };
int y = 2;
me.AssignMe(y);
Console.WriteLine(me); // prints 2
Console.ReadLine();
}
public static void AssignMe(this Integer me, int value)
{
me.value = value;
}
}
class Integer
{
public int value { get; set; }
public Integer()
{
value = 0;
}
public override string ToString()
{
return value.ToString();
}
}
Ramon what you really need is a ref modifier on the first (i.e. int me ) parameter of the extension method, but C# does not allow ref modifier on parameters having 'this' modifiers.
[Update]
No workaround should be possible for your particular case of an extension method for a value type. Here is the "reductio ad absurdum" that you are asking for if you are allowed to do what you want to do; consider the C# statement:
5.AssignMe(10);
... now what on earth do you think its suppose to do ? Are you trying to assign 10 to 5 ??
Operator overloading cannot help you either.
This is an old post but I ran into a similar problem trying to implement an extender for the String class.
My original code was this:
public static void Revert(this string s)
{
char[] xc = s.ToCharArray();
s = new string(xc.Reverse());
}
By using the new keyword I am creating a new object and since s is not passed by reference it will not be modified.
I changed it to the following which provides a solution to Ramon's problem:
public static string Reverse(this string s)
{
char[] xc = s.ToCharArray();
Array.Reverse(xc);
return new string(xc);
}
In which case the calling code will be:
s = s.Reverse();
To manipulate integers you can do something like:
public static int Increment(this int i)
{
return i++;
}
i = i.Increment();

Resources