{"action":"created","issue":{"url":"https://api.github.com/repos/staltz/xstream/issues/5","repository_url":"https://api.github.com/repos/staltz/xstream","labels_url":"https://api.github.com/repos/staltz/xstream/issues/5/labels{/name}","comments_url":"https://api.github.com/repos/staltz/xstream/issues/5/comments","events_url":"https://api.github.com/repos/staltz/xstream/issues/5/events","html_url":"https://github.com/staltz/xstream/issues/5","id":150836066,"number":5,"title":"imitate() should be lazy to add and to remove","user":{"login":"milankinen","id":1080706,"avatar_url":"https://avatars.githubusercontent.com/u/1080706?v=3","gravatar_id":"","url":"https://api.github.com/users/milankinen","html_url":"https://github.com/milankinen","followers_url":"https://api.github.com/users/milankinen/followers","following_url":"https://api.github.com/users/milankinen/following{/other_user}","gists_url":"https://api.github.com/users/milankinen/gists{/gist_id}","starred_url":"https://api.github.com/users/milankinen/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/milankinen/subscriptions","organizations_url":"https://api.github.com/users/milankinen/orgs","repos_url":"https://api.github.com/users/milankinen/repos","events_url":"https://api.github.com/users/milankinen/events{/privacy}","received_events_url":"https://api.github.com/users/milankinen/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/staltz/xstream/labels/issue%20is%20bug","name":"issue is bug","color":"ee0701"},{"url":"https://api.github.com/repos/staltz/xstream/labels/weight%203%20(should)","name":"weight 3 (should)","color":"888888"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":7,"created_at":"2016-04-25T12:05:05Z","updated_at":"2016-04-26T12:14:07Z","closed_at":null,"body":"It seems that imitate does not provide any way to \"dispose\" the imitation, thus it leaves the imitated stream open, even though the imitating stream closes.\r\n\r\nLet's take a look at the following code:\r\n```js\r\nimport xs from \"xstream\"\r\n\r\nconst state = xs.never()\r\n  .map(x => x + 1)\r\n  .fold((y, x) => y + x, 0)\r\n\r\nconst actions = xs.periodic(100).debug(console.log.bind(console))\r\nstate.imitate(actions)\r\n\r\nstate.take(10).addListener({\r\n  next: x => console.log(\"next\", x),\r\n  complete: () => console.log(\"complete\"),\r\n  error: e => console.error(e)\r\n})\r\n```\r\n\r\nNow the `state` stream get's closed after ten events but `actions` never get's disposed, even though it should. \r\n\r\nBecause `imitate` is meant to replace Rx `Subject` as a way to model circular dependencies, I'd like to propose a little bit different API that handles the same problem but in the same time is *automatically* garbage collected: `Stream.looped() : LoopedStream` and `Stream.prototype.loopTo(LoopedStream) : void`\r\n\r\nThe idea would be that *only values* get looped, thus it'd be almost trivial to make an implementation that gets the source stream events but also so that it also disposes the source stream during it's own disposal.\r\n\r\nAn (imaginary) API example:\r\n```js\r\nconst loopedActions = xs.looped()\r\nconst state = loopedActions\r\n  .map(x => x + 1)\r\n  .fold((y, x) => y + x, 0)\r\n\r\nxs.periodic(100).debug(console.log.bind(console)).loopTo(loopedActions)\r\n\r\nstate.take(10).addListener({\r\n  next: x => console.log(\"next\", x),\r\n  complete: () => console.log(\"complete\"),\r\n  error: e => console.error(e)\r\n})\r\n```\r\nAny thoughts?"},"comment":{"url":"https://api.github.com/repos/staltz/xstream/issues/comments/214720271","html_url":"https://github.com/staltz/xstream/issues/5#issuecomment-214720271","issue_url":"https://api.github.com/repos/staltz/xstream/issues/5","id":214720271,"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},"created_at":"2016-04-26T12:14:07Z","updated_at":"2016-04-26T12:14:07Z","body":"I think I see it as, given\r\n```js\r\nvar proxy$ = xs.create();\r\nvar real$ = // ...\r\nproxy$.imitate(real$);\r\n```\r\n\r\nproxy$ start only when real$ starts, and stop only when real$ stops, regardless of what listeners proxy$ has. We may need to add some hooks to stream.start and stream.stop, or change the logic for refCounting to auto-start."}}