From 555b0d031e9e9557d2a06d6efec0e920e5c7b145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petrus=20Nguy=E1=BB=85n=20Th=C3=A1i=20H=E1=BB=8Dc?= Date: Sun, 21 Aug 2022 20:02:15 +0700 Subject: [PATCH] refactor impl (#10) * refactor impl * refactor impl --- lib/src/dart_either.dart | 92 ++++++++++++++++++++-------------------- 1 file changed, 45 insertions(+), 47 deletions(-) diff --git a/lib/src/dart_either.dart b/lib/src/dart_either.dart index 4ccdc4b..7e0b026 100644 --- a/lib/src/dart_either.dart +++ b/lib/src/dart_either.dart @@ -16,9 +16,6 @@ extension on Object { if (this is ControlError) { throw this; } - if (this is _InvalidEitherError) { - throw this; - } return this; } } @@ -76,6 +73,23 @@ T Function(Object?) _const(T t) => (_) => t; abstract class Either { const Either._(); + Object? get _unionValue; + + @pragma('vm:always-consider-inlining') + @pragma('vm:prefer-inline') + @pragma('dart2js:tryInline') + C _foldInternal({ + required C Function(L value) ifLeft, + required C Function(R value) ifRight, + }) { + if (isLeft) { + return ifLeft(_unionValue as L); + } else { + assert(isRight); + return ifRight(_unionValue as R); + } + } + // ----------------------------------------------------------------------------- // // BEGIN: constructors @@ -417,13 +431,11 @@ abstract class Either { final result = ListBuilder(); for (final either in values) { - if (either is Left) { - return Either>.left(either.value); - } - if (either is Right) { - result.add(either.value); + if (either.isLeft) { + return Either>.left(either._unionValue as L); } else { - throw _InvalidEitherError(either); + assert(either.isRight); + result.add(either._unionValue as R); } } @@ -476,11 +488,11 @@ abstract class Either { // ----------------------------------------------------------------------------- /// Returns `true` if this is a [Left], `false` otherwise. - /// Used only for performance instead of fold. + /// Used only for performance instead of [fold]. bool get isLeft; /// Returns `true` if this is a [Right], `false` otherwise. - /// Used only for performance instead of fold. + /// Used only for performance instead of [fold]. bool get isRight; /// Applies [ifLeft] if this is a [Left] or [ifRight] if this is a [Right]. @@ -503,16 +515,8 @@ abstract class Either { C fold({ required C Function(L value) ifLeft, required C Function(R value) ifRight, - }) { - final self = this; - if (self is Left) { - return ifLeft(self.value); - } - if (self is Right) { - return ifRight(self.value); - } - throw _InvalidEitherError(self); - } + }) => + _foldInternal(ifLeft: ifLeft, ifRight: ifRight); /// If this is a [Right], applies [ifRight] with [initial] and [Right.value]. /// Returns [initial] otherwise. @@ -525,7 +529,8 @@ abstract class Either { /// /// result.foldLeft(initial, combine); // Result: 'dart_either hoc081098' /// ``` - C foldLeft(C initial, C Function(C acc, R element) rightOperation) => fold( + C foldLeft(C initial, C Function(C acc, R element) rightOperation) => + _foldInternal( ifLeft: _const(initial), ifRight: (r) => rightOperation(initial, r), ); @@ -537,7 +542,7 @@ abstract class Either { /// Left('left').swap(); // Result: Right('left') /// Right('right').swap(); // Result: Left('right') /// ``` - Either swap() => fold( + Either swap() => _foldInternal( ifLeft: (l) => Either.right(l), ifRight: (r) => Either.left(r), ); @@ -549,7 +554,7 @@ abstract class Either { /// Right(12).map((_) => 'flower'); // Result: Right('flower') /// Left(12).map((_) => 'flower'); // Result: Left(12) /// ``` - Either map(C Function(R value) f) => fold( + Either map(C Function(R value) f) => _foldInternal( ifLeft: (l) => Either.left(l), ifRight: (r) => Either.right(f(r)), ); @@ -561,7 +566,7 @@ abstract class Either { /// Right(12).mapLeft((_) => 'flower'); // Result: Right(12) /// Left(12).mapLeft((_) => 'flower'); // Result: Left('flower') /// ``` - Either mapLeft(C Function(L value) f) => fold( + Either mapLeft(C Function(L value) f) => _foldInternal( ifLeft: (l) => Either.left(f(l)), ifRight: (r) => Either.right(r), ); @@ -581,7 +586,7 @@ abstract class Either { /// Left('12').flatMap((v) => Right('flower $v')); // Result: Left('12') /// Left('12').flatMap((v) => Left('flower $v')); // Result: Left('12') /// ``` - Either flatMap(Either Function(R value) f) => fold( + Either flatMap(Either Function(R value) f) => _foldInternal( ifLeft: (l) => Either.left(l), ifRight: (r) => f(r), ); @@ -612,7 +617,7 @@ abstract class Either { required C Function(L value) leftOperation, required D Function(R value) rightOperation, }) => - fold( + _foldInternal( ifLeft: (l) => Either.left(leftOperation(l)), ifRight: (r) => Either.right(rightOperation(r)), ); @@ -628,7 +633,7 @@ abstract class Either { /// Left(12).exists((v) => v > 10); // Result: false /// Left(12).exists((v) => v < 10); // Result: false /// ``` - bool exists(bool Function(R value) predicate) => fold( + bool exists(bool Function(R value) predicate) => _foldInternal( ifLeft: _const(false), ifRight: predicate, ); @@ -640,7 +645,7 @@ abstract class Either { /// Right(12).getOrElse(() => 17); // Result: 12 /// Left(12).getOrElse(() => 17); // Result: 17 /// ``` - R getOrElse(R Function() defaultValue) => fold( + R getOrElse(R Function() defaultValue) => _foldInternal( ifLeft: (_) => defaultValue(), ifRight: _identity, ); @@ -652,7 +657,7 @@ abstract class Either { /// Right(12).orNull(); // Result: 12 /// Left(12).orNull(); // Result: null /// ``` - R? orNull() => fold( + R? orNull() => _foldInternal( ifLeft: _const(null), ifRight: _identity, ); @@ -665,7 +670,7 @@ abstract class Either { /// Right(12).getOrHandle((v) => 17); // Result: 12 /// Left(12).getOrHandle((v) => v + 5); // Result: 17 /// ``` - R getOrHandle(R Function(L value) defaultValue) => fold( + R getOrHandle(R Function(L value) defaultValue) => _foldInternal( ifLeft: defaultValue, ifRight: _identity, ); @@ -694,14 +699,12 @@ abstract class Either { required C Function(Left left) ifLeft, required C Function(Right right) ifRight, }) { - final self = this; - if (self is Left) { - return ifLeft(self); - } - if (self is Right) { - return ifRight(self); + if (isLeft) { + return ifLeft(this as Left); + } else { + assert(isRight); + return ifRight(this as Right); } - throw _InvalidEitherError(self); } } @@ -729,6 +732,9 @@ class Left extends Either { @override String toString() => 'Either.Left($value)'; + + @override + L get _unionValue => value; } /// The right side of the disjoint union, as opposed to the [Left] side. @@ -755,17 +761,9 @@ class Right extends Either { @override String toString() => 'Either.Right($value)'; -} - -class _InvalidEitherError extends Error { - final Either invalid; - - _InvalidEitherError(this.invalid); @override - String toString() => - 'Unknown $invalid. $invalid must be either a `Right<$L, $R>` or `Left<$L, $R>`.' - ' Cannot implement or extend `Either` class'; + R get _unionValue => value; } // -----------------------------------------------------------------------------