Solidity - ParserError: Expected primary expression when using var - mapping

I am trying to create a struct and add mapping in such a way that it can be retrieved later on using its address using the below code.
pragma solidity ^0.8.0;
contract Courses {
struct Instructor {
uint age;
string fName;
string lName;
}
mapping (address => Instructor) instructors;
address[] public instructorAccts;
function setInstructor(address _address, uint _age, string _fName, string _lName) public {
var instructor = instructors[_address]; //ERROR HERE
instructor.age = _age;
instructor.fName = _fName;
instructor.lName = _lName;
instructorAccts.push(_address) -1;
}
}
However, I am getting an error at the line var instructor = instructors[_address]
The error is ParserError: Expected primary expression
I am unable to understand what the issue is and how to resolve it. Could anyone help with this?

Solidity uses typed variables, doesn't have the generic var keyword (that is used in JavaScript for example).
When declaring reference types (in your case string and struct), you need to specify their data location - in your case memory for the string argument. And either memory or storage for the struct depending on whether you want to set the values just in the context of the setInstructor() function (location memory), or if you want to set its values in the contract storage (location storage).
function setInstructor(address _address, uint _age, string memory _fName, string memory _lName) public {
// either `memory` or `storage` depending on your use case
Instructor storage instructor = instructors[_address];
// ... rest of your code
There also is a syntax error on this line
instructorAccts.push(_address) -1;
you can fix it by removing the -1
instructorAccts.push(_address);

Related

Initialization error when creating an object

When I compile the following code:
class Student {
int id;
Student() {
this.id = 12345;
}
}
void main() {
var student1 = new Student();
}
I get the following error:
Error: Field 'id' should be initialized because its type 'int' doesn't
allow null.
But why do I get this error? I did initialize id in the constructor!
In Dart, the creation of objects are split into two phases:
Initialization of all values.
Execution of constructor body.
So when you are running code inside the constructor body (between the {...} in the constructor definition) then all class defined variables must have been provided a default value that is valid for the type of variable.
In your case, the variable is typed int but are not provided a default value. In Dart, all variable will by default be set to null in case of no other value provided. But since int is a non-nullable type it does not allow null to be a value and the compiler are therefore giving you the error.
The solution are to provide a value before the constructor is running. You can do that like this:
class Student {
int id;
Student() : id = 12345;
}
Or:
class Student {
int id = 12345;
Student(); // The constructor can in theory just be removed here
}
In case you cannot define a value as part of the initialization phase, you can (but should be prevented if possible) mark the variable as late which makes it so you promise, the Dart compiler, that you are going to provide a value for the variable before the first time you are trying to read from that variable:
class Student {
late int id;
Student() {
this.id = 12345;
}
}
In case you are trying to read from id before it have been provided a value, the program will crash with a LateInitializationError at runtime.
And at last, you can set the type to be a nullable type, like int?, to allow the variable to have a default value of null. But doing so will require you to check for null when you are trying to do something with the value in a context where null is not allowed:
class Student {
int? id;
Student() {
this.id = 12345;
}
}

`nameof` operator in flutter

There is nameof operator in C#, it allows to get property name at compile time:
var name = nameof(User.email);
Console.WriteLine(name);
//Prints: email
It is not possible to use reflection in flutter and I do not want to hardcode names of properties i.e. to be used for querying SQLite tables. Is there any workaround?
***Currently I'm using built_value library.
For the archives, I guess, this isn't possible as Dart doesn't store the names of variables after compiling, and as you mentioned, Flutter doesn't support reflection.
But you can still hardcode responsibly by grouping your properties as part of the object that they belong to, like with JSON:
class User {
final String email;
final String name;
const User({required this.email, required this.name});
Map toJson() => {
"email": email,
"name": name,
};
}
Instead of remembering to type out "email" and "name" whenever you use User, just call User.toJson(). Then, when you want to rename your variables, you can use your IDE's "rename all", or just skim over your User class to quickly change all of the names without missing any.
I'm currently monitoring the progress on the dart:mirrors package, which offers some neat reflective properties and methods, though, I hadn't found a simple way to just get the name of a symbol like nameof() does.
Example:
import 'dart:mirrors';
class User {
final String email;
final String name;
const User({required this.email, required this.name});
}
void main() {
reflectClass(User).declarations.forEach((key, value) {
print(value.simpleName);
});
}
Output:
Symbol("email")
Symbol("name")
Symbol("User")
These are of type Symbol.
More here: https://api.dart.dev/stable/2.4.0/dart-mirrors/dart-mirrors-library.html
So, until they develop a nameof, I've created an extension on symbol:
extension SymbolExtensions on Symbol {
String get nameof =>
RegExp(r'"(.*?)"').firstMatch(toString())!.group(1).toString();
}
So, you could do:
print(reflectClass(User)
.declarations[#email)]!
.simpleName
.nameof);
Output:
email
It's a start. Dart is still growing.
You can use code generation.
The basic idea is to create a nameof annotation class and mark parts of your code with it. You also need to create a code generator that handles your annotated code. Look at the json_serializable package for an example and create your own code generator.
If you do not want to create your own generator, use a ready-made package nameof: https://pub.dev/packages/nameof
Short how-to with this package.
Mark your class with nameof annotation.
#nameof
class Car {
final double price;
final double weigth;
final int year;
final String model;
Car(this.price, this.weigth, this.year, this.model);
Car.sedan(double price, double weigth, int year)
: this(price, weigth, year, 'Sedan');
}
Run the code generator.
flutter pub run build_runner build
Then use the generated class, which will look something like this.
/// Container for names of elements belonging to the [Car] class
abstract class NameofCar {
static const String className = 'Car';
static const String constructor = '';
static const String constructorSedan = 'sedan';
static const String fieldPrice = 'price';
static const String fieldWeigth = 'weigth';
static const String fieldYear = 'year';
static const String fieldModel = 'model';
}
You can implement your own nameOf function:
String? nameOf(dynamic o) {
if (o == null) return "null";
try {
if (o is List) {
var first = o.length > 0 ? o[0] : null;
if (first != null) {
var elementType = nameOf(first)!;
Log.debug("nameOf: List<$elementType>");
if (!isMinified(elementType))
return "List<$elementType>";
}
} else {
Function? getTypeName = o.getTypeName;
if (getTypeName != null) return getTypeName();
}
} catch (e) {
Log.debug("ignored nameOf error: $e, falling back to o.runtimeType: ${o.runtimeType}");
}
return o.runtimeType.toString();
}
bool isMinified(String type) => type.startsWith("minified:");

Get pointer to a struct from a Dart_NativeArguments struct in C

I'm trying to wrap a C library using Dart. I call into a C function from dart and pass in the arguments through a Dart_NativeArguments struct in C:
void _sayHello(Dart_NativeArguments arguments) {
string from;
Dart_Handle seed_object = HandleError(Dart_GetNativeArgument(arguments, 0));
if (Dart_IsString(seed_object)) {
const char* seed;
HandleError(Dart_StringToCString(seed_object, &seed));
from = seed;
}
num = (int)Dart_GetNativeArgument(arguments, 1);
Dart_SetReturnValue(arguments, HandleError(Dart_NewStringFromCString(sayHello(from, num).c_str())));
}
In Dart, I call the function and pass in the necessary arguments
String sayHello(String from) native "sayHello";
main() {
print(sayHello("Dart"));
}
I was wondering how I could pass in pointers (to a struct I made) instead of just strings and ints as arguments. There are functions in Dart to convert Dart_Handles into Strings and ints but not pointers. What is the internal structure of the Dart_Handle and how would I go about converting it back to a pointer? For example:
Dart code:
String sayHello(info from) native "sayHello";
class info
{
String message;
int num;
}
main() {
info tester = new info();
tester.message = "Dart";
tester.num = 2;
print(sayHello(tester));
}
C Code:
void sayHello(Dart_NativeArguments arguments) {
/*What do I do here to get back a pointe to the struct/class I passed
in as an argument in Dart?*/
}
Your Dart_NativeArguments will consist of just one item, which will be an instance - the instance of the class info that you created with new info(). You can test whether it's an instance with bool Dart_IsInstance(Dart_Handle object). So what you have is an handle to an instance of info. This allows you to access its instance fields (message and num) to get and set them, using Dart_GetField and Dart_SetField.
Dart_Handle instance = Dart_GetNativeArgument(arguments, 0);
Dart_Handle message_handle = Dart_GetField(retobj, NewString("message"));
char* message;
Dart_StringToCString(message_handle, &message);
Dart_Handle number_handle = Dart_GetField(retobj, NewString("num"));
int64_t number;
Dart_IntegerToInt64(number_handle, &number);
// message contains the string, number contains the number
// use them, copy them etc
I know this is just an example, but it might be easier to redefine sayHello to take 2 arguments (a string and an int) rather than passing an object instance. There isn't a way to access the fields of a class in one step, you need to access them individually. Consider these two versions of the Dart code, one passing an object instance and one just the values. The second version is simpler at the Dart and C side (no GetField steps). The first version is more powerful, though, because you could update the fields using SetField, which you couldn't in the second.
class Info {
String message;
int num;
Info(this.message, this.num);
}
version1() {
sayHelloV1(new Info('Dart', 2));
}
version2() {
sayHelloV2('Dart', 2);
}
If your C API requires you to pass in a struct you will have to create that in your C code by copying the values you extract using Dart_IntegerToInt64etc into it, then pass the pointer to your C struct to the API.
If your API is very precise about the packing/padding of the data into the struct, you could use Dart typed_data to pack the Dart types into a ByteData and pass the underlying byte array.

F# - POCO Class

Hey there! I'm trying to write a POCO class in proper F#... But something is wrong..
The C# code that I want to "translate" to proper F# is:
public class MyTest
{
[Key]
public int ID { get; set; }
public string Name { get; set; }
}
The closest I can come to the above code in F# is something like:
type Mytest() =
let mutable _id : int = 0;
let mutable _name : string = null;
[<KeyAttribute>]
member x.ID
with public get() : int = _id
and public set(value) = _id <- value
member x.Name
with public get() : string = _name
and public set value = _name <- value
However when I try to access the properties of the F# version it just returns a compile error saying
"Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."
The code thats trying to get the property is a part of my Repository (I'm using EF Code First).
module Databasethings =
let GetEntries =
let ctx = new SevenContext()
let mydbset = ctx.Set<MyTest>()
let entries = mydbset.Select(fun item -> item.Name).ToList() // This line comes up with a compile error at "item.Name" (the compile error is written above)
entries
What the hell is going on?
Thanks in advance!
Your class definition is fine, it's your LINQ that has a problem. The Select method is expecting an argument of type Expression<Func<MyTest,T>> but you're passing it a value of type FSharpFunc<MyTest,T> - or something similar to that anyway.
The point is you can't use F# lambda expressions directly with LINQ. You need to write your expression as an F# Quotation and then use the F# PowerPack to run the code against an IQueryable<> data source. Don Syme has a good overview of how this works.

Why do I get a "Null value was assigned to a property of primitive type setter of" error message when using HibernateCriteriaBuilder in Grails

I get the following error when using a primitive attribute in my grails domain object:
Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
org.hibernate.PropertyAccessException: Null value was assigned to a property of primitive type setter of MyDomain.myAttribute
at grails.orm.HibernateCriteriaBuilder.invokeMethod(HibernateCriteriaBuilder.java:1077)
According to this SO thread, the solution is to use the non-primitive wrapper types; e.g., Integer instead of int.
A null value cannot be assigned to a primitive type, like int, long, boolean, etc. If the database column that corresponds to the field in your object can be null, then your field should be a wrapper class, like Integer, Long, Boolean, etc.
The danger is that your code will run fine if there are no nulls in the DB, but will fail once nulls are inserted.
And you can always return the primitive type from the getter. Ex:
private Integer num;
public void setNum(Integer i) {
this.num = i;
}
public int getNum() {
return this.num;
}
But in most cases you will want to return the wrapper class.
So either set your DB column to not allow nulls, or use a wrapper class.
A primitive type cannot be null. So the solution is replace primitive type with primitive wrapper class in your tableName.java file.
Such as:
#Column(nullable=true, name="client_os_id")
private Integer client_os_id;
public int getClient_os_id() {
return client_os_id;
}
public void setClient_os_id(int clientOsId) {
client_os_id = clientOsId;
}
reference http://en.wikipedia.org/wiki/Primitive_wrapper_class to find wrapper class of a primivite type.
I'll try to make you understand with the help of an example. Suppose you had a relational table (STUDENT) with two columns and ID(int) and NAME(String). Now as ORM you would've made an entity class somewhat like as follows:-
package com.kashyap.default;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
/**
* #author vaibhav.kashyap
*
*/
#Entity
#Table(name = "STUDENT")
public class Student implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1354919370115428781L;
#Id
#Column(name = "ID")
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "NAME")
private String name;
public Student(){
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Lets assume table already had entries. Now if somebody asks you add another column of "AGE" (int)
ALTER TABLE STUDENT ADD AGE int NULL
You'll have to set default values as NULL to add another column in a pre-filled table. This makes you add another field in the class. Now the question arises whether you'll be using a primitive data type or non primitive wrapper data type for declaring the field.
#Column(name = "AGE")
private int age;
or
#Column(name = "AGE")
private INTEGER age;
you'll have to declare the field as non primitive wrapper data type because the container will try to map the table with the entity. Hence it wouldn't able to map NULL values (default) if you won't declare field as wrapper & would eventually throw "Null value was assigned to a property of primitive type setter" Exception.
use Integer as the type and provide setter/getter accordingly..
private Integer num;
public Integer getNum()...
public void setNum(Integer num)...
#Column(name ="LEAD_ID")
private int leadId;
Change to
#Column(name ="LEAD_ID")
private Integer leadId;
There are two way
Make sure that db column is not allowed null
User Wrapper classes for the primitive type variable like private int var; can be initialized as private Integer var;
Do not use primitives in your Entity classes, use instead their respective wrappers. That will fix this problem.
Out of your Entity classes you can use the != null validation for the rest of your code flow.
Either fully avoid null in DB via NOT NULL and in Hibernate entity via #Column(nullable = false) accordingly or use Long wrapper instead of you long primitives.
A primitive is not an Object, therefore u can't assign null to it.
#Dinh Nhat, your setter method looks wrong because you put a primitive type there again and it should be:
public void setClient_os_id(Integer clientOsId) {
client_os_id = clientOsId;
}
Change the parameter type from primitive to Object and put a null check in the setter. See example below
public void setPhoneNumber(Long phoneNumber) {
if (phoneNumber != null)
this.phoneNumber = phoneNumber;
else
this.extension = 0l;
}
Make sure your database myAttribute field contains null instead of zero.

Resources