What is Left and Right in the Either module in Flutter? - flutter

I'm looking at some Flutter code that looks like this :
try {
return Right(_doSomethingAndReturnSingleValue());
} on CustomException {
return Left(CustomException());
}
Left and Right are from the core either.dart package, this is the code :
class Left<L, R> extends Either<L, R> {
final L _l;
const Left(this._l);
L get value => _l;
#override B fold<B>(B ifLeft(L l), B ifRight(R r)) => ifLeft(_l);
#override bool operator ==(other) => other is Left && other._l == _l;
#override int get hashCode => _l.hashCode;
}
class Right<L, R> extends Either<L, R> {
final R _r;
const Right(this._r);
R get value => _r;
#override B fold<B>(B ifLeft(L l), B ifRight(R r)) => ifRight(_r);
#override bool operator ==(other) => other is Right && other._r == _r;
#override int get hashCode => _r.hashCode;
}
I'm really struggling to make any sense of what this logic is supposed to do.
Can anyone help me understand what Left() and Right() are for in Dart ?

Left and Right are two generic classes inherited from the same parent, which does almost same thing. The major difference is in the fold method implementation. The left class call the ifLeft callback and right class call the ifRight callback.
For example:
Either<CustomException, String> getSomething() {
try {
return Right(_doSomethingAndReturnSingleValue());
} on CustomException {
return Left(CustomException());
}
}
No matter what happens the above function will return either an object of Either with CustomException (Means Left) or an object of Either with String (Means Right).
Now if you use the function like:
final eitherData = getSomething();
You will be getting an either object (Object of Left or Right). Instead of checking whether that eitherData is of type Left or Right, you can call the fold method on that object like below:
eitherData.fold<Widget>(
(err) => Text('Error Happened: $err'), // ifLeft callback
(data) => Text('Got data: $data'), // ifRight callback
)
As I mentioned earlier based on the object type the corresponding callback will get triggered and you can gracefully handle the success and error cases without writing any if else statements or type checks.

Related

How can I print the last item in the stack? (using dart)

class CustomStack<T> {
final _list = <T>[];
void push(T value) => _list.add(value);
T pop() => _list.removeLast();
T get top => _list.last;
bool get isEmpty => _list.isEmpty;
bool get isNotEmpty => _list.isNotEmpty;
int get length => _list.length;
#override
String toString() => _list.toString();
}
void main() {
CustomStack<String> plates = CustomStack();
//Add plates into the stack
plates.push("Plate1");
plates.push("Plate2");
plates.push("Plate3");
plates.push("Plate Extra");
print(plates);
print(plates[plates.length-1]);
}
I get an error in the last line "The operator '[]' isn't defined for the type 'CustomStack'."
How can I control the index in the stack.
I want to print only "Plate Extra" on the screen.
There is no need to use that structure plates[plates.length-1] if getting the last element is possible with the built function. If you want to get the last item in Custom Stack, you can define a function in your Custom Stack.
T get peek => _list.last;

How to make inheritance hierarchy for Type Converter of Dart Floor?

As below, I define ListConverter<T> to make inheritance hierarchy.
abstract class ListConverter<T> extends TypeConverter<List<T>, String> {
static const delimiter = "!DELIMITER!";
T fromDB(String databaseValue);
String toDB(T value);
#override
List<T> decode(String databaseValue) {
return databaseValue
.split(delimiter)
.where((element) => element.isNotEmpty)
.map((e) => fromDB(e))
.toList();
}
#override
String encode(List<T> value) {
return value.map((e) => toDB(e)).join(delimiter);
}
}
Using ListConverter<T>, I implement IntListConverter.
class IntListConverter extends ListConverter<int> {
#override
int fromDB(String databaseValue) {
return int.parse(databaseValue);
}
#override
String toDB(int value) {
return value.toString();
}
}
My plan was to use ListConverter<T> also on StringListConverter, etc.
But unfortunately, I got this error message while running floor_generator.
[SEVERE] floor_generator:floor_generator on lib/persistence/db/app_database.dart:
Only classes that inherit from TypeConverter can be used as type converters. Make sure use a class that inherits from TypeConverter.
I know that Hierarchy (B) works well, but I want to build (A) structure for managing other list converters.
(A) TypeConverter -> ListConverter -> IntListConverter
(B) TypeConverter -> IntListConverter
How to make inheritance hierarchy for Type Converter of Dart Floor?
I resolved this problem in a roundabout way.
I use mixin keyword instead of direct inheritance.
class IntListConverter extends TypeConverter<List<int>, String>
with ListConverter<int> {
#override
int fromDB(String databaseValue) {
return int.parse(databaseValue);
}
#override
String toDB(int value) {
return value.toString();
}
}

How to use generics with freezed sealed union objects?

I have a Flutter class that uses Freezed to create a sealed union that represents either data or an error:
#freezed
class DataOrError<T, E> with _$DataOrError {
const factory DataOrError.loading() = Loading;
const factory DataOrError.data(T data) = DataOrE<T, E>;
const factory DataOrError.error(E error) = DOrError<T, E>;
static DataOrError<T, E> fromEither<T, E>(Either<E, T> val) {
final result = val.fold(
(l) => DataOrError<T, E>.error(l), (r) => DataOrError<T, E>.data(r));
return result;
}
}
I use riverpod so I have a riverpod StateNotifier that looks like:
class RolesNotifier
extends StateNotifier<DataOrError<List<Role>, RoleFailure>> {
final Ref _ref;
StreamSubscription? sub;
RolesNotifier(Ref ref)
: _ref = ref,
super(const DataOrError.loading());
/// Will run the fetch
void fetch() {
// fetch roles
state = const DataOrError.loading();
sub = _ref.read(firebaseRoleService).getRoles().listen((event) {
state = DataOrError.fromEither<List<Role>, RoleFailure>(event);
});
}
// ... this class has been shortened for simplicity.
}
final rolesProvider = StateNotifierProvider.autoDispose<RolesNotifier,
DataOrError<List<Role>, RoleFailure>>((ref) {
return RolesNotifier(ref);
});
When I consume this provider; however, the types for DataOrError are gone:
ref
.read(rolesProvider)
.when(loading: (){}, data: (d) {
// d is dynamic type not List<Role>
}, error: (e){});
For some reason both d and e are dynamic types and not List<Role> & RoleFailure respectively. Everything appears to be typed correctly so why is this not working? I'm not sure if the error is with Freezed or Riverpod. I would like to avoid type casting (i.e. d as List<Role>) because that defeats the purpose of the generics.
The mixin has to be defined with the same generic types Like
class DataOrError<T, E> with _$DataOrError<T,E>
Although if you did not explicitly define the mixin generics ,the runner will mimic the original class types but in that case there will be no relation between them. in our case it will be a different set of T and E that is why it will be dynamic , bottom line is that you have to tell the mixin that it is indeed the same set of types.
Your code seems to be setup correctly, my intuition is that the types are not being inferred because you are using ref.read. This may be intentional in riverpod for some reason.
Finally, using ref.read inside the build method is an anti-pattern and your UI will not change whenever the state notifier updates.
Replace ref.read(rolesProvider) with:
ref.watch(rolesProvider).when(
loading: (){},
data: (d) {}, // Types should be inferred correctly now
error: (e){},
);

How can I test a method and to mock another method that are in the same class in Flutter

Description:
I have already tested methodA() and methodB() so I can be sure that they are covered.
What are the ways to test methodToBeTested() by mocking methodA() and methodB() that are in the same file? The parameters are passed through the methodToBeTested() to the methodA() and methodB() to properly test these methods using injection.
Note: They are cannot be extracted to a different class since it is a related logic of the calculation service and these methods are already atomically is separated.
Code:
class ClassForTesting {
int methodToBeTested(String a, String b) {
// Calculation in this method also is a bit more difficult
return methodA() + methodB();
}
int methodA(String a) {
int value = 1;
// Here is calculation logic that has been tested
return value;
}
int methodB(String b) {
int value = 2;
// Here is calculation logic that has been tested
return value;
}
}
What has been done:
I have tried several approaches from Mockito, but it doesn't allow to do such a trick:
#GenerateMocks - is creating a mock and requires me to stub each method using when(), even methodToBeTested().
By extending Fake using the next construction:
class Mock extends Fake implements PasswordValidatorService {}
But in this way, I'm only inheriting the PasswordValidatorService's behavior instead of instead implementation and each non-overridden method throws UnimplementedError. Thus, I'm not able to override methodToBeTested() and call its super implementation.
I found that Mockito for Java has #Spy construction that would be perfect in this case but unfortunately it is not available for Dart and Flutter.
The only way I currently came is to create my own Mock:
class MockClassForTesting extends ClassForTesting {
#override
int methodA() {
return 2;
}
#override
int methodB() {
return 5;
}
}
But this implementation doesn't allow me to use Mockito's flexibility of when() construction since I must have different methodA() and methodB() returns.
This fact forces me to have additional variables in my MockClassForTesting to achieve when() construction functionality.
The questions:
What would be the best way to achieve my purposes?
Can be the same mocking approach to be used during the Widget testing?
One approach would be to use a hybrid approach where you create your own derived class but where some of its overrides delegate to a Mock implementation. For example:
class ClassForTesting {
int methodToBeTested(String a, String b) {
// Calculation in this method also is a bit more difficult
return methodA(a) + methodB(b);
}
int methodA(String a) {
int value = 1;
// Here is calculation logic that has been tested
return value;
}
int methodB(String b) {
int value = 2;
// Here is calculation logic that has been tested
return value;
}
}
class PartialMockClassForTesting extends ClassForTesting {
final mock = MockClassForTesting();
#override
int methodA(String a) => mock.methodA(a);
#override
int methodB(String b) => mock.methodB(b);
}
#GenerateMocks([ClassForTesting])
void main() {
test('Test partial mock', () {
var partialMock = PartialMockClassForTesting();
when(partialMock.methodA('hello')).thenReturn(42);
when(partialMock.methodA('goodbye')).thenReturn(-42);
when(partialMock.methodB('world')).thenReturn(10);
expect(partialMock.methodToBeTested('hello', 'world'), 52);
expect(partialMock.methodToBeTested('goodbye', 'world'), -32);
});
}
If you want to conditionally mock certain methods, you could have your overrides check boolean flags to conditionally call either the mock or the real implementation. For example:
class PartialMockClassForTesting extends ClassForTesting {
final mock = MockClassForTesting();
final shouldMock = <Function, bool>{};
#override
int methodA(String a) =>
shouldMock[methodA] ?? false ? mock.methodA(a) : super.methodA(a);
#override
int methodB(String b) =>
shouldMock[methodB] ?? false ? mock.methodB(b) : super.methodB(b);
}
#GenerateMocks([ClassForTesting])
void main() {
test('Test partial mock', () {
var partialMock = PartialMockClassForTesting();
partialMock.shouldMock[partialMock.methodA] = true;
partialMock.shouldMock[partialMock.methodB] = true;
...

Extending base List class with extra functionality in Dart language

This question is about Dart language.
I want to have a class which is just a List but with some extra functionality.
For example I have a class named Model:
class Model{
String name;
int type;
Model(this.name, this.type);
}
I know that Model's type could take only four values: from 0 to 3.
And I want to have a method, which can give me a List of Models of specified type, e.g. List<Model> modelCollection.getByType(int type);.
I plan to to have four 'hidden' Lists of the Models (grouped by type) in that class.
Thus I need to override addition and removal of List elements to make that hidden lists being up to date.
How can I realize this as easy as possible?
P.S. I know this is quite simple, but I'm poorly familiar with Object inheritance and can't find proper examples.
P.P.S. I've also checked this but don't know is it outdated or not and didn't catch the idea.
To make a class implement List there are several ways :
Extending ListBase and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends ListBase<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Mixin ListMixin and implementing length, operator[], operator[]= and length= :
import 'dart:collection';
class MyCustomList<E> extends Base with ListMixin<E> {
final List<E> l = [];
MyCustomList();
void set length(int newLength) { l.length = newLength; }
int get length => l.length;
E operator [](int index) => l[index];
void operator []=(int index, E value) { l[index] = value; }
// your custom methods
}
Delegating to an other List with DelegatingList from the quiver package:
import 'package:quiver/collection.dart';
class MyCustomList<E> extends DelegatingList<E> {
final List<E> _l = [];
List<E> get delegate => _l;
// your custom methods
}
Depending on your code each of those options have their advantages. If you wrap/delegate an existing list you should use the last option. Otherwise use one of the two first options depending on your type hierarchy (mixin allowing to extend an other Object).
A basic approach is to extend an Object with IterableMixin. It also seems that you don't even need to override the "length" getter or let's say all methods that the IterableMixin already provides.
import 'dart:collection';
class Model {
String name;
int type;
Model(this.name, this.type) {
}
}
class ModelCollection extends Object with IterableMixin {
List<Model> _models;
Iterator get iterator => _models.iterator;
ModelCollection() {
this._models = new List<Model>();
}
//get one or the first type
Model elementByType(int type) {
for (Model model in _models) {
if (model.type == type) {
return model;
}
}
}
//get all of the same type
List<Model> elementsByType(int type) {
List<Model> newModel = new List<Model>();
for (Model model in _models) {
if (model.type == type) {
newModel.add(model);
}
}
return newModel;
}
add(Model model) {
this._models.add(model);
}
}
Excuse my strong static typing.
You might be interested in quiver.dart's Multimap. It behaves like a Map that allows multiple values per key.
Here's the code on github: https://github.com/google/quiver-dart/blob/master/lib/src/collection/multimap.dart#L20
It's on pub simply as quiver. We'll be hosting the dartdocs somewhere soon.