language icon indicating copy to clipboard operation
language copied to clipboard

Propagating type parameter from generic function's argument to the function call

Open FireSourcery opened this issue 1 year ago • 2 comments

While an object with a generic parameter preserves that type value, it is difficult to call a function passing/propagating that generic parameter. A work around is the call the function from the object. This seems quite tedious, surely there is, or can be a better way?

typedef GenericFunction<R, A> = R Function<G>(A args);

// in AppSetting class
R callTyped<R, A>(GenericFunction<R, A> fn, A args) => fn<T>(args);

void onSetting<T>(AppSetting<T> setting) {
  print(T);
  print(setting.runtimeType);
}

void main() {
  test('test', () {
    for (final setting in AppSetting.values) {
      onSetting(setting); // prints dynamic, AppSetting<double>
      setting.callTyped<void, AppSetting>(<G>(args) => onSetting<G>(setting as AppSetting<G>), setting);  // prints double, AppSetting<double>
    }
  });
}

FireSourcery avatar Apr 15 '24 04:04 FireSourcery

Sound like what you want is to extract the type variable from an AppSetting object.

There is no way to do that without the cooperation of the AppSetting class. Type variables are not accessible outside of their lexical scope, meaning outside of the class that declared them.

If the AppSetting class had a method like

  R callWith<R>(R Function<T>(AppSetting<T>) callback){
  return callback<T>(this);
}

then you could use that to get access to the actual type argument that was passed to the AppSetting constructor.

The other alternative that has been suggested, is to allow destructuring to extract type variables, fx like:

  AppSetting<final T> appSetting = someAppSetting;

which would extract the actual type argument of AppSetting that someAppSetting implements.

lrhn avatar Apr 15 '24 05:04 lrhn

Sound like what you want is to extract the type variable from an AppSetting object.

There is no way to do that without the cooperation of the AppSetting class. Type variables are not accessible outside of their lexical scope, meaning outside of the class that declared them.

If the AppSetting class had a method like

  R callWith<R>(R Function<T>(AppSetting<T>) callback){
  return callback<T>(this);
}

then you could use that to get access to the actual type argument that was passed to the AppSetting constructor.

The other alternative that has been suggested, is to allow destructuring to extract type variables, fx like:

  AppSetting<final T> appSetting = someAppSetting;

which would extract the actual type argument of AppSetting that someAppSetting implements.

Ah, yes a simple callback providing access to the type parameter would be sufficient. There's no need to handle arguments, as the initial context can directly pass arguments to the body of the anonymous function.

return setting.callWith<SettingMenu<T>>(<G>() => SettingMenu<G>(setting: setting as Setting<G>, settingsController: settingsController) as SettingMenu<T>);

FireSourcery avatar Apr 15 '24 06:04 FireSourcery