I have a singleton class and I would like to refer to it from within itself, however I am getting a CyclicInitializationError (Reading static variable 'instance' during its initialization) when trying to do so.
Here is an example:
void main(){
Singleton newSingleton = Singleton();
print(newSingleton.member);
}
class Singleton {
static final instance = Singleton._internal();
Singleton._internal();
factory Singleton(){
return instance;
}
String member = "hello";
String hamburger = instance.member; // This line causes the error to be thrown
}
Related
I gathered the following understanding for creating a singleton in dart with params
class Foo extends ChangeNotifier {
late String channel;
void instanceMemberFunction () {
print('Foo created with channel $channel')
}
static final Foo _instance = Foo._internal();
Foo._internal() {
instanceMemberFunction();
}
factory Foo({
required String channel
}) {
_instance.channel = channel;
return _instance;
}
}
and I am calling the instance like so
Foo({channel: "bar"})
Now I want to have some working that if I use
Foo({channel: "baz"})
Then a new instance is created and it's okay in that case to destroy the old one. How can I achieve this in dart?
It seems like you've copied some existing example for creating a singleton without fully understanding what it's doing and why. The core parts are:
The single instance is stored in a global or static variable.
The class has one or more public factory constructors that returns that global/static variable, initializing it if necessary.
All other constructors for the class are private to force consumers to go through the factory constructors.
Therefore, if you want your factory constructor to replace its singleton based on its argument, you need to:
Make your factory constructor check if the argument is appropriate for the existing instance. If it is, return the existing instance. If not (or if there is no existing instance), create and return a new instance.
Since you need to check if the existing instance is initialized, make it nullable. (You alternatively could initialize it to a non-null sentinel value, e.g. Foo._internal(channel: '').
Pass the argument along to the private constructor.
class Foo extends ChangeNotifier {
final String channel;
void instanceMemberFunction () {
print('Foo created with channel $channel');
}
static Foo? _instance;
Foo._internal({required this.channel}) {
instanceMemberFunction();
}
factory Foo({required String channel}) {
if (channel != _instance?.channel) {
_instance = Foo._internal(channel: channel);
}
return _instance!;
}
}
Note that this implementation will create a new object if the constructor argument changes, which isn't very singleton-like. Depending on what you want to do, you could:
Return a new object (which could allow multiple simultaneous instances).
Return the existing object.
Return the existing object, but mutate it with the constructor argument.
I'm using Flutter web. I have a javascript class with methods. I can call the constructor from Dart with package:js, and I can access members with getters, but when I try to call a class method I get a NoSuchMethodError. How do I make the class methods available to Dart?
In my index.html I have this in a script block:
class TestClass {
constructor(val) {
this.foo = val;
console.log("TestClass constructed with foo="+this.foo);
}
someGenericFunction() {
console.log("generic");
}
getSomeValue(foo, bar) {
return this.foo+" "+foo+" "+bar;
}
}
This is my Dart interop code:
#JS()
library testclass.js;
import 'package:js/js.dart';
#anonymous
#JS()
abstract class TestClass {
external factory TestClass({String foo});
external String get foo;
external void someGenericFunction();
external String getSomeValue(String foo, String bar);
}
Here's my Dart code:
TestClass ts = TestClass(foo: "dart"); //Works!
String foo = ts.foo; //Works!
//The below methods error with:
//JSNoSuchMethodError (NoSuchMethodError: tried to call a non-function...)
ts.someGenericFunction();
ts.someGenericFunction.call();
String testClassString = ts.getSomeValue("one", "two");
The constructor works and the getter works. How do I correctly expose the TestClass methods?
Basically wondering if there is a quick way other than creating a method to create a new class instance from itself so the example below would print 9, not 15.
void main() {
final classOne = SomeClass(mutableString: 'Hello', mutableInt: 9);
final classTwo = classOne;
classTwo.mutableInt = 15;
print(classOne.mutableInt);
}
class SomeClass {
SomeClass({required this.mutableString, required this.mutableInt});
String mutableString;
int mutableInt;
}
Thanks
You can add a method in the class which retuns the same object.
For example :
I am ading copyWith method in SomeClass
class SomeClass {
SomeClass({required this.mutableString, required this.mutableInt});
String mutableString;
int mutableInt;
SomeClass copyWith({int? mutableInt}) {
return SomeClass(
mutableString: this.mutableString,
mutableInt: mutableInt ?? this.mutableInt,
);
}
}
Now you can use the method as :
void main() {
final classOne = SomeClass(mutableString: 'Hello', mutableInt: 9);
final classTwo = classOne.copyWith(mutableInt:15);;
print(classOne.mutableInt);
}
#anoncgain solution is correct up-to an extent.
You can also do the same as
class SomeClass {
//...other code ....
String? mutableString; //make your params nullable
int? mutableInt;
//declare a named constructor to copp the existing object value.
SomeClass.copy(SomeClass object){
mutableString = object.mutableString;
mutableInt = object.mutableInt;
}
}
Then you can use it as
final classTwo = SomeClass.copy(classOne);
//it will copy the values to the newly created object
//rather then storing the reference of the object
In Haxe, it is possible to get the class of an object with the following function:
Type.getClass(myObject);
If the object myObject is an instance of the class myClass, which contains a static field, I should be able to access this static field:
class MyClass
{
public static myStaticField:Int = 5;
}
public var myObject = new MyClass();
//expected trace: "5"
trace (Type.getClass(myObject).myStaticfield);
But the result is:
"Class <MyClass> has no field myStaticField."
Any idea why?
You need to use reflection to get such value:
class Test {
#:keep public static var value = 5;
static function main() {
var test = new Test();
var v = Reflect.field(Type.getClass(test), "value");
trace(v);
}
public function new() {}
}
Note that to prevent DCE (dead code elimination) I had to mark the static var with #:keep. Normally DCE is going to suppress that variable because it is never referred directly.
Working example here: http://try.haxe.org/#C1612
Try the Reflect class (Specifically the callMethod or getProperty functions).
have class Klass with static method fn1
class Klass {
static String fn1() => 'hello';
}
> Klass.fn1(); // hello
but when Klass is assigned to a variable, calling the method fn1 fails
var k = Klass;
> k.fn1() // "Unhandled exception: Class '_Type' has no instance method 'fn1'.
don't quite know what's going on here
A simple workaround
class Klass {
static fn1(String name) {
return name;
}
fn1NonStatic(String name) {
return fn1(name);
}
}
Klass().fn1NonStatic("test");
I'm not sure what the intent of the code here is, but you might want to use dart:mirrors to reflectively call fn1(). I don't believe you can invoke it by assigning Klass to a variable. Here is how you can do it:
import 'dart:mirrors';
class Klass {
static String fn1() => 'hello';
}
main() {
final mirror = reflectClass(Klass);
print(mirror.invoke(#fn1, []).reflectee); // Prints 'hello'.
}