how to make a property is only readable from abstract class in Dart? - dart

abstract class ListController {
int numberOfDocumentPerPage = 7;
}
then use the abstract class
class EventListController extends ListController {
}
but when I make an instance, I can change/assign the new value to the property
final controller = EventListController();
controller.numberOfDocumentPerPage = 1000; // should be error in here
so how to make a property is only readable from abstract class ?
UPDATE:
I also need to modify the property inside EventListController class

Basically you want the base class to declare a public getter. I think the simplest way would be:
abstract class ListController {
static const defaultNumberOfDocumentPerPage = 7;
int get numberOfDocumentPerPage => defaultNumberOfDocumentPerPage;
}
class EventListController extends ListController {
int _numberOfDocumentPerPage = ListController.defaultNumberOfDocumentPerPage;
#override
int get numberOfDocumentPerPage => _numberOfDocumentPerPage;
}
If you don't want the separate named constant, you could explicitly initialize your internal value with the result of calling the original getter:
abstract class ListController {
final int numberOfDocumentPerPage = 7;
}
class EventListController extends ListController {
EventListController() {
_numberOfDocumentPerPage = super.numberOfDocumentPerPage;
}
// ignore: super_in_invalid_context, https://github.com/dart-lang/sdk/issues/46850
late int _numberOfDocumentPerPage = super.numberOfDocumentPerPage;
#override
int get numberOfDocumentPerPage => _numberOfDocumentPerPage;
}
Another approach would be to provide a protected setter in the base class:
import 'package:meta/meta.dart';
abstract class ListController {
int _numberOfDocumentPerPage = 7;
int get numberOfDocumentPerPage => _numberOfDocumentPerPage;
#protected
set numberOfDocumentPerPage(int value) => _numberOfDocumentPerPage = value;
}
But note that the #protected annotation just provides a hint to the analyzer so that it can warn about violations; it is not enforced at compilation-time nor at runtime.

Related

List property inheritance

The parser is complaining that the property inheritor .list is not subtype of ModelList.list, but LeadsGroup does inherit from Model.
Is this wrong? What is the correct way to do this?
My base class:
abstract class ModelList {
List<Model> get list;
set list(List<Model> n);
}
The inheritor:
class ListLeadsGroup extends ModelList {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
If you have code like
class Foo extends ModelList {}
ModelList ml = new ListLeadsGroup();
ml.list.add(new Foo());
ml.list is of type Model, therefore adding Foo should be legit.
But this very likely is not what you want.
This is why List<ListLeadsGroup> can't override List<Model>.
This should do what you want:
abstract class ModelList<T extends Model> {
List<T> get list;
set list(List<T> n);
}
class ListLeadsGroup extends ModelList<LeadsGroup> {
List<LeadsGroup> list;
}
class LeadsGroup extends Model {
}
just copied from Matan Lurey's comment on Gitter
import 'package:func/func.dart';
class ModelRegistry {
final _factories = <Type, Func0<Model>>{};
Model create(Type type) => _factories[type]();
void register(Type type, Model factory()) {
_factories[type] = factory;
}
}
main() {
var registry = new ModelRegistry();
registry.register(FooModel, () => new FooModel());
var foo = registry.create(FooModel);
}
found a solution using the new keyword covariant. Now the classes that extends ModelList can override the List<Model> list without warnings.
#serializable
abstract class ModelList extends ModifiedModel
implements Model {
Type get listType {
throw new UnimplementedError();
}
List<Model> get list;
set list(covariant List n);
}

Polymer Dart 1.0 - Observer not working

I have a custom element <test-object> which looks like this:
#PolymerRegister('test-object')
class TestObject extends PolymerElement with TestBehavior {
TestObject.created() : super.created() {
}
}
The TestBehavior:
#reflectable
class TestModel extends JsProxy {
#Property(notify: true)
num value = 0;
PolymerElement _target;
TestModel(PolymerElement target) {
_target = target;
}
changeBy(num by) {
value += by;
_target.set('testModel.value', value);
}
}
#behavior
abstract class TestBehavior implements PolymerBase {
#Property(notify: true)
TestModel testModel;
PolymerElement _instance;
static ready(instance) {
instance._init(instance);
}
static created(instance) {
instance._instance = instance;
}
_init(PolymerElement instance) {
set('testModel', new TestModel(instance));
}
}
My main app looks like this:
<dom-module id="main-app">
<style>
:host {
display: block;
#apply(--layout-center-center);
}
</style>
<template>
<div>{{testObject.testModel.value}}</div>
<test-object id="obj"></test-object>
</div>
</template>
</dom-module>
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
#Property(notify: true)
TestObject testObject = null;
MainApp.created() : super.created();
ready() {
set('testObject', testObject = $$('#obj') as TestObject);
}
#Listen('click')
clicked([_]) {
testObject.testModel.changeBy(1);
}
#Observe('testObject.testModel.*')
valueChanged([_]) {
window.console.log('Value was changed');
}
}
This is a very simple toy example. I click <main-app> which causes the value in testModel to increase (this works). However, <main-app> doesn't update the div which should display the value. Also, valueChanged is never invoked.
I want to notify testObject about the valueupdate in testModel and propagate this notification up to main-app which than should update its UI via data binding.
Why is this not working?
You can't have a property in model classes, only in components
#Property(notify: true)
num value = 0;
should just be
#reflectable
num value = 0;
The set and notifyPath methods should really be called from your element classes, not the models. This actually simplifies your code a lot, and makes everything work as expected as well. Below I have pasted the new MainApp, TestModel, and TestBehavior classes (I also made some other minor edits).
#PolymerRegister('main-app')
class MainApp extends PolymerElement {
// Defines a read-only property (implicit because of the getter).
#property
TestObject get testObject => $['obj'];
MainApp.created() : super.created();
// I added the 2nd optional argument here, to fix a reflectable error
#Listen('click')
clicked([_, __]) {
// Notify directly here, this is the primary change.
notifyPath('testObject.testModel.value', testObject.testModel.changeBy(1));
}
#Observe('testObject.testModel.*')
valueChanged([_]) {
window.console.log('Value was changed');
}
}
// Removed the `_instance` field.
class TestModel extends JsProxy {
// use #reflectable instead of #Property(notify: true)
#reflectable
num value = 0;
TestModel();
num changeBy(num by) {
value += by;
// Added a return value for convenience
return value;
}
}
#behavior
abstract class TestBehavior implements PolymerBase {
#Property(notify: true)
TestModel testModel = new TestModel();
}

Dagger - Is it possible to select a Provider based on inheritance?

At the moment I have a Base class that contains a member I would like to inject. However, I would like the concrete type of this member to depend on the Subclass being instantiated. What I am aiming for is something along these lines:
public interface StringInterface {
public String getString();
}
public class HelloStringConcrete implements StringInterface {
public String getString() {
return "Hello";
}
}
public class WorldStringConcrete implements StringInterface {
public String getString() {
return "World";
}
}
public abstract class Base {
#Inject StringInterface member;
public Base() {
// Assume access to object graph
MyObjectGraph.get().inject(this);
}
public void printSomething() {
System.out.println(member.getString());
}
}
public class SubclassHello extends Base {}
public class SubclassWorld extends Base {}
#Module(injects = {SubclassHello.class})
public class HelloModule {
#Provides StringInterface provideStringInterface() {
return new HelloStringConcrete();
}
}
#Module(injects = {SubclassWorld.class})
public class WorldModule {
#Provides StringInterface provideStringInterface() {
return new WorldStringConcrete();
}
}
So now what I would like to do is something along the lines of:
#Module(
includes = {
HelloModule.class,
WorldModule.class
}
)
public class BigModule {}
// Somewhere in another piece of code...
objectGraph = ObjectGraph.create(new BigModule());
// In yet another piece of code...
SubclassHello hello = new SubclassHello();
SubclassWorld world = new SubclassWorld();
hello.printSomething();
world.printSomething();
// Hopefully would result in :
// Hello
// World
This type of setup won't work though, because including two modules with the same provider will result in a duplicate provider error at compile time. It would be cool to see a solution to this problem without introducing #Named or #Qualifer annotations, or using scoped graph extensions via graph.plus() because these strategies necessarily introduce coupling to the subclasses
This is possible but I think the code I've attached below is more coupled than using scoped graphs or annotations. Basically you can use constructor injection to inject concrete dependencies to your
SubclassHello and SubclassWorld.
public abstract class Base {
private final StringInterface member;
public Base(StringInterface member) {
this.member = member;
}
...
}
#Module(injects = {SubclassWorld.class})
public class WorldModule {
#Provides
WorldStringConcrete provideStringInterface() {
return new WorldStringConcrete();
}
}
public class SubclassWorld extends Base {
#Inject
public SubclassWorld(WorldStringConcrete worldStringConcrete) {
super(worldStringConcrete);
}
}
#Module(injects = {SubclassHello.class})
public class HelloModule {
#Provides
HelloStringConcrete provideStringInterface() {
return new HelloStringConcrete();
}
}
public class SubclassHello extends Base {
#Inject
public SubclassHello(HelloStringConcrete helloStringConcrete) {
super(helloStringConcrete);
}
}
// Somewhere in another piece of code...
ObjectGraph objectGraph = ObjectGraph.create(new BigModule());
// In yet another piece of code...
SubclassHello hello = objectGraph.get(SubclassHello.class);
SubclassWorld world = objectGraph.get(SubclassWorld.class);
I don't think there are other solutions. How could Dagger find out which StringInterface implementations should be injected to the concrete classes?

What is the difference between extends Object with Observable and extends Observable

What is the difference between extends Object with Observable and extends Observable as applied to the class below.
The result is the same when the application is run.
library models;
import 'package:polymer/polymer.dart';
class Person extends Object with Observable {
#observable String name;
#observable bool signedAgreement = false;
Person();
Person.from(Person other) {
name = other.name;
signedAgreement = other.signedAgreement;
}
blank() {
name = '';
signedAgreement = false;
}
}
library models;
import 'package:polymer/polymer.dart';
class Person extends Observable {
#observable String name;
#observable bool signedAgreement = false;
Person();
Person.from(Person other) {
name = other.name;
signedAgreement = other.signedAgreement;
}
blank() {
name = '';
signedAgreement = false;
}
}
There no difference in the behaviour between this two declarations.
Here's a quote from Florian Loitsch :
When you extend "Object" with a mixin the first mixin can always take the place of "Object".
The only little difference is in class hierarchy (superclass are not the same) :
import 'dart:mirrors';
abstract class Mixin {}
class A extends Mixin {}
class B extends Object with Mixin {}
main() {
print(reflectClass(A).superclass);
// => ClassMirror on 'Mixin'
print(reflectClass(A).superclass.superclass);
// => ClassMirror on 'Object'
print(reflectClass(B).superclass);
// => ClassMirror on 'dart.core.Object with .Mixin'
print(reflectClass(B).superclass.superclass);
// => ClassMirror on 'Object'
}

How can refer base class instance?

The following example, how do I refer base class instance?
public class A
{
public string test;
public A()
{
B b = new B();
test = "I am A class of test.";
}
public void hello()
{
MessageBox.Show("I am A class of hello.");
}
class B
{
public B()
{
//Here...
//How can I get A class of test and call A class of hello method
//base.test or base.hello() are not working.
}
}
}
You'd have to pass a reference of A to B.
One way you can do this is as follows:
public class A
{
string name = "Class A";
public A()
{
var b = new B(this);
}
class B
{
public B(A a)
{
a.name.Dump(); // Write out the property of a.name to some stream.
}
}
}
To clearly distinguish between base class and nested class, please refer the example below.
namespace Example
{
class A
{
string Name = "test"; // access restricted only to this class
public string Type; // global access
internal string Access; // within defining namespace
protected string Code; // this class and subclass
// When you create a nested class like C, you can create instances of C within this class(A).
C c = new C();
class C
{
string name;
public C()
{
//this is a nested class and you cannot call A as its base
name = "test success";
}
}
}
class B : A
{
public string Type { get { return base.Type; } set { base.Type = value; } } // You can use base when you hide a base class member
public B()
{
Type = "test";
Code = "nothing";
Access = "success";
//Cannot Access 'Name' Here as it is private
}
}
}

Resources