{"action":"created","issue":{"url":"https://api.github.com/repos/ReactiveX/RxJS/issues/453","labels_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/453/labels{/name}","comments_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/453/comments","events_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/453/events","html_url":"https://github.com/ReactiveX/RxJS/issues/453","id":109577087,"number":453,"title":"publishBehavior and publishReplay semantics when completed","user":{"login":"staltz","id":90512,"avatar_url":"https://avatars.githubusercontent.com/u/90512?v=3","gravatar_id":"","url":"https://api.github.com/users/staltz","html_url":"https://github.com/staltz","followers_url":"https://api.github.com/users/staltz/followers","following_url":"https://api.github.com/users/staltz/following{/other_user}","gists_url":"https://api.github.com/users/staltz/gists{/gist_id}","starred_url":"https://api.github.com/users/staltz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/staltz/subscriptions","organizations_url":"https://api.github.com/users/staltz/orgs","repos_url":"https://api.github.com/users/staltz/repos","events_url":"https://api.github.com/users/staltz/events{/privacy}","received_events_url":"https://api.github.com/users/staltz/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/ReactiveX/RxJS/labels/type:%20discussion","name":"type: discussion","color":"207de5"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":57,"created_at":"2015-10-02T21:42:51Z","updated_at":"2015-11-04T16:51:18Z","closed_at":null,"body":"Continuing the discussion that started here: https://github.com/ReactiveX/RxJS/pull/235/files\r\n\r\nRxJS Legacy (v4) passes these tests:\r\n```js\r\nvar results1 = [];\r\nvar results2 = [];\r\nvar subscriptions = 0;\r\n\r\nvar source = Rx.Observable.create(function (observer) {\r\n  subscriptions++;\r\n  observer.onNext(1);\r\n  observer.onNext(2);\r\n  observer.onNext(3);\r\n  observer.onNext(4);\r\n  observer.onCompleted();\r\n});\r\n\r\nvar hot = source.shareValue(0);\r\n\r\nhot.subscribe(x => results1.push(x));\r\n\r\nexpect(results1).toBe([0,1,2,3,4]);\r\nexpect(results2).toBe([]);\r\n\r\nhot.subscribe(x => results2.push(x));\r\n\r\nexpect(results1).toBe([0,1,2,3,4]);\r\nexpect(results2).toBe([]);\r\nexpect(subscriptions).toBe(2);\r\n```\r\nand\r\n```js\r\nvar results1 = [];\r\nvar results2 = [];\r\nvar subscriptions = 0;\r\n\r\nvar source = Rx.Observable.create(function (observer) {\r\n  subscriptions++;\r\n  observer.onNext(1);\r\n  observer.onNext(2);\r\n  observer.onNext(3);\r\n  observer.onNext(4);\r\n  observer.onCompleted();\r\n});\r\n\r\nvar hot = source.shareReplay(2);\r\n\r\nhot.subscribe(x => results1.push(x));\r\n\r\nexpect(results1).toBe([1,2,3,4]);\r\nexpect(results2).toBe([]);\r\n\r\nhot.subscribe(x => results2.push(x));\r\n\r\nexpect(results1).toBe([1,2,3,4]);\r\nexpect(results2).toBe([3,4]);\r\nexpect(subscriptions).toBe(2);\r\n```\r\n\r\nYet RxJS Next behaves basically the opposite way:\r\n```\r\nFailures:\r\n1) Observable.prototype.publishBehavior() should not emit next events to observer after completed\r\n  Message:\r\n    Expected [ 0 ] to equal [  ].\r\n  Stack:\r\n    Error: Expected [ 0 ] to equal [  ].\r\n      at Object.<anonymous> (./RxJSNext/spec/operators/publishBehavior-spec.js:65:21)\r\n2) Observable.prototype.publishReplay() should emit replayed events to observer after completed\r\n  Message:\r\n    Expected [  ] to equal [ 3, 4 ].\r\n  Stack:\r\n    Error: Expected [  ] to equal [ 3, 4 ].\r\n      at Object.<anonymous> (./RxJSNext/spec/operators/publishReplay-spec.js:98:21)\r\n145 specs, 2 failures\r\nFinished in 12.951 seconds\r\n```\r\n\r\nBecause in RxJS legacy there is\r\n```js\r\n    ConnectableObservable.prototype._subscribe = function (o) {\r\n      return this._subject.subscribe(o);\r\n    };\r\n```\r\n\r\nWhile in RxJS Next:\r\n```ts\r\nclass ConnectableObservable<T> extends Observable<T> {\r\n  subject: Subject<T>;\r\n\r\n  // ...\r\n\r\n  _subscribe(subscriber) {\r\n    return this._getSubject().subscribe(subscriber);\r\n  }\r\n\r\n  _getSubject() {\r\n    const subject = this.subject;\r\n    if (subject && !subject.isUnsubscribed) {\r\n      return subject;\r\n    }\r\n    // Subject will be recreated\r\n    return (this.subject = this.subjectFactory());\r\n  }\r\n\r\n  // ...\r\n}\r\n```\r\n\r\n- - -\r\n\r\nIn my opinion, the new behavior in RxJS Next is illogical at first sight, and a potential source for a lot of developer confusion. Besides that, it differs from RxJS legacy features, making migration a potential headache. I think the semantics argument (with regard to subscriptions after complete(), publishReplay should behave just like a ReplaySubject and publishBehavior should behave just like a BehaviorSubject) is straightforward and also aligned with traditional Rx, such as in Rx.NET: [check Lee Campbells book on this part](http://introtorx.com/Content/v1.0.10621.0/14_HotAndColdObservables.html#OtherConnectables)."},"comment":{"url":"https://api.github.com/repos/ReactiveX/RxJS/issues/comments/153789626","html_url":"https://github.com/ReactiveX/RxJS/issues/453#issuecomment-153789626","issue_url":"https://api.github.com/repos/ReactiveX/RxJS/issues/453","id":153789626,"user":{"login":"trxcllnt","id":178183,"avatar_url":"https://avatars.githubusercontent.com/u/178183?v=3","gravatar_id":"","url":"https://api.github.com/users/trxcllnt","html_url":"https://github.com/trxcllnt","followers_url":"https://api.github.com/users/trxcllnt/followers","following_url":"https://api.github.com/users/trxcllnt/following{/other_user}","gists_url":"https://api.github.com/users/trxcllnt/gists{/gist_id}","starred_url":"https://api.github.com/users/trxcllnt/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/trxcllnt/subscriptions","organizations_url":"https://api.github.com/users/trxcllnt/orgs","repos_url":"https://api.github.com/users/trxcllnt/repos","events_url":"https://api.github.com/users/trxcllnt/events{/privacy}","received_events_url":"https://api.github.com/users/trxcllnt/received_events","type":"User","site_admin":false},"created_at":"2015-11-04T16:51:18Z","updated_at":"2015-11-04T16:51:18Z","body":"@mattpodwysocki that's exactly my point: it's not \"correct\" because someone decided so. It's correct because it's functionally pure, and the behavior is consistent with the rest of the library. \r\n\r\nThe Observable referential transparency is beautiful, allowing them to be retried, etc. In the original design, ConnectableObservables aren't referentially transparent; it behaves differently whether you connect it the first time vs. the second.\r\n\r\nMy argument is the same here as it is in other discussions re: hot-by-default, primarily: if we start from the pure implementation, we can graduate to the impure as-needed. If we start impure, we can never go back to pure.\r\n\r\nI'm arguing for this specifically because I've been bitten by repeat/retry on ConnectableObservable failing."}}