1

I have an extension method:

extension When<T extends Object> on T {
  T? when(bool Function(T self) predicate, {T Function(T self)? otherwise}) {
    if (predicate(this)) return this;
    return otherwise?.call(this);
  }
}

It allows me to do some handling with inner variables and inner function results after testing them without the need for them to be saved in a variable.

Sometimes, when I wanted to use this with Widgets, it bothered me that I always need to cast it to Widget. So, I went and did the following extension, since it's more specific, the compiler uses it instead of the first.

extension WhenWidget<T extends Widget> on T {
  Widget? when(bool Function(T self) predicate, {Widget Function(T self)? otherwise,}) {
    if (predicate(this)) return this;
    return otherwise?.call(this);
  }
}

I asked myself, can I do something like this then?

extension When<R extends Object, T extends R> on T {
  R? when(bool Function(T self) predicate, {R Function(T self)? otherwise}) {
    if (predicate(this)) return this;
    return otherwise?.call(this);
  }
}

But this way all of my type inference goes away. What I wanted to do was create this extension in a way that knows how to handle super types. So, if I try and do:

final variable = 1.when((self) self.isEven, otherwise: (self) => self + 0.5)!;

The variable would be num and not Object.

Edit

To be more precise, what I get is that the actual runtimeType is in fact double, but if you try and use .toInt() or any inner method or whatever, it will warn you that you are trying to call that from a dynamic and that's not type-safe.

FMorschel
  • 799
  • 5
  • 18
  • 1
    I'm confused by what you're observing when you say "it will warn you that you are trying to call that from a dynamic and that's not type-safe." If you try your code, you should observe that `variable` is of type `Object` (`R` is constrained to `Object`, `when` returns an `R?`, and `!` forces the `R?` to `R`). – jamesdlin Apr 17 '23 at 16:12
  • 1
    Anyway, I'm fairly certain that compile-time type constraints cannot do what you want and that you would need to rely on a runtime `as R` cast. – jamesdlin Apr 17 '23 at 16:14

2 Answers2

1

As I've asked in an issue. There is no way for me to do what I want (at the moment). If you want more information, you can look here, I'm going to follow this issue as suggested in the comment linked before, so that when this new feature releases I'm aware. Thank you for the responses!

FMorschel
  • 799
  • 5
  • 18
0

Please replace this with following signature and usage

void main() {
  final variable = 1.when<num, int>(
    (self) => self.isEven,
    otherwise: (self) => self + 0.5,
  );

  print(variable?.toInt());
}

extension When on dynamic {
  R? when<R, T extends R>(bool Function(T self) predicate,
      {R Function(T self)? otherwise}) {
    if (predicate(this)) return this;
    return otherwise?.call(this);
  }
}

Output: 1

Rahul
  • 3,529
  • 1
  • 5
  • 19