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

switch with extended classes problem #1970

Closed
camposFabio opened this issue Nov 10, 2021 · 3 comments
Closed

switch with extended classes problem #1970

camposFabio opened this issue Nov 10, 2021 · 3 comments
Labels
request Requests to resolve a particular developer problem

Comments

@camposFabio
Copy link

I creating and app with bloc and cubit and have several classes for each state, all extended from an master class:

@immutable
class TransactionsListState {
  const TransactionsListState();
}

@immutable
class InitTransactionsListState extends TransactionsListState {
  const InitTransactionsListState();
}

@immutable
class LoadingTransactionsListState extends TransactionsListState {
  const LoadingTransactionsListState();
}

@immutable
class LoadedTransactionsListState extends TransactionsListState {
  final List<Transaction> transactions;
  const LoadedTransactionsListState(this.transactions);
}

@immutable
class FatalErrorTransactionsListState extends TransactionsListState {
  const FatalErrorTransactionsListState();
}

I was using an IF-ELSE sequence to treat then on an builder:

 body: BlocBuilder<TransactionsListCubit, TransactionsListState>(
        builder: (context, state) {
          if (state is InitTransactionsListState ||
              state is LoadingTransactionsListState) {
            return const Progress();
          }
          if (state is LoadedTransactionsListState) {  
            final List<Transaction> transactions = state.transactions; /* Point (1) */

but wanted to replace it with switch to make the code more clear:

    body: BlocBuilder<TransactionsListCubit, TransactionsListState>(
        builder: (context, state) {
          switch (state.runtimeType) {
            case InitTransactionsListState:
            case LoadingTransactionsListState:
              return const Progress();
            case LoadedTransactionsListState:  
              final List<Transaction> transactions = state.transactions; /* Point (2) */

The problem is, when I use IF the code analysis identify the state inside the IF in the Point (1) as belonging to the LoadedTransactionsListState class.
When I use the switch this does not occurs and it throws an error:

The getter 'transactions' isn't defined for the class 'TransactionsListState'.

I fix it with an cast:

final List<Transaction> transactions =
                  (state as LoadedTransactionsListState).transactions;

I put an print(state.runtimeType) before the final List line and with IF or switch:

 if (state is LoadedTransactionsListState) {  
      print(state.runtimeType);
      final List<Transaction> transactions = state.transactions; 
 case LoadedTransactionsListState:  
      print(state.runtimeType);
          final List<Transaction> transactions = state.transactions;

Both return the same (correct) type:

I/flutter ( 4104): state: LoadedTransactionsListState

Expected results:
I expected the code analysis to identify the correct class inside the case statement like it identifies using if

Maybe the compiler can identify that in that particular case statement the class can belong to the extented class and not to the master class.

@camposFabio camposFabio added the request Requests to resolve a particular developer problem label Nov 10, 2021
@lrhn
Copy link
Member

lrhn commented Nov 10, 2021

Dart does not have type-checking switches.

You are trying to use runtimeType, and it doesn't work (for much of anything).
In particular, you are checking whether the value of state.runtimeType (a getter which can be overridden to return anything) equals the Type object of a specific type. Even if that is true, it's not enough information to promote state to that type. Dart only promotes on == checks (for nullability) and is/as checks/casts.

I recommend actually using if statements. Not only does it promotes the variable to the tested type on a success, it also works with subtyping (if you ever wanted that).

A switch with more complicated checks, including type-checks, would be pattern matching, #1747, which the language hasn't added yet.

As a general rule, using .runtimeType is not the best solution to any real problem.

@camposFabio
Copy link
Author

@lrhn Thanks for the information. I suspected that the type of check I suggested was complicated.
I usually prefer switch over if since I think it is more cleanner but I think there are situations where if is preferable (like the one above)
Thank you for the insign. I will close this request

@camposFabio
Copy link
Author

already addressed on other request

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
request Requests to resolve a particular developer problem
Projects
None yet
Development

No branches or pull requests

2 participants