Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Watching a future returning function leads to type case error #29

Closed
TheNordicOne opened this issue May 9, 2024 · 5 comments
Closed

Comments

@TheNordicOne
Copy link

Hi there,

as the title describes an error is thrown if you try to watch a future based on a function that is returning a future.

Error:

type '() => ItemTemplateViewModel?' is not a subtype of type 'ItemTemplateViewModel?' in type cast

Stacktrace
I/flutter ( 7540): #0   _WatchItState.registerFutureHandler (package:watch_it/src/watch_it_state.dart:398:42)
I/flutter ( 7540): #1   watchFuture (package:watch_it/src/watch_it.dart:268:31)
...

Line throwing the error:

initialValueProvider?.call as R?;

watchFuture call:

final itemTemplate = watchFuture((LibraryService p0) => p0.getItemTemplateById(templateId ?? -1), initialValue: null);

getItemTemplateById signature:

Future<ItemTemplateViewModel?> getItemTemplateById(int templateId) 

I suspect this might be a bug in registerFutureHandler. The following is the code block including the line throwing the error and the code before it

/// select returned a different value than the last time
/// so we have to unregister out handler and subscribe anew
watch.dispose();
initialValue = preserveState && watch.lastValue!.hasData
    ? watch.lastValue!.data ?? initialValueProvider?.call()
    : initialValueProvider?.call as R?;

initialValueProvider?.call as R?; is trying to cast the function to R instead of calling it and then casting. Given that at all other times (in this file) the .call is actually being called, this is most likely a bug. Changing it to : initialValueProvider?.call() as R?; works without throwing an error.

@escamoteur
Copy link
Owner

Thanks for reporting, I will look into it

escamoteur added a commit that referenced this issue May 12, 2024
@escamoteur
Copy link
Owner

Hi,

I added a new branch and PR with a fix #30

Could you please verify that it's works (you can directly reference the branch from your pubspec)
It seems that your selector function (LibraryService p0) => p0.getItemTemplateById(templateId ?? -1) returns different futures on different builds which is probably pretty rarely used. watch_it was built to deal with this, but you just found the bug there.

@TheNordicOne
Copy link
Author

TheNordicOne commented May 12, 2024

Hi,

thanks for the quick fix. I tested it out and it works.

One thing I noticed is that this only happened when templateId was null. getItemTemplateById ultimately calls the following implementation interacting with the local Drift database

Future<ItemTemplateViewModel?> getItemTemplateWithId(int id) async {
    final row = await _joinValues(select(itemTemplates)..where((li) => li.id.equals(id))).getSingleOrNull();
    return _rowToViewModel(row);
  }

@escamoteur
Copy link
Owner

It might be, that it only really happend when the returned value was null. But in general I wouldn't implement it this way as it really will create a new Future on every call that is awaited and then leads to a rebuild which creates a new future.
I prefer to have such functions updating a ´ValueNotifier´ when a new value is available and then watch that one.
I highly recommend checking out my flutter_command package as it is a great addition to watch_it especially to handle async function calls

@escamoteur
Copy link
Owner

Fixed in V1.4.2 now on pub

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants