These are chat archives for systemjs/systemjs

22nd
Nov 2017
Aluan Haddad
@aluanhaddad
Nov 22 2017 21:05
@mlc-mlapis :D I hope so
Aluan Haddad
@aluanhaddad
Nov 22 2017 21:33

That would imply a clear role:
Observable ===> async push sequence.
This is the role that Eric Miejer, the creator of Rx, indicates in this enlightening (and hilarious) talk: https://channel9.msdn.com/events/Lang-NEXT/Lang-NEXT-2014/Keynote-Duality?term=Duality%20and%20the%20End%20of%20Reactive

In short, for some T:


sync One ===> T               |  async One ===> Task[T]

sync Many ===> Enumerable[T]  |  async Many ===> Observable[T]

However, The requirement to allow synchronous observation as discussed in several https://github.com/tc39/proposal-observable issues on GitHub, suggests much broader usage wherein Observable may subsume Enumerable(Iterable or Array).

Furthermore, the way RxJS has been ussed, for example in Angular, ammounts to a style where Stream (Observable) also subumes Tasklikes (Promise or Thennable). The Angular Http library is a good example of this because a single request, is represented as an Obervable that only ever produces a single response. The argument about composing multiple requests, is moot because you need to call Rx.Observable.prototype.flatMap or Rx.Observable.prototype.switchMap to project the resulting stream of requests and these operations are implemented such that they lift Promises to Observables anyway.

Miloš Lapiš
@mlc-mlapis
Nov 22 2017 21:44
@aluanhaddad ... nice to see ^^^. :sparkles: ... but I am always thinking about Angular Http as a temporary solution because of its stateless historical limitation ... and I am just waiting ... when one connection will emit simply more sequences ... HTTP2 and so on ...
Aluan Haddad
@aluanhaddad
Nov 22 2017 21:53
Ex:
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/mergeMap';
import {Observable} from 'rxjs/Observable';
import {Http} from '@angular/http';

@injected export default class {
  constructor(readonly http: Http) {}

  getUserWithAvatars(userId: number): Observable<User & AvatarBearer> {
    return this.http.get(`api/users/${userId}`)
      .map(response => response.json() as User) // Observable<User>
        .map(user => this.http.get(`api/images/${user.avatarId}`)
          .map(response => response.json() as Avatar) // Observable<Avatar>
          .map(avatar => ({user, avator}))  // Observable<Observable<{user: User, avatar: Avatar}>>
      )
      .flatMap(innerObservable => innerObservable.map({user, avatar}) => ({
          ...user,
          avatar
       }));
  }
}

function injected(_:{}){}

interface User {id: number; avatarId: number;}
interface AvatarBearer {avatar: Avatar;}
interface Avatar {data: string;}
Aluan Haddad
@aluanhaddad
Nov 22 2017 22:00
With promises:
import SimpleHttp from 'app/service/simple-http.service';

@injected export default class {
  constructor(readonly http: SimpleHttp) {}

  async getUserWithAvatars(userId: number): Promise<User & AvatarBearer> {
    const user = await this.getUser();
    const avatar = await this.getAvatar(user.id);

    return {
      ...user,
      avatar
    };
  }

  async getUser() {
    const response = await this.http.get(`api/users/${userId}`);
    return response.json() as User;
  }

  async getAvatar(avatarId: number) {
    const response = await this.http.get(`api/images/${avatarId}`);
    return response.json() as Avatar;
  }
}

function injected(_: {}) {}

interface User {id: number; avatarId: number;}
interface AvatarBearer {avatar: Avatar;}
interface Avatar {data: string;}
Aluan Haddad
@aluanhaddad
Nov 22 2017 22:06

@mlc-mlapis

but I am always thinking about Angular Http as a temporary solution because of its stateless historical limitation ... and I am just waiting ... when one connection will emit simply more sequences ... HTTP2 and so on ...

Very good point, that is a perfect use case for Observable.

But consider the relative clarity of the two bog standard examples, above.

The point is use Observables when you actually have a stream, but use the singular async abstractions when you have only one value

Aluan Haddad
@aluanhaddad
Nov 22 2017 22:32
Now, one might argue that it is the async/await sugar that makes the second version more readable.
So consider an example in the language where Observable was conceived, where they were designed around leveraging existing generalized monad comprehension syntax that the language already possessed.
In C#
class UserService
{
    public UserService(Http http) => this.http = http;

    public Observable<UserWithAvatar> GetUserWithAvatar(int userId) =>
        from response in http.get($"api/users/{userId}")
        let user = JsonConvert.DeserializeObject<User>(response.Body)
        select user into $user
        from user in $user
        from response in http.get($"api/avatars/{user.AvatarId}")
        let avatar = JsonConvert.DeserializeObject<Avatar>(response.Body)
        select  new UserWithAvatar
        {
            Id = user.Id,
            Avatar = avatar,
            AvatarId = avatar.id
        } into $userWithAvatar
        from userWithAvatar in $userWithAvatar
        select userWithAvatar;

    readonly Http http;      
}

class UserWithAvatar: User, IAvatarBearer
{
    public Avatar Avatar { get; set; }
    public int AvatarId { get; set; }
}
Miloš Lapiš
@mlc-mlapis
Nov 22 2017 23:09
@aluanhaddad ... yeah, ... we should also count with one of the assumptions ... that one reason why Angular Http was based on Observable is the simple fact that the one and the same pattern is a simpler way than two or more patterns which could be even better from some point of view.
Aluan Haddad
@aluanhaddad
Nov 22 2017 23:28

I'm not sure I buy that (keep in mind I enjoy debating).

Firstly Promises are ubiquitous, even developers who stick to Angular will need to understand them to use third part libraries and extenions. For example, Ionic uses promises heavily.

Secondly, whiel there are always gotchas, as with every feature, Promises are fairly simple to consume and async/await makes them trivial to compose. Even without that sugar, you don't need to know that .then is a monadic bind operator (flatMap/SelectMany).

Thirdly, we need representations for all of these things. I'll let Kris Kowal argue that though: https://github.com/kriskowal/gtor#a-general-theory-of-reactivity

Aluan Haddad
@aluanhaddad
Nov 22 2017 23:33
I had some mistakes and issues in my C# example (that's what I get for coding in the gitter message composition pane), so I made a just with a working version: https://gist.github.com/aluanhaddad/7c29fe4a7230557772b105c617a8f8f2