Final<T> constructor

const Final<T>({
  1. Object? name,
  2. required Equal<T> equal,
  3. ExposeValue<T>? expose,
  4. DisposeValue<T>? dispose,
  5. bool lazy = true,
})

Assign an instance and exposing it in current scope.

So:

final rootScope = await Scope.root([
  Final<StreamController<String>>(
    name: 'controller', 
    equal: (scope) => StreamController(),
  ),
]);

Simulate:

void rootScope() {
  final StreamController<String> controller = StreamController();
}

Use expose parameter to override default exposing behavior:

final rootScope = await Scope.root([
  Final<StreamController<String>>(
    equal: (scope) => StreamController(),
    expose: (scope, getStreamController) {

      // Instead of exposing the whole `StreamController`, 
      // We can only expose its stream field here.
      scope.expose<Stream<String>>(
        expose: () => getStreamController().stream,
      );

    },
  )
]);

print(rootScope.has<StreamController<String>>()); // false
print(rootScope.has<Stream<String>>());           // true

Use dispose parameter to register dispose logic:

final rootScope = await Scope.root([
  Final<StreamController<String>>(
    equal: (scope) => StreamController(),
    dispose: (controller) {
      controller.close();
    },
  ),
]);

// pop scope will close the controller.
rootScope.dispose(); 

Implementation

const Final({
  Object? name,
  required Equal<T> equal,
  ExposeValue<T>? expose,
  DisposeValue<T>? dispose,
  bool lazy = true,
}): _name = name,
  _equal = equal,
  _expose = expose,
  _dispose = dispose,
  _lazy = lazy;