I have a class like this:
class A extends B {
final Property<bool> property = Property<bool>(this);
}
class Property<T> {
Property(this.b);
final B b;
}
But I get an error on this saying:
Invalid reference to 'this' expression.
I believe I can't access this at that moment, probably because the object reference is not ready yet.
So I tried other forms of initializing that variable like:
class A extends B {
final Property<bool> property;
A() : property = Property<bool>(this);
}
But I get the same error.
The only thing that works is:
class A extends B {
Property<bool> property;
A() {
property = Property<bool>(this);
}
}
Which needs me to remove the final variable declaration, which is something I don't want to.
How can I initialize a final variable in Dart that needs a reference to the object itself?
You can't reference this in any initializers as this hasn't yet been initialized itself, so you won't be able to set Property<bool> property to be final.
If you're just trying to prevent modification of the value of property from outside the instance, you can use a private member and provide a getter to prevent modification. Given your example, that would look something like this:
class A extends B {
// Since there's no property setter, we've effectively disallowed
// outside modification of property.
Property<bool> get property => _property;
Property<bool> _property;
A() {
property = Property<bool>(this);
}
}
Related
In Dart, is there a difference in assigning values right away vs in constructor like in Java?
class Example {
int x = 3;
}
vs
class Example {
int x;
Example() {
x = 3;
}
}
I ask because when I was using Flutter and tried to assign a Function that uses setState to a variable, it was not possible with the former method but possible with the latter.
In your trivial case, it doesn't matter.
In general, you can initialize instance variables in a few ways:
Inline (field initializers)
class Example1 {
T x = value;
}
Advantages:
Direct, concise.
Member will be initialized in all constructors.
Can be used to initialize final or non-nullable members.
Member is initialized before invoking base class constructors, which is important when the base class constructor calls member functions that are overridden by the derived class.
Disadvantages:
Cannot depend on construction arguments.
Usually cannot depend on this since the initialization occurs before this becomes valid (i.e., cannot depend on other instance members). (An exception is if the member is initialized lazily by declaring it late. This requires the null-safety feature to be enabled.)
Initializer list
class Example2 {
T x;
Example2() : x = value;
}
Advantages:
Can be used to initialize final or non-nullable members.
Member is initialized before invoking base class constructors, which is important when the base class constructor calls member functions that are overridden by the derived class.
Can utilize construction arguments.
The initialized variable always refers to a member variable, never to a constructor parameter.
Disadvantages:
If the class has multiple constructors, initialization would need to be duplicated, or constructors should redirect to a common constructor.
Cannot depend on this since the initialization occurs before this becomes valid (i.e., cannot depend on other instance members).
Can initialize only members of the enclosing class. Because initializer lists are executed before invoking base class constructors, they cannot set base class members.
Constructor body
class Example3 {
T x;
Example3() {
x = value;
}
}
Advantages:
Can utilize construction arguments.
Can be used to perform more complicated initialization, such as cases where the member cannot be initialized via a single expression.
Can use this (i.e., can use other instance members).
Can be used to set base class members.
Disadvantages:
Cannot be used to initialize non-late final nor non-nullable members.
If the class has multiple constructors, initialization would need to be duplicated or initialization code would need to be refactored out (such as, but not limited to, redirecting to a common constructor).
Member is initialized after invoking base class constructors.
If the constructor has a parameter that shadows a member variable, it's easy to accidentally refer to the parameter instead of the member. (See https://github.com/dart-lang/linter/issues/2552 for details.)
There probably are some points I'm forgetting, but I think that should cover the main ones.
Direct, inline initialization occurs first, then initialization lists, then constructor bodies. Also see Difference between assigning the values in parameter list and initialiser list, which explains why this becomes valid only for the later stages of object initialization.
As an example where it matters where members are initialized:
class Base {
Base() {
doSomething();
}
void doSomething() {}
}
class DerivedEarly extends Base {
int? x;
DerivedEarly() : x = 42;
#override
void doSomething() => print(x);
}
class DerivedLate extends Base {
int? x;
DerivedLate() {
x = 42;
}
#override
void doSomething() => print(x);
}
void main() {
DerivedEarly(); // Prints: 42
DerivedLate(); // Prints: null
}
I'm working on a library, and I have a implementation pattern users are required to follow:
class MyView extends LibView {
static Foo f = Foo();
#override
void render(){
use(f); // f should be static, otherwise things not work correctly
}
}
I would like to tell the compiler that, if someone ever does this, it's incorrect:
class MyView {
Foo f = Foo(); // Error: Foo can only be used in Static field.
...
}
Anyone know if this is possible? I find it really hard to find good docs on these sorta of language details when it comes to dart.
[EDIT] Since the "why" question always comes up, imagine something like:
class ViewState{
Map<int, Object> props = {};
}
ViewState _state = ViewState();
class View {
View(this.state);
ViewState state;
static int _key1 = getRandomInt();
void render(){
print(state(_key1))
}
}
// These should both print the same value off of state since the 'random' int is cached
View(_state);
View(_state);
If the key's were not static, everything would compile fine, but they would not print the same results.
What you properly need are a singleton which can be created in different ways in Dart. One way is to use a factory constructor like this:
class Foo {
static final Foo _instance = Foo._();
factory Foo() => _instance;
// Private constructor only used internally
Foo._();
}
void main() {
final a = Foo();
final b = Foo();
print(identical(a, b)); // true
}
By doing it like this, there will only be one instance of Foo which are then shared each time an instance are asked for. The instance are also first created the first time it is asked for since static variables in Dart are lazy and only initialized when needed.
I just want to do the functional equivalent of
int someUniqueKey = 0, or MyViewEnums.someUniqueKey but do it with a typed object rather than a int/enym, like: Object<Foo> someUniqueKey = Object<Foo>(). In order for this to work with Objects, it needs to be static. It's similar to how int someUniqueKey = random.nextInt(9999) would have to be static in order to be used as a key that all instances could share. That way keys are auto-managed and unique, and people don't need to assign int's, strings, or whatever. It also has the advantage of letting me use the type later for compile time checks.
bool prop = getPropFromRef(_prop1Ref); //Will throw error prop1Ref is not Ref<bool>
I think I've figured out something that does the trick using darts package-level methods.
class Ref<T> {}
// Re-use existing ref if it already exists
Ref<T> getRef<T>(Ref<T> o) => o ?? Ref<T>();
class RefView {}
// In some other package/file:
class MyView extends RefView {
static Ref<bool> prop1Ref = getRef(prop1Ref);
static Ref<int> prop2Ref = getRef(prop2Ref);
}
This will make sure that prop1 and prop2 have the same values across all instances of MyView and it will throw an error if these are not static (since you can not pass an instance field before Constructor)
This still has the downside of a potential hard to spot error:
class MyView extends RefView {
static Ref<bool> prop1 = getRef(prop1);
static Ref<bool> prop2 = getRef(prop1); // passing prop1 to prop2's getRef, and they have the same<T>, compiler will miss it
}
But I think it might be preferable than having this potential error:
class MyView extends RefView {
//Both of these will fail silently, keys will change for each instance of MyView
Ref<bool> prop1 = getRef(prop1);
Ref<bool> prop2 = getRef(prop2);
}
Suppose I have the following Dart class, with a named parameter in its constructor:
class TestClass {
final int someValue;
TestClass({this.someValue});
}
void someMethod() {
TestClass testClass = new TestClass(someValue: 10);
print(testClass.someValue);
}
How can I add a getter for the field? I was trying something along the lines of:
class TestClass {
final int _someValue;
TestClass({this.someValue});
int get someValue => _someValue+2;
}
Named parameters can't be private, but you can get the results you want using a named parameter, a private member, and an initializer. You could do the same thing in the constructor body without the initializer, but then _someValue couldn't be final.
class TestClass {
final int _someValue;
TestClass({int someValue}) : _someValue = someValue;
int get someValue => _someValue;
}
However, there is very little value to doing this in Dart. A getter without a corresponding setter is semantically equivalent to a final field.
TestClass({this.someValue});
There's no member variable by that name. Did you mean _someValue?
code running in xcode
“For computed type properties for class types, you can use the class keyword instead to allow subclasses to override the superclass’s implementation.”
“You can override an inherited instance or type property to provide your own custom getter and setter for that property”
----Apple Swift3
//override static
class A{
var myValue = 0614
static var storedTypeProperty = "Some value"
class var overrideableComputedTypeProperty: Int {
return 1
}
}
class B: A {
storedTypeProperty = "New String"
}
It seems like that B doesn't inherit any type property from A.
So how to override the "inherited type property" as described above in Swift3 book.
The problem you are facing is because you are using a static variable. static variables can not be overwritten, full stop. No point to argue here.
First sentence says, if you have a class (not a struct),like class A {} , you can use the class keyword instead of the static keyword, and override class types. This means, that you can use two keyword for the same purpose, with a major difference, that static can not be overwritten.
class A {
// overridable computed property
class var overridableClassPropery: String {
return "This is class A's overwritten property"
}
// Not overridable `static` computed property
// Error will be shown if you try to override this property in class `B`
static var notOverridableStaticPropery: String {
return "Can not override this property in a subclass"
}
}
The second one says, that you can override a superclasses class property, and provide your own get implementation in a subclass, like the following:
class B: A {
// Class type computed property can be overwritten
override class var overridableClassPropery: String {
return "This is class B's overwritten property"
}
}
EDIT:
notOverridableStaticPropery of class A is being inherited by class B, what means, you can access / call it through class B. BUT you can not override it, it will have the value set in class A always.
print(A.notOverridableStaticPropery) // prints "This is class A's not overridable static property"
print(B.notOverridableStaticPropery) // prints "This is class A's not overridable static property"
Please help me to understand what it exactly means:
Quote from the "Chapter 2. A Tour of the Dart Language"
A local, top-level, or class variable that’s declared as final is initialized the first time it’s used
So this is my test code:
lazyTest(msg) => print(msg);
class Printer{
Printer(msg){
print(msg);
}
final finalClassVariable = lazyTest("final class variable");
}
var globalsAreLazy = lazyTest("top-level");
var lazyInitialized = lazyTest("lazy initialized");
void main() {
final localFinal = new Printer("local final");
var initialize = lazyInitialized;
}
Output:
final class variable
local final
lazy initialized
Both finalClassVariable and localFinal initialized and only globalsAreLazy wasn't. lazyInitialized was initialized on access as i expected.
Class variables is another name for static fields, so you need to make finalClassVariable static for it to be lazy.
The text is incorrect on local variables. They are initialized when the declaration is executed, not lazily when it is first read.
Non-static class fields with initializer expressions are initialized when a constructor is called. They are not lazy.
finalClassVariable is an instance variable not a class variable. To make it a class variable you have to prepend static.