I have a loop traversing a graph using a 'const' reference but when I assign my iteration variable I realize that it is non-const then I get nice compiler's complains.
class ClassDescriptor
{
const string name;
const TypeInfo type;
const ClassDescriptor base;
const IPropertyDescriptor[string] propertiesByName;
IPropertyDescriptor getFlattenProperty(string name)
{
// This declaration makes 'const(ClassDescriptor) bag'
// Note that in this point I can't add ref keyword.
auto bag = this;
while(!(bag is null))
{
if(name in bag.propertiesByName)
{
return bag.propertiesByName[name];
}
// This assigment breaks the constness
bag = bag.base;
}
return null;
}
public this(string name, TypeInfo type, ClassDescriptor base, const IPropertyDescriptor[string] propertiesByName)
{
this.name = name;
this.type = type;
this.base = base;
this.propertiesByName = propertiesByName;
}
}
Sounds like a job for std.typecons.Rebindable:
http://dpldocs.info/experimental-docs/std.typecons.Rebindable.html
import std.typecons;
Rebindable!(const typeof(this)) bag = this;
then the rest should work the same.
Related
is there a way to use some variable or any holder to store constructor parameters,
to be able to pass them to multiple constructors without repeating the values?
I think its possible if the constructor has only positional parameters (no named parameters).
var parametersHolder={
named1: "str",
named2: "lorem",
};
// normal usage
constructorA(named1: "str", named2: "lorem");
constructorB(named2: "lorem",named1: "str" );
my question is how to do the following in dart:
constructorA(parametersHolder);
constructorB(parametersHolder);
so is that achievable ?
Thanks
If you really want, you could use Function.apply with a constructor tear-off:
class Foo {
String named1;
String named2;
Foo({required this.named1, required this.named2});
#override
String toString() => 'Foo: $named1 $named2';
}
void main() {
var namedArguments = {
#named1: 'str',
#named2: 'lorem',
};
var foo = Function.apply(Foo.new, null, namedArguments) as Foo;
print(foo); // Prints: Foo: str lorem
}
Note that doing this sacrifices compile-time type-safety.
You can define a class to hold your parameters like this:
class MyClass{
late final int myInt;
late final String myString;
MyClass.firstConstructor(MyClassParams params){
this.myInt = params.myInt;
this.myString = params.myString;
}
MyClass.secondConstructor(MyClassParams params){
this.myInt = params.myInt;
this.myString = params.myString;
}
}
class MyClassParams{
final int myInt;
final String myString;
const MyClassParams(this.myInt, this.myString);
}
I am learning factory method in dart. However I encounter a problem, which says
A value of type 'Person?' can't be returned from a function with return type 'Person' because 'Person?' is nullable and 'Person' isn't.
3-1.dart:13
Here is my code:
void main(List<String> args) {
Person a = new Person("zarkli");
a.say("hello");
}
class Person{
final name;
static final Map<String, Person> _cache = new Map<String,Person>();
factory Person(String name){
if (_cache.containsKey(name)){
return _cache[name]; // error
} else {
final person = new Person.newPerson(name);
_cache[name] = person;
return person;
}
}
Person.newPerson(this.name);
void say(String content){
print("$name: $content");
}
}
Some maps allow null as a value. For those maps, a lookup using this operator cannot distinguish between a key not being in the map, and the key being there with a null value.
This is from the get operator documentation for map. When you use containsKey it could be the case that the key exists but its value is null.
You can use a local variable to store _cache[name] and check if it's null or not. Dart then can promote that local variable and not give you any errors. So your factory will look like this:
factory Person(String name) {
final cached = _cache[name];
if (cached != null) {
return cached;
} else {
final person = Person.newPerson(name);
_cache[name] = person;
return person;
}
}
Got an error for following code
Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
static const MyClass darkerText = MyClass(param);
Understood that using static in this instance might be inappropriate. Just wanted to look if there is any possible way to do so.
class MyClass {
final int total;
MyClass(total);
}
class Test {
static int param = 10;
static const MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
You seem to have misunderstood the point of const and final. const is for values that are known at compile time, so in your case this is possible, though somewhat pointless, if all your values are compile time constants:
class MyClass {
final int total;
const MyClass(this.total);
}
class Test {
static const int param = 10;
static const MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
What is more normal is to use final variables, which can be set during the program's lifecycle but don't change after being set, in which case you would use something like this:
class MyClass {
final int total;
MyClass(this.total);
}
class Test {
static int param = 10;
static final MyClass darkerText = MyClass(param);
}
main() {
new Test();
}
You can copy paste run full code in DartPad
You need to use this.total and remove const keyword of darkerText
class MyClass {
final int total;
MyClass(this.total);
}
class Test {
static int param = 10;
static MyClass darkerText = MyClass(param);
}
main() {
print(Test.darkerText.total);
}
As the error says, your MyClass is a non-const constructor.Make it const:
class MyClass {
final int total;
const MyClass(this.total);
}
class Test {
static const int param = 10;
static const MyClass darkerText = MyClass(param);
}
void main() {
new Test();
}
struct Person {
string FirstName;
string LastName;
};
class Builder {
public:
Person Builder::Build() {
Person person;
person.FirstName = "FirstName";
person.LastName = "LastName";
return person;
};
};
When I compile this it gives me the below error:
'return' - structure have objects and cannot be copied.
I just need to create a struct or class object and return it, I don't want to do any copying.
I tried using & and * combinations but didn't work. I tried with a class instead of struct and it didn't work either.
I also tried with class as shown below:
class Person {
public:
string FirstName;
string LastName;
};
class Builder {
public:
Person* Build() {
Person person;
person.FirstName = "FirstName";
person.LastName = "LastName";
return &person;
};
};
int OnInit()
{
Builder builder;
Person* person = builder.Build();
string firstName = person.FirstName;
return(INIT_SUCCEEDED);
}
And it gives me invalid pointer access when accessing person.FirstName in the OnInit() method at runtime.
Found the answer but how to avoid memory leak? how to destruct the object and its pointer after use?
class cPerson {
public:
string FirstName;
string LastName;
};
class cBuilder {
public:
cPerson* Build() {
cPerson* person = new cPerson();
person.FirstName = "firstname";
return person;
};
};
cBuilder builder;
cPerson* person = builder.Build();
string age = person.FirstName;
You can delete the object by delete(person); and if you are unsure the object is not a null, it is better to check if(CheckPointer(object)==POINTER_DYNAMIC)delete(object);
Overall you should have all such objects as variables with corresponding variable names, or keep them all in a collection and destroy the whole collection at end. You may also create global variable of object (before OnInit, not inside any function) and it is to be deleted at end of program.
Regarding the initial question - you cannot have string inside a struct, only primitives
you should NOT delete static objects - you will get "delete invalid pointer"-message from compiler in print area... therefore the check should be done as Daniel Kniaz answered... but as so as you are creating the object inside the wrapper - you'd better have a check for deletion & delete it in the Destructor of its wrapper (though I doubt, that you really should use here another class for CPerson creation - yuo can create its object in its - CPerson's - Constructor)
First you need a default constructor and copy constructor in your code. second you need to initialize the struct to default value, the struct only allocate space in the memory and not initialize it, so you can end up with cases where a long variable has some weird value like -1823834393939, so always set your struct to default values.
then when you return a class or struct from a function. the copy constructor will be called that copy the values. so if you don't want to return the exact object you've created in your class you don't need to return a reference
struct Person
{
string FirstName;
string LastName;
Person()
{
FirstName = "";
LastName = "";
}
Person(Person &that)
{
FirstName = that.FirstName;
LastName = that.LastName;
}
};
class Builder
{
public:
Person Builder::Build(string argFirstname, string argLastName)
{
Person person;
person.FirstName = argFirstname;
person.LastName = argLastName;
return person;
};
};
void OnStart()
{
Builder b;
Person p = b.Build("Mohammad Hossein", "amri");
Print(p.FirstName + " " + p.LastName);
}
the output will be
I've a Collection class which aims to store different kind of objects, however I'd like to call specific method name which these classes share (e.g. ToString()).
Here is my attempt:
class Collection {
public:
void *data[];
void Collection() {}
void ~Collection() {
for (int i = 0; i < ArraySize(data); i++) {
if (CheckPointer(data[i]) == POINTER_DYNAMIC) delete data[i];
}
}
void *Add(void *_object) {
uint _size = ArraySize(data);
ArrayResize(data, _size + 1, 100);
data[_size] = _object;
return _object;
}
string ToString(string _dlm = ",") {
string _out = "";
for (int i = 0; i < ArraySize(data); i++) {
if (CheckPointer(data[i]) == POINTER_DYNAMIC) {
_out += ((void *) data[i]).ToString(); // #fixme: Syntax error.
}
}
return _out;
}
};
However using ((void *) data[i]).ToString() syntax fails with:
'ToString' - member function not defined Collection.mqh
How can I call a ToString() method for each stored object?
It seems to me that it should be something like collection.toString() where collection is an object of your class Collection. Then each object that you add to your collection should implement this function... Maybe it is easier to mention some superclass that supports toString() (or interface with this method) and make sure that you add only correct objects? This also makes your code free of unexpected errors in runtime.
Also CArrayObj is at your disposal with most functions, if you need toString() or any other function then you can simply extend basic class. Maybe the only disadvantage of the default collection is that it stores CObject-inherited objects.
This can be achieved by creating an abstract class where all classes can share the same virtual method. For example:
class Object {
public:
virtual string ToString() = NULL;
};
class Foo : public Object {
public:
virtual string ToString() {
return "Foo";
};
};
class Bar : public Object {
public:
virtual string ToString() {
return "Bar";
};
};
Then in the Collection class the following method:
virtual string ToString(string _dlm = ",") {
string _out = "";
for (int i = 0; i < ArraySize(data); i++) {
if (CheckPointer(data[i]) == POINTER_DYNAMIC) {
_out += ((Object *) data[i]).ToString() + _dlm;
}
}
return _out;
}
Sample usage:
Collection *objects;
objects = new Collection;
Foo *foo = new Foo();
Bar *bar = new Bar();
objects.Add(foo);
objects.Add(bar);
Print(objects.ToString());
delete objects;