Skip to content

Union of Modddels: how to properly handle narrowed types? #7

@chikamichi

Description

@chikamichi

Sorry for the continuous streak of questions, I got hyped!

Using my repo from #6 as context, I now face a rather annoying issue regarding (I guess) ahead of compilation vs runtime types, when a modddel is exposed through a Riverpod provider cased Modddels in a union (in my case, the union modddels is exposed through a Riverpod AsyncNotifier, which wraps an AsyncValue<MapLayer> with MapLayer being the union of modddels: MapLayer.raster, MapLayer.vector and MapLayer.geojson).

My guess is that I’m not providing Riverpod with enough insight, but I did not manage to discover how. edit: wrong guessing 🙈


Here it is, explained by comments:

// [… imports … ]

class Map extends ConsumerWidget {
  const Map({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final logger = ref.read(loggerProvider);

    final provider = mapLayerControllerProvider(layerName: "some_raster_layer");

    final rasterLayer = ref.watch(provider);

    return rasterLayer.when(data: (layer) {
      logger.d(layer);
      // ==> layer exposed as a ValidRaster, which is expected, for it was created
      // with MapLayer.raster(…) with valid attributes values;
      // but this fails because Dart thinks it’s a MapLayer, which has no position attribute:
      // logger.i(layer.position.value);
      // ==> Hence doing a cumbersome type casting:
      final l = layer as ValidRaster;
      logger.i(l.position.value); // works fine now!
      return Text("OK");
    }, error: (e, _) {
      logger.d(e);
      return Text("KO");
    }, loading: () {
      logger.d("Loading…");
      return Text("Loading…");
    });
  }
}

Of course, the problem stays the same if I, say, mapValidity on layer within the widget (rather than within the controller/provider):

    return rasterLayer.when(data: (layer) {
      return layer.mapValidity(valid: (layer) {
        logger.d(layer.runtimeType); // ValidRaster
        // logger.i(layer.position.value); // Error: The getter 'position' isn’t defined for the type 'ValidMapLayer'.
        logger.i((layer as ValidRaster).position.value); // works fine, for ValidRaster extends MapLayer
                                                         // with Raster, which has the attributes
        return Text("Valid layer $layer");
      }, invalid: (layer) {
        logger.d(layer.runtimeType); // InvalidRaster
        logger.d(layer.failures); // works fine; layer is seen as an InvalidMapLayer, though
        return Text("Invalid layer $layer");
      });
    }, error: (e, _) {
      logger.d(e);
      return Text("KO");
    }, loading: () {
      logger.d("Loading…");
      return Text("Loading…");
    });

Metadata

Metadata

Assignees

No one assigned

    Labels

    discussionOpen-ended topics or questions, likely to be converted to a Github Discussion

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions