0

I am trying to set a property from an external object:

main() {
  A a = A();
  print(a.prop.runtimeType); // is 'Null'
  MiddleMan().b.assign(a.prop);
  print(a.prop.runtimeType); // should be 'B', but is 'Null'
}

class A { B prop; }

class MiddleMan { B b = B(); }

class B {
  assign(B property) { property = this; }
}

I managed to achieve this functionality with mirrors:

import 'dart:mirrors';

main() {
  A a = A();
  print(a.prop.runtimeType); // is 'Null'
  MiddleMan().b.assign(a, 'prop');
  print(a.prop.runtimeType); // is 'B'
}

class A { B prop; }

class MiddleMan { B b = B(); }

class B {
  assign(dynamic object, String property) {
    InstanceMirror reflectee = reflect(object);
    reflectee.setField(Symbol(property), this);
  }
}

But then I realized mirrors are disabled in Flutter. Is there any workaround?

Kaspi
  • 3,538
  • 5
  • 24
  • 29
  • try A a = new A(); – Basel Abuhadrous Oct 21 '19 at 20:16
  • This isn't *quite* what you are looking for, but in your B class could you do this: assign(A a) { a.prop = this; } – Adrian Murray Oct 21 '19 at 20:31
  • or maybe make a static method that sits outside of it all, skipping the middleMan: static assignBfrom(B bFrom, B bTo)=>bTo = bFrom; – Adrian Murray Oct 21 '19 at 20:33
  • @BaselAbuhadrous As far as I know the `new` keyword can be omitted in Dart from a certain version. I tried anyway and it didn't work. – Kaspi Oct 22 '19 at 08:22
  • @AdrianMurray A specific condition is that I'm building a lib where I don't know in advance what property will the user want to have set from their object. I can't do `a.prop`. I'll try to play with static methods to find a solution, thanks. – Kaspi Oct 22 '19 at 08:27
  • How is this not a duplicate of https://stackoverflow.com/questions/18258267/is-there-a-way-to-pass-a-primitive-parameter-by-reference-in-dart/18273525#18273525? – Rémi Rousselet Oct 22 '19 at 09:52

1 Answers1

0

Just as mentioned here, one can use a wrapper class:

main() {
  A a = new A();
  print(a.prop.value.runtimeType); // is 'Null'
  MiddleMan().b.assign(a.prop);
  print(a.prop.value.runtimeType); // is 'B'
}

class A {
  Wrapper<B> prop = Wrapper(null);
}

class MiddleMan {
  B b = B();
}

class B {
  assign(Wrapper<B> property) {
    property.value = this;
  }
}

class Wrapper<T> {
  T value;

  Wrapper(this.value);
}

But because my intention is to write a library and make its use easy for the user, with one line call such as:

MiddleMan().b.assign(a.prop);

And at the same time I needed to optionally process additional stuff when the property is assigned, so a direct assignment like a.prop = MiddleMan().b;, for now I decided to utilize somewhat unusual syntax with overloading the & operator, which results in usage as:

a.prop = MiddleMan().b;

or optionally:

a.prop = MiddleMan().b & doAdditionalStuff;

Here's the implementation:

class B {
  B operator &(Function doAdditionalStuff) {
    if (doAdditionalStuff != null)
      doAdditionalStuff();

    return this;
  }
}

To give it more sense of what I am trying to achieve, my lib is supposed to work in context with the Provider library. User code example:

class MyStore with ChangeNotifier {
  B prop;

  MyStore() {
    // MiddleMan is Singleton
    prop = MiddleMan().b;
    // or alternatively
    prop = MiddleMan().b & notifyListeners;
  }
}

Library code example:

class B {
  List<Function> _reactives = [];

  B operator &(Function notifyListenersCallback) {
    if (notifyListenersCallback != null)
      this._reactives.add(notifyListenersCallback);

    return this;
  }

  // called on each internally triggered change
  notifyListeners() {
    for (Function reactive in this._reactives) {
      if (reactive != null)
        reactive();
    }
  }
}
Kaspi
  • 3,538
  • 5
  • 24
  • 29