Repository: fluture-js/Fluture
Pull request #74 (2017-02-14 18:06:59)

Flip the argument order of Future.or
I though `and` had the wrong order of arguments, but *really* it was `or` all-along. I think both `and` and `or` should have non-inverted arguments (as opposed to most static functions), so:

```js
Future.ap(a, b)  === b.ap(a);
Future.or(a, b)  === a.or(b);
Future.and(a, b) === a.and(b);
```

I think this is much more expected behavior, and has the arguments in the right order for `reduce`.


Patch:
diff --git a/README.md b/README.md
index d0f34ff..b2e0101 100644
--- a/README.md
+++ b/README.md
@@ -666,6 +666,11 @@ if the first rejects.
 //An asynchronous version of:
 //const result = isResolved() && getValue();
 const result = isResolved().and(getValue());
+
+//Asynchronous "all", where the resulting Future will be the leftmost to reject:
+const all = ms => ms.reduce(Future.and, Future.of(true));
+all([Future.after(20, 1), Future.of(2)]).value(console.log);
+//> 2
 ```
 
 #### or
@@ -686,13 +691,10 @@ if the second has side-effects, they will run even if the first resolves.
 //const result = planA() || planB();
 const result = planA().or(planB());
 
-const program = S.pipe([
-  reject,
-  or(of('second chance')),
-  value(console.log)
-]);
-program('first chance')
-> "second chance"
+//Asynchronous "any", where the resulting Future will be the leftmost to resolve:
+const any = ms => ms.reduce(Future.or, Future.reject('empty list'));
+any([Future.reject(1), Future.after(20, 2), Future.of(3)]).value(console.log);
+//> 2
 ```
 
 In the example, assume both plans return Futures. Both plans are executed in
diff --git a/fluture.js b/fluture.js
index a8ec7d1..2b3eeb6 100644
--- a/fluture.js
+++ b/fluture.js
@@ -513,15 +513,15 @@
     return race$right(right, left);
   };
 
-  function or$right(right, left){
-    if(!isFuture(left)) invalidArgument('Future.or', 1, 'be a Future', left);
+  function or$left(left, right){
+    if(!isFuture(right)) invalidArgument('Future.or', 1, 'be a Future', right);
     return new FutureOr(left, right);
   }
 
-  Future.or = function or(right, left){
-    if(!isFuture(right)) invalidArgument('Future.or', 0, 'be a Future', right);
-    if(arguments.length === 1) return unaryPartial(or$right, right);
-    return or$right(right, left);
+  Future.or = function or(left, right){
+    if(!isFuture(left)) invalidArgument('Future.or', 0, 'be a Future', left);
+    if(arguments.length === 1) return unaryPartial(or$left, left);
+    return or$left(left, right);
   };
 
   function finally$right(right, left){


Test patch:
diff --git a/test/5.future-and.test.js b/test/5.future-and.test.js
index ca421c2..b2605c5 100644
--- a/test/5.future-and.test.js
+++ b/test/5.future-and.test.js
@@ -101,9 +101,21 @@ describe('Future.and()', () => {
     expect(f).to.throw(TypeError, /Future.*second/);
   });
 
-  //TODO: Argument order.
   testInstance((a, b) => Future.and(a, b));
 
+  it('allows for the implementation of `all` in terms of reduce', () => {
+    const all = ms => ms.reduce(Future.and, Future.of(true));
+    return Promise.all([
+      U.assertResolved(all([]), true),
+      U.assertRejected(all([F.rejected, F.resolved]), 'rejected'),
+      U.assertRejected(all([F.resolved, F.rejected]), 'rejected'),
+      U.assertResolved(all([F.resolvedSlow, F.resolved]), 'resolved'),
+      U.assertResolved(all([F.resolved, F.resolvedSlow]), 'resolvedSlow'),
+      U.assertRejected(all([F.rejected, F.rejectedSlow]), 'rejected'),
+      U.assertRejected(all([F.rejectedSlow, F.rejected]), 'rejectedSlow')
+    ]);
+  });
+
 });
 
 describe('Future#and()', () => {
diff --git a/test/5.future-or.test.js b/test/5.future-or.test.js
index 8006cdd..01ce68f 100644
--- a/test/5.future-or.test.js
+++ b/test/5.future-or.test.js
@@ -101,11 +101,10 @@ describe('Future.or()', () => {
     expect(f).to.throw(TypeError, /Future.*second/);
   });
 
-  testInstance((a, b) => Future.or(b, a));
+  testInstance((a, b) => Future.or(a, b));
 
   it('allows for the implementation of `any` in terms of reduce', () => {
-    const C = f => (b, a) => f(a, b);
-    const any = ms => ms.reduce(C(Future.or), Future.reject('empty list'));
+    const any = ms => ms.reduce(Future.or, Future.reject('empty list'));
     return Promise.all([
       U.assertRejected(any([]), 'empty list'),
       U.assertRejected(any([Future.reject(1)]), 1),