{"action":"created","comment":{"url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/comments/204030884","pull_request_review_id":139039086,"id":204030884,"node_id":"MDI0OlB1bGxSZXF1ZXN0UmV2aWV3Q29tbWVudDIwNDAzMDg4NA==","diff_hunk":"@@ -0,0 +1,53 @@\n+/* This Source Code Form is subject to the terms of the Mozilla Public\n+ * License, v. 2.0. If a copy of the MPL was not distributed with this\n+ * file, you can obtain one at http://mozilla.org/MPL/2.0/. */\n+\n+package mozilla.components.support.utils.observer\n+\n+/**\n+ * This helper class prevents side effects (glitches) in an <code>Observable</code> implementation\n+ * where an observer can modify the internal state of an <code>Observable</code> from an observer\n+ * callback. In this situation follow-up observers may see a modified state that may conflict with\n+ * the change the observer was notified about.\n+ *\n+ * To avoid those side effects in an <code>Observable</code> create an internal instance of\n+ * <code>SideEffects</code> and wrap methods modifying the <code>Observable</code> state inside\n+ * <code>modifyWithoutSideEffects()</code>. Methods that just read the current state can be wrapped\n+ * in <code>readWithLock</code>.\n+ *\n+ * SideEffects queues modifications to an <code>Observable</code> until all observers have been\n+ * notified and then performs them sequentially\n+ *\n+ * For an example of observer side effects / glitches see SideEffectsTest<code>.\n+ */\n+class SideEffects {\n+    // Those properties have 'internal' visibility with @PublishedApi annotation so that they can be\n+    // inlined by the compiler.\n+\n+    @PublishedApi internal val lock = Any()\n+    @PublishedApi internal val queue: MutableList<() -> Unit> = mutableListOf()\n+    @PublishedApi internal var isProcessing = false\n+\n+    inline fun modifyWithoutSideEffects(crossinline action: () -> Unit): Unit = synchronized(lock) {\n+        if (isProcessing) {\n+            queue.add {\n+                action()\n+            }\n+        } else {\n+            isProcessing = true\n+\n+            action()","path":"components/support/utils/src/main/java/mozilla/components/support/utils/observer/SideEffects.kt","position":39,"original_position":39,"commit_id":"9bdd9ac42fc651c706eecd7ec464948c177dceb4","original_commit_id":"9bdd9ac42fc651c706eecd7ec464948c177dceb4","user":{"login":"pocmo","id":89638,"node_id":"MDQ6VXNlcjg5NjM4","avatar_url":"https://avatars0.githubusercontent.com/u/89638?v=4","gravatar_id":"","url":"https://api.github.com/users/pocmo","html_url":"https://github.com/pocmo","followers_url":"https://api.github.com/users/pocmo/followers","following_url":"https://api.github.com/users/pocmo/following{/other_user}","gists_url":"https://api.github.com/users/pocmo/gists{/gist_id}","starred_url":"https://api.github.com/users/pocmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pocmo/subscriptions","organizations_url":"https://api.github.com/users/pocmo/orgs","repos_url":"https://api.github.com/users/pocmo/repos","events_url":"https://api.github.com/users/pocmo/events{/privacy}","received_events_url":"https://api.github.com/users/pocmo/received_events","type":"User","site_admin":false},"body":"I'm afraid that a `return` statement inside the lambda will jump out of this method because it's getting inlined. I thought `crossinline` would prevent that. But I seem to be able to still use a return@label:\r\n\r\n```\r\nfun someMethod(bar: Foo?) = sideEffects.modifyWithoutSideEffects {\r\n    if (bar == null) {\r\n        // This doesn't compile because of 'crossinline'\r\n        return\r\n    }\r\n\r\n    if (bar == null) {\r\n        // This compiles... but isn't it the same as the one above?\r\n        return@modifyWithoutSideEffects\r\n    }\r\n\r\n    // ...\r\n}\r\n```","created_at":"2018-07-20T12:41:30Z","updated_at":"2018-07-20T12:41:33Z","html_url":"https://github.com/mozilla-mobile/android-components/pull/453#discussion_r204030884","pull_request_url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453","author_association":"COLLABORATOR","_links":{"self":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/comments/204030884"},"html":{"href":"https://github.com/mozilla-mobile/android-components/pull/453#discussion_r204030884"},"pull_request":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453"}}},"pull_request":{"url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453","id":202577927,"node_id":"MDExOlB1bGxSZXF1ZXN0MjAyNTc3OTI3","html_url":"https://github.com/mozilla-mobile/android-components/pull/453","diff_url":"https://github.com/mozilla-mobile/android-components/pull/453.diff","patch_url":"https://github.com/mozilla-mobile/android-components/pull/453.patch","issue_url":"https://api.github.com/repos/mozilla-mobile/android-components/issues/453","number":453,"state":"open","locked":false,"title":"Issue #400: Prevent side effects / glitches in Observable implementations.","user":{"login":"pocmo","id":89638,"node_id":"MDQ6VXNlcjg5NjM4","avatar_url":"https://avatars0.githubusercontent.com/u/89638?v=4","gravatar_id":"","url":"https://api.github.com/users/pocmo","html_url":"https://github.com/pocmo","followers_url":"https://api.github.com/users/pocmo/followers","following_url":"https://api.github.com/users/pocmo/following{/other_user}","gists_url":"https://api.github.com/users/pocmo/gists{/gist_id}","starred_url":"https://api.github.com/users/pocmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pocmo/subscriptions","organizations_url":"https://api.github.com/users/pocmo/orgs","repos_url":"https://api.github.com/users/pocmo/repos","events_url":"https://api.github.com/users/pocmo/events{/privacy}","received_events_url":"https://api.github.com/users/pocmo/received_events","type":"User","site_admin":false},"body":"This is a first version of a helper to fix the issue described in #400.\r\n\r\nIt's not used in any `Observable` yet. We may want to use it in `SessionManager` and `Session` but probably not `EngineSession` implementations because observers do not really modify the internal state.","created_at":"2018-07-19T14:26:12Z","updated_at":"2018-07-20T12:41:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4aeeb70b0ac4252cddba4802b780c9c07501a204","assignee":null,"assignees":[],"requested_reviewers":[],"requested_teams":[],"labels":[],"milestone":null,"commits_url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453/commits","review_comments_url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453/comments","review_comment_url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/comments{/number}","comments_url":"https://api.github.com/repos/mozilla-mobile/android-components/issues/453/comments","statuses_url":"https://api.github.com/repos/mozilla-mobile/android-components/statuses/9bdd9ac42fc651c706eecd7ec464948c177dceb4","head":{"label":"pocmo:observers-without-sideeffects","ref":"observers-without-sideeffects","sha":"9bdd9ac42fc651c706eecd7ec464948c177dceb4","user":{"login":"pocmo","id":89638,"node_id":"MDQ6VXNlcjg5NjM4","avatar_url":"https://avatars0.githubusercontent.com/u/89638?v=4","gravatar_id":"","url":"https://api.github.com/users/pocmo","html_url":"https://github.com/pocmo","followers_url":"https://api.github.com/users/pocmo/followers","following_url":"https://api.github.com/users/pocmo/following{/other_user}","gists_url":"https://api.github.com/users/pocmo/gists{/gist_id}","starred_url":"https://api.github.com/users/pocmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pocmo/subscriptions","organizations_url":"https://api.github.com/users/pocmo/orgs","repos_url":"https://api.github.com/users/pocmo/repos","events_url":"https://api.github.com/users/pocmo/events{/privacy}","received_events_url":"https://api.github.com/users/pocmo/received_events","type":"User","site_admin":false},"repo":{"id":126212737,"node_id":"MDEwOlJlcG9zaXRvcnkxMjYyMTI3Mzc=","name":"android-components","full_name":"pocmo/android-components","owner":{"login":"pocmo","id":89638,"node_id":"MDQ6VXNlcjg5NjM4","avatar_url":"https://avatars0.githubusercontent.com/u/89638?v=4","gravatar_id":"","url":"https://api.github.com/users/pocmo","html_url":"https://github.com/pocmo","followers_url":"https://api.github.com/users/pocmo/followers","following_url":"https://api.github.com/users/pocmo/following{/other_user}","gists_url":"https://api.github.com/users/pocmo/gists{/gist_id}","starred_url":"https://api.github.com/users/pocmo/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/pocmo/subscriptions","organizations_url":"https://api.github.com/users/pocmo/orgs","repos_url":"https://api.github.com/users/pocmo/repos","events_url":"https://api.github.com/users/pocmo/events{/privacy}","received_events_url":"https://api.github.com/users/pocmo/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/pocmo/android-components","description":null,"fork":true,"url":"https://api.github.com/repos/pocmo/android-components","forks_url":"https://api.github.com/repos/pocmo/android-components/forks","keys_url":"https://api.github.com/repos/pocmo/android-components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/pocmo/android-components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/pocmo/android-components/teams","hooks_url":"https://api.github.com/repos/pocmo/android-components/hooks","issue_events_url":"https://api.github.com/repos/pocmo/android-components/issues/events{/number}","events_url":"https://api.github.com/repos/pocmo/android-components/events","assignees_url":"https://api.github.com/repos/pocmo/android-components/assignees{/user}","branches_url":"https://api.github.com/repos/pocmo/android-components/branches{/branch}","tags_url":"https://api.github.com/repos/pocmo/android-components/tags","blobs_url":"https://api.github.com/repos/pocmo/android-components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/pocmo/android-components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/pocmo/android-components/git/refs{/sha}","trees_url":"https://api.github.com/repos/pocmo/android-components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/pocmo/android-components/statuses/{sha}","languages_url":"https://api.github.com/repos/pocmo/android-components/languages","stargazers_url":"https://api.github.com/repos/pocmo/android-components/stargazers","contributors_url":"https://api.github.com/repos/pocmo/android-components/contributors","subscribers_url":"https://api.github.com/repos/pocmo/android-components/subscribers","subscription_url":"https://api.github.com/repos/pocmo/android-components/subscription","commits_url":"https://api.github.com/repos/pocmo/android-components/commits{/sha}","git_commits_url":"https://api.github.com/repos/pocmo/android-components/git/commits{/sha}","comments_url":"https://api.github.com/repos/pocmo/android-components/comments{/number}","issue_comment_url":"https://api.github.com/repos/pocmo/android-components/issues/comments{/number}","contents_url":"https://api.github.com/repos/pocmo/android-components/contents/{+path}","compare_url":"https://api.github.com/repos/pocmo/android-components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/pocmo/android-components/merges","archive_url":"https://api.github.com/repos/pocmo/android-components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/pocmo/android-components/downloads","issues_url":"https://api.github.com/repos/pocmo/android-components/issues{/number}","pulls_url":"https://api.github.com/repos/pocmo/android-components/pulls{/number}","milestones_url":"https://api.github.com/repos/pocmo/android-components/milestones{/number}","notifications_url":"https://api.github.com/repos/pocmo/android-components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/pocmo/android-components/labels{/name}","releases_url":"https://api.github.com/repos/pocmo/android-components/releases{/id}","deployments_url":"https://api.github.com/repos/pocmo/android-components/deployments","created_at":"2018-03-21T16:59:46Z","updated_at":"2018-04-13T09:59:55Z","pushed_at":"2018-07-19T13:55:00Z","git_url":"git://github.com/pocmo/android-components.git","ssh_url":"git@github.com:pocmo/android-components.git","clone_url":"https://github.com/pocmo/android-components.git","svn_url":"https://github.com/pocmo/android-components","homepage":null,"size":1932,"stargazers_count":1,"watchers_count":1,"language":"Kotlin","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":0,"mirror_url":null,"archived":false,"open_issues_count":0,"license":{"key":"mpl-2.0","name":"Mozilla Public License 2.0","spdx_id":"MPL-2.0","url":"https://api.github.com/licenses/mpl-2.0","node_id":"MDc6TGljZW5zZTE0"},"forks":0,"open_issues":0,"watchers":1,"default_branch":"master"}},"base":{"label":"mozilla-mobile:master","ref":"master","sha":"50add3e176e038c6630ab3612268feb156d33984","user":{"login":"mozilla-mobile","id":22351667,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMzUxNjY3","avatar_url":"https://avatars3.githubusercontent.com/u/22351667?v=4","gravatar_id":"","url":"https://api.github.com/users/mozilla-mobile","html_url":"https://github.com/mozilla-mobile","followers_url":"https://api.github.com/users/mozilla-mobile/followers","following_url":"https://api.github.com/users/mozilla-mobile/following{/other_user}","gists_url":"https://api.github.com/users/mozilla-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla-mobile/subscriptions","organizations_url":"https://api.github.com/users/mozilla-mobile/orgs","repos_url":"https://api.github.com/users/mozilla-mobile/repos","events_url":"https://api.github.com/users/mozilla-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla-mobile/received_events","type":"Organization","site_admin":false},"repo":{"id":126199585,"node_id":"MDEwOlJlcG9zaXRvcnkxMjYxOTk1ODU=","name":"android-components","full_name":"mozilla-mobile/android-components","owner":{"login":"mozilla-mobile","id":22351667,"node_id":"MDEyOk9yZ2FuaXphdGlvbjIyMzUxNjY3","avatar_url":"https://avatars3.githubusercontent.com/u/22351667?v=4","gravatar_id":"","url":"https://api.github.com/users/mozilla-mobile","html_url":"https://github.com/mozilla-mobile","followers_url":"https://api.github.com/users/mozilla-mobile/followers","following_url":"https://api.github.com/users/mozilla-mobile/following{/other_user}","gists_url":"https://api.github.com/users/mozilla-mobile/gists{/gist_id}","starred_url":"https://api.github.com/users/mozilla-mobile/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mozilla-mobile/subscriptions","organizations_url":"https://api.github.com/users/mozilla-mobile/orgs","repos_url":"https://api.github.com/users/mozilla-mobile/repos","events_url":"https://api.github.com/users/mozilla-mobile/events{/privacy}","received_events_url":"https://api.github.com/users/mozilla-mobile/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/mozilla-mobile/android-components","description":"A collection of Android libraries to build browsers or browser-like applications.","fork":false,"url":"https://api.github.com/repos/mozilla-mobile/android-components","forks_url":"https://api.github.com/repos/mozilla-mobile/android-components/forks","keys_url":"https://api.github.com/repos/mozilla-mobile/android-components/keys{/key_id}","collaborators_url":"https://api.github.com/repos/mozilla-mobile/android-components/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/mozilla-mobile/android-components/teams","hooks_url":"https://api.github.com/repos/mozilla-mobile/android-components/hooks","issue_events_url":"https://api.github.com/repos/mozilla-mobile/android-components/issues/events{/number}","events_url":"https://api.github.com/repos/mozilla-mobile/android-components/events","assignees_url":"https://api.github.com/repos/mozilla-mobile/android-components/assignees{/user}","branches_url":"https://api.github.com/repos/mozilla-mobile/android-components/branches{/branch}","tags_url":"https://api.github.com/repos/mozilla-mobile/android-components/tags","blobs_url":"https://api.github.com/repos/mozilla-mobile/android-components/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/mozilla-mobile/android-components/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/mozilla-mobile/android-components/git/refs{/sha}","trees_url":"https://api.github.com/repos/mozilla-mobile/android-components/git/trees{/sha}","statuses_url":"https://api.github.com/repos/mozilla-mobile/android-components/statuses/{sha}","languages_url":"https://api.github.com/repos/mozilla-mobile/android-components/languages","stargazers_url":"https://api.github.com/repos/mozilla-mobile/android-components/stargazers","contributors_url":"https://api.github.com/repos/mozilla-mobile/android-components/contributors","subscribers_url":"https://api.github.com/repos/mozilla-mobile/android-components/subscribers","subscription_url":"https://api.github.com/repos/mozilla-mobile/android-components/subscription","commits_url":"https://api.github.com/repos/mozilla-mobile/android-components/commits{/sha}","git_commits_url":"https://api.github.com/repos/mozilla-mobile/android-components/git/commits{/sha}","comments_url":"https://api.github.com/repos/mozilla-mobile/android-components/comments{/number}","issue_comment_url":"https://api.github.com/repos/mozilla-mobile/android-components/issues/comments{/number}","contents_url":"https://api.github.com/repos/mozilla-mobile/android-components/contents/{+path}","compare_url":"https://api.github.com/repos/mozilla-mobile/android-components/compare/{base}...{head}","merges_url":"https://api.github.com/repos/mozilla-mobile/android-components/merges","archive_url":"https://api.github.com/repos/mozilla-mobile/android-components/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/mozilla-mobile/android-components/downloads","issues_url":"https://api.github.com/repos/mozilla-mobile/android-components/issues{/number}","pulls_url":"https://api.github.com/repos/mozilla-mobile/android-components/pulls{/number}","milestones_url":"https://api.github.com/repos/mozilla-mobile/android-components/milestones{/number}","notifications_url":"https://api.github.com/repos/mozilla-mobile/android-components/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/mozilla-mobile/android-components/labels{/name}","releases_url":"https://api.github.com/repos/mozilla-mobile/android-components/releases{/id}","deployments_url":"https://api.github.com/repos/mozilla-mobile/android-components/deployments","created_at":"2018-03-21T15:24:03Z","updated_at":"2018-07-20T11:56:33Z","pushed_at":"2018-07-20T12:34:47Z","git_url":"git://github.com/mozilla-mobile/android-components.git","ssh_url":"git@github.com:mozilla-mobile/android-components.git","clone_url":"https://github.com/mozilla-mobile/android-components.git","svn_url":"https://github.com/mozilla-mobile/android-components","homepage":"","size":1932,"stargazers_count":98,"watchers_count":98,"language":"Kotlin","has_issues":true,"has_projects":false,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":37,"mirror_url":null,"archived":false,"open_issues_count":101,"license":{"key":"mpl-2.0","name":"Mozilla Public License 2.0","spdx_id":"MPL-2.0","url":"https://api.github.com/licenses/mpl-2.0","node_id":"MDc6TGljZW5zZTE0"},"forks":37,"open_issues":101,"watchers":98,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453"},"html":{"href":"https://github.com/mozilla-mobile/android-components/pull/453"},"issue":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/issues/453"},"comments":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/issues/453/comments"},"review_comments":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453/comments"},"review_comment":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/pulls/453/commits"},"statuses":{"href":"https://api.github.com/repos/mozilla-mobile/android-components/statuses/9bdd9ac42fc651c706eecd7ec464948c177dceb4"}},"author_association":"COLLABORATOR"}}
{"actor":{"display_login":"pocmo"}}