Solidity Error: Struct containing a (nested) mapping cannot be constructed - compilation

My version of solc:
"solc": "^0.7.1",
When I try to construct a struct that contains mapping, I got this error:
"Struct containing a (nested) mapping cannot be constructed"
This is my solidity code.
Campaign.sol
contract Campaign {
struct Request {
...
// I guess this might cause an error
mapping(address => bool) approvals;
}
constructor(uint256 minimum, address creator) {
...
}
function createRequest(
string memory description,
uint256 value,
address payable recipient
) public onlyManager {
Request memory newRequest = Request({
// Here the compiler complains
});
}
...
If I want to put a mapping inside of my Request struct, is there any other way around?
Thank you

from 0.7.0 do like below:
struct Request{
string description;
uint value;
address recipient;
bool complete;
uint approvalsCount;
mapping(address => bool) approvals;
}
uint numRequests;
mapping (uint => Request) requests;
function createRequest (string memory description, uint value,
address recipient) public{
Request storage r = requests[numRequests++];
r.description = description;
r.value = value;
r.recipient = recipient;
r.complete = false;
r.approvalsCount = 0;
}

I think I find an answer here
I put the mapping outside of the struct, and the error is gone:
contract Campaign {
struct Request {
//...
}
mapping(address => bool) approvals;
I'm not sure it solves the problem totally. I'll update if there is another issue.

Related

Using Go generics to implement a chain of processors

I am trying to implement a kind of simple processing pipeline in Go, where each processor has a determined input and output type, and a list of successor processors that take current processor output type as input, and may have successor processors of their own.
I am running into issues on how to add successor processors to the current one, regardless of their output type. I tried using any as a wildcard type like I would do with ? in Java, but Go is not having it.
What I have in Go is this:
type Processor[InputType any, OutputType any] struct {
nextProcessors []*Processor[OutputType, any]
ProcessingFunction func(InputType) OutputType
}
func (b *Processor[InputType, OutputType]) Process(input InputType) {
result := b.ProcessingFunction(input)
for _, nextProcessor := range b.nextProcessors {
nextProcessor.Process(result)
}
}
func (b *Processor[InputType, OutputType]) AddOutputProcessor(p *Processor[OutputType, any]) {
b.nextProcessors = append(b.nextProcessors, p)
}
func main() {
outputer := Processor[int, string]{ProcessingFunction: func(input int) string {
print(input)
return string(input)
}}
doubler := Processor[int, int]{ProcessingFunction: func(input int) int { return input * 2 }}
rng := Processor[int, int]{ProcessingFunction: func(input int) int { return rand.Intn(input) }}
rng.AddOutputProcessor(&doubler)
doubler.AddOutputProcessor(&outputer)
rng.Process(20)
}
Which gives me a compilation error:
cannot use &doubler (value of type *Processor[int, int]) as type *Processor[int, any]
Is there a way to ignore the output type of the successor processor? Or should I maybe go a different way about it? I would just like to make sure that successor processors can accept the right type of input.
For reference, here is the interface definition in Java that works the way I intend it to.
public interface Processor<InputType, OutputType> {
void addOutputProcessor(Processor<OutputType, ?> outputProcessor);
void process(InputType input);
}
public class Pipeline {
private abstract class BaseProcessor<InputType, OutputType> implements Processor<InputType, OutputType> {
List<Processor<OutputType, ?>> nextProcessors = new ArrayList<>();
abstract OutputType processHelper(InputType input);
#Override
public void addOutputProcessor(Processor<OutputType, ?> outputProcessor) {
nextProcessors.add(outputProcessor);
}
#Override
public void process(InputType input) {
OutputType result = processHelper(input);
for (Processor<OutputType, ?> nextProcessor : nextProcessors) {
nextProcessor.process(result);
}
}
}
private class RandomNumberGenerator extends BaseProcessor<Integer, Integer> {
#Override
Integer processHelper(Integer input) {
int generatedNumber = new Random().nextInt(input);
return generatedNumber;
}
}
private class IncrementProcessor extends BaseProcessor<Integer, Integer> {
#Override
Integer processHelper(Integer input) {
return input + 1;
}
}
private class DoubleProcessor extends BaseProcessor<Integer, Integer> {
#Override
Integer processHelper(Integer input) {
return input * 2;
}
}
private class Outputer extends BaseProcessor<Integer, String> {
String name;
public Outputer(String name) {
this.name = name;
}
#Override
String processHelper(Integer input) {
String output = String.format("Pipeline %s result: %d", name, input);
System.out.println(output);
return output;
}
}
public void buildAndRunPipeline() {
Processor<Integer, String> doublingOutputter = new Outputer("Doubling");
Processor<Integer, String> incrementingOutputter = new Outputer("Incrementing");
Processor<Integer, String> rngOutputter = new Outputer("Generating number");
Processor<Integer, Integer> doubler = new DoubleProcessor();
doubler.addOutputProcessor(doublingOutputter);
Processor<Integer, Integer> incrementer = new IncrementProcessor();
incrementer.addOutputProcessor(incrementingOutputter);
Processor<Integer, Integer> starter = new RandomNumberGenerator();
starter.addOutputProcessor(rngOutputter);
starter.addOutputProcessor(doubler);
starter.addOutputProcessor(incrementer);
starter.process(20);
}
public static void main(String[] args) {
Pipeline p = new Pipeline();
p.buildAndRunPipeline();
}
}
Is there a way to ignore the output type of the successor processor?
No.
In Go any is just a static type (alias of interface{}. It can never be a replacement for Java's unbounded wildcard ?. So *Processor[int, any] is just not the same type as *Processor[int, int] and you can't assign one to the other, as reported by your error message.
In order to construct an arbitrarily long chain you would need to parametrize the Process method itself, but this is not possible in Go 1.18. You must declare all type parameters on the type itself. Though, even if you do this, you will keep incurring in the same issue of not knowing the output type of the next processor.
Generally speaking, using a for loop can't work because the static types of the in/out values keep changing.
I believe the closest you can get without reflection is to implement some sort of composition operator — like . in haskell, via a top-level function. But you would have to manually nest calls.
A simplified example (the type Processor is redundant, but keeping it closer to your code):
package main
import (
"fmt"
"strconv"
)
type Processor[In, Out any] func(In) Out
func Process[In, Out any](input In, processor Processor[In, Out]) Out {
return processor(input)
}
func main() {
parser := Processor[string, int](func(input string) int { s, _ := strconv.Atoi(input); return s })
doubler := Processor[int, int](func(input int) int { return input * 2 })
outputer := Processor[int, string](func(input int) string { return fmt.Sprintf("%d", input) })
out := Process(Process(Process("20", parser), doubler), outputer)
fmt.Println(out)
}
Playground: https://go.dev/play/p/Iv-virKATyb
You can't use any keyword to instantiate the value of generic type.
nextProcessors []*Processor[OutputType, any] // keyword any is not a valid type here
You can actually, but the second parameter always should be interface{}. But it's not a part of answer to your question.
To solve your issue you can use generic interface instead
type IProcess[InputType any] interface {
Process(input InputType)
}
type Processor[InputType any, OutputType any] struct {
nextProcessors []IProcess[OutputType]
ProcessingFunction func(InputType) OutputType
}
func (b *Processor[InputType, OutputType]) AddOutputProcessor(p IProcess[OutputType]) {
b.nextProcessors = append(b.nextProcessors, p)
}
https://go.dev/play/p/B1wlOvSbb0I

Member "add" not found or not visible after argument-dependent lookup in struct Chainlink.Request memory

I am creating nft smart contract and using chainlinkClient.sol for updation of URI.
chainlinkClient Version: v0.6
Error: TypeError: Member "add" not found or not visible after argument-dependent lookup in struct Chainlink.Request memory.
Any Idea Why am I getting this error?
Code:
// SPDX-License-Identifier: MIT
pragma solidity >=0.6.0 <0.9.0;
import "chainlink/evm-contracts/src/v0.6/ChainlinkClient.sol";
contract phoneNumber is ChainlinkClient{
uint256 public phone_no;
address private oracle;
bytes32 private jobId;
uint256 private fee;
constructor(uint256 _initial_phone_no){
setPublicChainlinkToken();
oracle = 0x7AFe1118Ea78C1eae84ca8feE5C65Bc76CcF879e;
jobId = "6d1bfe27e7034b1d87b5270556b17277";
fee = 0.1 * 10 ** 18; // 0.1 LINK
phone_no = _initial_phone_no;
}
function requestVolumeData() public returns (bytes32 requestId)
{
Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.update_phone_no.selector);
// Set the URL to perform the GET request on
request.add("get", "http://localhost:3000/images/phone.json");
request.add("path", "phone.new");
// Multiply the result by 1000000000000000000 to remove decimals
int timesAmount = 10**18;
request.addInt("times", timesAmount);
// Sends the request
return sendChainlinkRequestTo(oracle, request, fee);
}
function update_phone_no(bytes32 _requestId, uint256 new_phone_no) public recordChainlinkFulfillment(_requestId)
{
phone_no = new_phone_no;
}
function withdrawLink() external {
LinkTokenInterface linkToken = LinkTokenInterface(chainlinkTokenAddress());
require(linkToken.transfer(msg.sender, linkToken.balanceOf(address(this))), "Unable to transfer");
}
}
Your import statement is missing an "#" symbol. Add it to the beginning like this:
import "#chainlink/contracts/src/v0.6/ChainlinkClient.sol";
Note: Also don't forget to explicitly state your constructor visibility specifier to public or internal as well.

If the data type changes from string to bool data store is throwing an error

I am storing my struct values in google data store. Here is my struct:
type Appointment struct {
ID string
Appointment Date string
Start Time string
End Time string
Select Specialization string
Smoking Status string
}
I have stored some data using datastore, but later changed the data type from string to bool for the field "Smoking Status" then the data store is throwing an error:
{"error":{"message":"data store: cannot load field \"Smoking Status\" into a \"simplysthealth.Encounter\": type mismatch: string versus bool"}}
Is there any feasible solution for this?
package main
// I have corrected all of your method names
type Appointment struct {
ID string
AppointmentDate string
StartTime string
EndTime string
SelectSpecialization string
SmokingStatus string
}
type AllOldData struct {
Data []Appointment
}
type FixedAppointment struct {
ID string
AppointmentDate string
StartTime string
EndTime string
SelectSpecialization string
SmokingStatus bool
}
type FixedData struct {
Data []FixedAppointment
}
func TypeFixing() FixedData {
var OldData AllOldData
var NewData FixedData
OldData = GetYourAllOldData()
for i, v := range OldData.Data {
if v.SmokingStatus == "true" {
// other value exchanging
NewData.Data[i].SmokingStatus = true
} else {
// other value exchanging
NewData.Data[i].SmokingStatus = false
}
}
return NewData // Save the data in a new table or whatever you call it
}
func GetYourAllOldData() AllOldData {
// A function that returns all old data
return AllOldData{} // You must return return your all data
}
This is what you need to do it manually!

Return enum type based on string value in swift?

I'm trying to do the following in a playground to assign an enum type based on a string, but getting an error in the changeType function. How can I get this to work properly?
enum TransactionType {
case purchase,charge
case deposit,payment
func description() -> String {
switch self {
case .purchase:
return "purchase"
case .charge:
return "charge"
case .deposit:
return "deposit"
case .payment:
return "payment"
}
}
func typeFromString(value:String) -> TransactionType {
switch value {
case "charge":
return .charge
case "deposit":
return .deposit
case "payment":
return .payment
default:
return .purchase
}
}
}
class Tester {
var transactionType = TransactionType.purchase
func changeType() {
transactionType = TransactionType.typeFromString("charge")
}
}
var tester = Tester()
print(tester.transactionType.description())
tester.changeType()
print(tester.transactionType.description())
The solution is simpler than you think:
enum TransactionType : String {
case purchase = "purchase", charge = "charge"
case deposit = "deposit", payment = "payment"
}
class Tester {
var transactionType = TransactionType.purchase
func changeType() {
transactionType = TransactionType.fromRaw("charge")!
}
}
var tester = Tester()
print(tester.transactionType.toRaw())
tester.changeType()
print(tester.transactionType.toRaw())
The trick is to set a raw value of String type, which defines the type associated to each enum case.
More info Raw Values in Enumerations
You can define the typeFromString method as static in order to avoid complications with optional values. After all, it just contains constants anyway. Simply add the word static before the func definition.
static func typeFromString(value:String) -> TransactionType {

How do I specify the field in an object to update with a string or some other pointer c#

I'm just learning visual c# in visual studio
Ok, so I have a ton of data fields in a form, and then I want to write the handlers to all call one main method, update, which then updates a resultsEntry object, which encapsulates a bunch of uint variables with various names.
How do I write an update method to put in either the results object, or the update method that will take the name of the variable in resultsEntry as a string, and the integer to update it with, and then update that field.
Basically, I need to do a
resultsEntry.(inStringHere) = inValueHere;
where resultsEntry is the object being updated, the inStringHere specifies the field to be updated, and the inValueHere represents the integer value to assign to it.
Thanks!
Sam French
You have two challenges,
Setting a field/property in class using a string (the focus of your question). This will be accomplished using reflection.
Converting values to the type in your class (this may not be a problem for you, you may have 'typed' values. I have an ugly solution because this is not the main focus of your question.
Setting a property by name (see comments preceded with '**'):
static class Program
{
// A 'ResultEntry' type
public class ResultEntry
{
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
static void Main()
{
// some tuples Field1 = Property Name; Field2 = Raw Value (string)
List<Tuple<string, string>> rawEntries = new List<Tuple<string, string>>() {
new Tuple<string,string>("ID", "1")
, new Tuple<string, string>("FirstName", "George")
, new Tuple<string, string>("LastName", "Washington")
};
ResultEntry resultEntry = new ResultEntry();
// ** Get MemberInfo's for your ResultEntry. Do this once, not for each instance of ResultEntry!
MemberInfo[] members = resultEntry.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
// Iterate over input
foreach (var raw in rawEntries)
{
// find a MemberInfo (PropertyInfo) that matches your input 'PropertyName'
MemberInfo member = members.FirstOrDefault(m => m.MemberType == MemberTypes.Property && m.Name == raw.Item1);
if (member != null)
{
// if you input is typed you will not have to deal with
// conversion of the string to the actual type of the property
object val = raw.Item2.MyConverter(((PropertyInfo)member).PropertyType);
// ** set the value in 'ResultEntry'
((PropertyInfo)member).SetValue(resultEntry, val, null);
}
}
Console.WriteLine(string.Format("Result Entry: ID = {0}, FirstName = {1}, LastName = {2}", resultEntry.ID, resultEntry.FirstName, resultEntry.LastName));
Console.ReadLine();
}
}
If you need to deal with converting raw string input to type (e.g. string to int), then is just one strategy...
public static class Extensions
{
public static object MyConverter(this string rawValue, Type convertToMe)
{
// ugly, there are other strategies
object val;
if (convertToMe == typeof(Int32))
val = Convert.ToInt32(rawValue);
// ... add other type conversions
else
val = rawValue;
return val;
}
}
Hope this helps.

Resources