Trying to factorize code with generics classes or methods

97 views
Skip to first unread message

Vince Ricosti

unread,
May 24, 2022, 2:10:33 PMMay 24
to Dart Misc
Hi,

I am really new to this language and I am working on a flutter project where I find the code too verbose.
For instance inside a part of the code I can see 2 classes with methods defined like this:
```
@freezed
class RestartVideoRequest with _$RestartVideoRequest {
const RestartVideoRequest._();

factory RestartVideoRequest({
@JsonKey(defaultValue: 'restartVideo') @Default('restartVideo') String cmd,
required int id,
}) = _RestartVideoRequest;

factory RestartVideoRequest.fromJson(Map<String, dynamic> json) =>
_$RestartVideoRequestFromJson(json);

String get command => jsonEncode(toJson());
}
/////////////////////////////////////////////////

@freezed
class StopVideoRequest with _$StopVideoRequest {
const StopVideoRequest._();

factory StopVideoRequest({
@JsonKey(defaultValue: 'stopVideo') @Default('stopVideo') String cmd,
required int id,
}) = _StopVideoRequest;

factory StopVideoRequest.fromJson(Map<String, dynamic> json) => _$StopVideoRequestFromJson(json);

String get command => jsonEncode(toJson());
}

```

So the only differrences are the types ( RestartVideoRequest vs  StopVideoRequest) and the string passed to the factory constructor ( 'restartVideo' vs ' stopVideo'.

Wouldn't be possible to declare some kind of generic class or method to factorize it ?

I have the same problem with the calling method that duplicate the code like this:

```
Future<StopVideoResponse> stopVideo() {
final id = cmdId;
final completer = Completer<StopVideoResponse>();

_channel.sink.add(StopVideoRequest(id: id).command);

_stream.where((data) => responseIdFilter(id, data)).listen((data) {
try {
completer.complete(StopVideoResponse.fromString(data));
} catch (e) {
completer.completeError(e);
}
}).onError((e) {
completer.completeError(e);
});

_stream.where((data) => responseErrorFilter(id, data)).listen((message) {
try {
completer.completeError(ErrorResponse.fromString(message));
} catch (e) {
completer.completeError(e);
}
}).onError((e) {
completer.completeError(e);
});

return completer.future;
}

Future<RestartVideoResponse> restartVideo() {
final id = cmdId;
final completer = Completer<RestartVideoResponse>();

_channel.sink.add(RestartVideoRequest(id: id).command);

_stream.where((data) => responseIdFilter(id, data)).listen((data) {
try {
completer.complete(RestartVideoResponse.fromString(data));
} catch (e) {
completer.completeError(e);
}
}).onError((e) {
completer.completeError(e);
});

_stream.where((data) => responseErrorFilter(id, data)).listen((message) {
try {
completer.completeError(ErrorResponse.fromString(message));
} catch (e) {
completer.completeError(e);
}
}).onError((e) {
completer.completeError(e);
});

return completer.future;
}
```
I am sure it should be possible to factorize all this stuff, I Started some abstract generic class but at the end it never works...

Chris Norman

unread,
May 25, 2022, 5:34:46 AMMay 25
to mi...@dartlang.org
So @freezed is a decorator used with the freezed package. As with the json_annotation package, the code tends towards the verbose, although the latter package is less so.

I'm not sure how they'll deal with subclassing, although you could give it a go. You'll need something to differentiate between the two classes, presumably so you know whether to start or stop your video.

HTH a little.

Take care,

Chris Norman



--
For more ways to connect visit https://dart.dev/community
---
You received this message because you are subscribed to the Google Groups "Dart Misc" group.
To unsubscribe from this group and stop receiving emails from it, send an email to misc+uns...@dartlang.org.
To view this discussion on the web visit https://groups.google.com/a/dartlang.org/d/msgid/misc/0712fb06-db83-4990-a34f-43aba7be693fn%40dartlang.org.

Vince Ricosti

unread,
May 25, 2022, 8:53:38 AMMay 25
to Dart Misc, chris....@googlemail.com
Hi,

it's a shame I cannot factorize the caller functions with something like this:

```
Future<TResp> cmdNoArgs<TReq, TResp>() {
    final id = cmdId;
    final completer = Completer<TResp>();
 
    _channel.sink.add(TReq(id: id).command);
 
    _stream.where((data) => responseIdFilter(id, data)).listen((data) {
      try {
        completer.complete(TResp.fromString(data));
      } catch (e) {
        completer.completeError(e);
      }
    }).onError((e) {
      completer.completeError(e);
    });
 
    _stream.where((data) => responseErrorFilter(id, data)).listen((message) {
      try {
        completer.completeError(ErrorResponse.fromString(message));
      } catch (e) {
        completer.completeError(e);
      }
    }).onError((e) {
      completer.completeError(e);
    });
 
    return completer.future;
  }
```

And I would be able to factorize the code like this:

Future<StopVideoResponse> stopVideo() { return cmdNoArgs<StopVideoRequest, StopVideoRequest>(); }
or
Future<StopVideoResponse> stopVideo()  stopVideo() =  cmdNoArgs<StopVideoRequest, StopVideoRequest>(); 

I mean coming from c++ or other language dart is a bit frustrating.




Vince Ricosti

unread,
May 30, 2022, 11:10:02 AMMay 30
to Dart Misc
Finally I tried 2 defined to abstract classes like this and t ocast inside the generic method but it doesn't work so I give up:

```
import 'dart:convert';

abstract class BaseRequest {
  factory BaseRequest({
    required int id,
  }) {
    return BaseRequest(id: 0);
  }

  factory BaseRequest.fromJson(Map<String, dynamic> json) {
    return BaseRequest(id: 0);
  }

  Map<String, dynamic> toJson() {
    return <String, dynamic>{};
  }

  String get command => jsonEncode(toJson());
}

abstract class BaseResponse {
  factory BaseResponse({required int id}) {
    return BaseResponse(id: 0);
  }

  factory BaseResponse.fromJson(Map<String, dynamic> json) {
    return BaseResponse(id: 0);
  }

  factory BaseResponse.fromString(String message) =>
      BaseResponse.fromJson(jsonDecode(message)['rsp']);
}
```

///--------------------------------------------------------
```
Future<TResp> cmdNoArgs<TReq, TResp>() {
    final id = cmdId;
    final completer = Completer<TResp>();

    _channel.sink.add(TReq as BaseRequest(id: id).command);

    _stream.where((data) => responseIdFilter(id, data)).listen((data) {
      try {
        completer.complete((TResp as BaseResponse).fromString(data));
      } catch (e) {
        completer.completeError(e);
      }
    }).onError((e) {
      completer.completeError(e);
    });

    _stream.where((data) => responseErrorFilter(id, data)).listen((message) {
      try {
        completer.completeError(ErrorResponse.fromString(message));
      } catch (e) {
        completer.completeError(e);
      }
    }).onError((e) {
      completer.completeError(e);
    });

    return completer.future;
  }
```

Inside the generic method I get 
_channel.sink.add((TReq as BaseRequest)(id: id).command);     // Error: The expression does not evaluate to a function, so it can't be invoked
completer.complete((TResp as BaseResponse).fromString(data));     //  Error:  The method fromString isn't defined for the type 'BaseResponse'.

  
Reply all
Reply to author
Forward
0 new messages