{"action":"created","comment":{"url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/comments/92233896","pull_request_review_id":12745503,"id":92233896,"diff_hunk":"@@ -0,0 +1,191 @@\n+# JULEP Nullable\n+\n+- **Title:** Nullable Redesign\n+- **Authors:** John Myles White <<jmw@johnmyleswhite.com>>\n+- **Created:** December 9, 2016\n+- **Status:** work in progress\n+\n+## Abstract\n+\n+The representation of null-like constructs in Julia is too complicated. We\n+currently have all of the following kinds of null-like constructs:\n+\n+* A ` Void` type with a singleton value `nothing`,\n+* A `Nullable` type,\n+* An `#undef` quasi-value that reflects the use of null pointers in Julia's\n+    implementation.\n+\n+This Julep describes a proposal to coalesce all of these concepts into one.\n+\n+The proposal is to replace everything with a new version of the `Nullable`\n+type. This new version of `Nullable` will involve both changing the\n+implementation of our `Nullable` type and clarifying the semantics of this\n+type by laying out a thorough description of how the type would be used in\n+practice.\n+\n+The core goals for this Julep are to:\n+\n+* Simplify the language by replacing many similar constructs with a single\n+    construct.\n+* Ensure that all representations of `null` are first-class citizens of the\n+    language. In particular, we will resolve the problems with `#undef`, which\n+    is a quasi-value that can be present in types, but cannot be inserted into\n+    them.\n+* Resolve the lifting problem for `Nullable` types by formalizing\n+    general-purpose, extensible machinery for lifting.\n+* Make it possible to write optimized code for `Nullable` types that does not\n+    call into type inference via `return_types` or require the use of\n+    `promote_type`.\n+\n+The optional goals for this Julep are to:\n+\n+* Replace the `NullableArray` type with `Array{Nullable}`, while maintaining\n+    the ability to pass the raw values storage unit via FFI in the way that\n+    `NullableArray` currently allows.\n+\n+The prerequisites for this Julep are the following:\n+\n+* Optimizations to the Julia compiler to handle `Union{S, T}` as efficiently as\n+    our current `Nullable` type handles the union of `S` and `Void`. These\n+    compiler changes may include both memory layout changes and optimization\n+    of run-time dispatch among K pre-specified types into simple branches.\n+\n+## Step 1: Redefining the Nullable Type\n+\n+Assuming that compiler optimizations are put in place for union types, the\n+first step for this Julep is to replace the concrete type `Nullable` with an\n+optimized union type. The options for replacing `Nullable{T}` are:\n+\n+* `Union{T, Void}`\n+* `Union{Some{T}, Void}`\n+* `Union{T, Null{T}}`\n+\n+The `Union` type would have the same semantics as unions currently have. Their\n+implementation in the scalar case would likely match that of a possible\n+`TaggedUnion` type, which represents a discriminated union, but is a concrete\n+type that is not a parent of `T`, `Void`, etc.\n+\n+Deciding between these options requires balancing a variety of concerns. As\n+we currently understand them, the arguments are:\n+\n+### `Union{T, Void}` Pros & Cons\n+\n+When a function returns `Union{T, Void}`, the user can immediately apply all\n+methods defined on `T` without any unwrapping. This is very convenient and\n+does not require the introduction of specialized methods.\n+\n+The counter-argument is that such code will only work if the methods being\n+called are defined for both `T` and `Void`. As such, one must redefine\n+`f(x::Void) = nothing` for every new function, even though the semantics are\n+identical. The requirement for always defining such repetitive functions\n+therefore may be perceived as less safe because code that is tested only\n+against values of type `T` may fail in untested cases with a method error if\n+applied to a value of type `Void`. This could be resolved by static analysis\n+tools that check for totality.\n+\n+### `Union{Some{T}, Void}` Pros & Cons\n+\n+This approach is essentially the inverse of the `Union{T, Void}`: here no\n+methods will work on objects of this type unless they are defined for both\n+`f(x::Some{T})` and `f(x::Void)`. As such, this approach requires consistent\n+of specialized lifting machinery via dot-broadcasting syntax. See the later\n+section on lifting for details.\n+\n+Because users will have to work with lifted functions, this approach is\n+less convenient, but more general and often safer. It also allows one to\n+distinguish between outcomes in cases where a method returns something like\n+`Union{Some{Void}, Void}` -- as might happen in a hash table implementation\n+that returns `Some` when a key is present and associated with `nothing` as a\n+value, but returns `Void` when a key is not present.\n+\n+### `Union{T, Null{T}}` Pros & Cons\n+\n+This approach allows us to distinguish `Null{Bool}` from `Null{Int}` in\n+cases in which that distinction might be useful. R makes such a distinction,\n+although it seems to be done only because it is falls out naturally from an\n+implementation that uses sentinel values. Otherwise, it is similar to the\n+`Union{T, Void}` case described above, except for one crucial problem.\n+\n+That problem is essentially the problem we already have with `Nullable{T}`:\n+writing \"clean\" functions requires information about type-inference because of\n+a coupling of result types to knowledge about counterfactual outcomes in\n+branches.\n+\n+To see the issue, consider the following possible implementation of\n+`map(f, x::Nullable{T})` in our current implementation of `Nullable{T}`:\n+\n+```\n+function map(f, x::Nullable{T})\n+    if hasvalue(x)\n+        return Nullable(f(value(x)))\n+    else\n+        return Nullable{return_types(f, T)}()\n+    end\n+end\n+```\n+\n+The problem is that, when given a null input, the return type can only match\n+the counterfactual return type that would have occurred if called on a non-null\n+value if the function knows the return type of `f`.\n+\n+In static languages with arrow types this is not a problem as the return type\n+of a function is guaranteed to be well-defined by the semantics of the\n+language. But Julia does not provide such guarantees, so type-inference must\n+be invoked to determine information about the return type of the counterfactual\n+branch.\n+\n+Note that this problem does not occur for the non-null case because we are\n+expected to evaluate `f`. It is only a problem when we need to know the return\n+type of `f`, but must not determine this type by evaluation of `f`.\n+\n+## Step 2:: Define Core Operations on Nullable Types by Lifting\n+\n+The core semantic issue for nullable types is maximizing code reuse: we want\n+to evaluate `f(x::?T)`, but not require that every function be defined for\n+both `f(x::T)` and `f(x::?T)` separately as the overwhelming majority of\n+functions will return `null` as their output whenever any of their arguments\n+are `null`. Implementing this lifting of functions can be solved as follows:\n+\n+First, we define `broadcast(f, x::Nullable)` as follows:\n+\n+```\n+immutable Lifted{T}\n+    func::T\n+end\n+\n+lift(f) = Lifted(f)\n+\n+broadcast(f, x::Nullable) = broadcast(lift(f), x)\n+\n+broadcast(f′::Lifted, x::Nullable) = hasvalue(x) ? f′.func(value(x)) : null\n+```\n+\n+This allows us to give default semantics to all functions that implement the\n+natural approach to lifting, while still making it possible to handle special\n+case functions that require distinct semantics.\n+\n+Some such functions are:\n+\n+* `hasvalue`\n+* `isnull`\n+* `get`\n+* `get_or_default`\n+\n+There are natural extensions of this logic to the n-ary function case.\n+\n+Because we would use broadcasting, lifting would happen via dot-syntax:\n+`x .+ y` would be lifted by default. In addition, we would special several\n+operators like `+`, `-`, `==`, etc. to automatically be equivalent to\n+broadcasting on nullables.\n+\n+## Step 3: Introduce Syntactic Sugar for Nullable Types\n+\n+Following the lead of\n+[Flow for Javascript](https://flowtype.org/docs/nullable-types.html), we\n+would introduce `?T` as sugar for `Nullable{T}`. We have also considered C#'s\n+`T?`. Which is chosen will likely depend upon how they interact with the\n+ternary operator.\n+\n+We might also introduce a null-coalescing operator of `??` with\n+right-associativity that essentially performs lifting: in this case,\n+`x ?? y ?? 0` would be equivalent to `hasvalue(x) ? x : (hasvalue(y) ? y : 0)`.","path":"Nullable.md","position":191,"original_position":191,"commit_id":"04311d28aac500e6163ccb68eac266333348a234","original_commit_id":"04311d28aac500e6163ccb68eac266333348a234","user":{"login":"ararslan","id":6396159,"avatar_url":"https://avatars.githubusercontent.com/u/6396159?v=3","gravatar_id":"","url":"https://api.github.com/users/ararslan","html_url":"https://github.com/ararslan","followers_url":"https://api.github.com/users/ararslan/followers","following_url":"https://api.github.com/users/ararslan/following{/other_user}","gists_url":"https://api.github.com/users/ararslan/gists{/gist_id}","starred_url":"https://api.github.com/users/ararslan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ararslan/subscriptions","organizations_url":"https://api.github.com/users/ararslan/orgs","repos_url":"https://api.github.com/users/ararslan/repos","events_url":"https://api.github.com/users/ararslan/events{/privacy}","received_events_url":"https://api.github.com/users/ararslan/received_events","type":"User","site_admin":false},"body":"Or `isnull` and switch the order","created_at":"2016-12-13T18:28:33Z","updated_at":"2016-12-13T18:28:33Z","html_url":"https://github.com/JuliaLang/Juleps/pull/21#discussion_r92233896","pull_request_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21","_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/comments/92233896"},"html":{"href":"https://github.com/JuliaLang/Juleps/pull/21#discussion_r92233896"},"pull_request":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21"}}},"pull_request":{"url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21","id":97402489,"html_url":"https://github.com/JuliaLang/Juleps/pull/21","diff_url":"https://github.com/JuliaLang/Juleps/pull/21.diff","patch_url":"https://github.com/JuliaLang/Juleps/pull/21.patch","issue_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/21","number":21,"state":"open","locked":false,"title":"[WIP] Nullable Redesign","user":{"login":"johnmyleswhite","id":22064,"avatar_url":"https://avatars.githubusercontent.com/u/22064?v=3","gravatar_id":"","url":"https://api.github.com/users/johnmyleswhite","html_url":"https://github.com/johnmyleswhite","followers_url":"https://api.github.com/users/johnmyleswhite/followers","following_url":"https://api.github.com/users/johnmyleswhite/following{/other_user}","gists_url":"https://api.github.com/users/johnmyleswhite/gists{/gist_id}","starred_url":"https://api.github.com/users/johnmyleswhite/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/johnmyleswhite/subscriptions","organizations_url":"https://api.github.com/users/johnmyleswhite/orgs","repos_url":"https://api.github.com/users/johnmyleswhite/repos","events_url":"https://api.github.com/users/johnmyleswhite/events{/privacy}","received_events_url":"https://api.github.com/users/johnmyleswhite/received_events","type":"User","site_admin":false},"body":"This draft describes the core ideas behind a redesign of nullables. It will require substantial elaboration before we have a final design, but my goal is to get this out in front of people while we are still debating the remaining points of uncertainty in the design. The primary source of remaining uncertainty are the arguments in favor of `Union{T, Void}` vs `Union{Some{T}, Void}`.","created_at":"2016-12-10T00:14:24Z","updated_at":"2016-12-13T18:28:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"a1050244700d6ab9b73db0ae3b35f703df79b685","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21/commits","review_comments_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21/comments","review_comment_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls/comments{/number}","comments_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/21/comments","statuses_url":"https://api.github.com/repos/JuliaLang/Juleps/statuses/04311d28aac500e6163ccb68eac266333348a234","head":{"label":"JuliaLang:jmw/nullable","ref":"jmw/nullable","sha":"04311d28aac500e6163ccb68eac266333348a234","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":71597220,"name":"Juleps","full_name":"JuliaLang/Juleps","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/Juleps","description":"Julia Enhancement Proposals","fork":false,"url":"https://api.github.com/repos/JuliaLang/Juleps","forks_url":"https://api.github.com/repos/JuliaLang/Juleps/forks","keys_url":"https://api.github.com/repos/JuliaLang/Juleps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/Juleps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/Juleps/teams","hooks_url":"https://api.github.com/repos/JuliaLang/Juleps/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/Juleps/events","assignees_url":"https://api.github.com/repos/JuliaLang/Juleps/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/Juleps/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/Juleps/tags","blobs_url":"https://api.github.com/repos/JuliaLang/Juleps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/Juleps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/Juleps/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/Juleps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/Juleps/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/Juleps/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/Juleps/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/Juleps/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/Juleps/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/Juleps/subscription","commits_url":"https://api.github.com/repos/JuliaLang/Juleps/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/Juleps/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/Juleps/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/Juleps/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/Juleps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/Juleps/merges","archive_url":"https://api.github.com/repos/JuliaLang/Juleps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/Juleps/downloads","issues_url":"https://api.github.com/repos/JuliaLang/Juleps/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/Juleps/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/Juleps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/Juleps/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/Juleps/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/Juleps/deployments","created_at":"2016-10-21T21:11:21Z","updated_at":"2016-11-12T15:35:37Z","pushed_at":"2016-12-13T18:25:51Z","git_url":"git://github.com/JuliaLang/Juleps.git","ssh_url":"git@github.com:JuliaLang/Juleps.git","clone_url":"https://github.com/JuliaLang/Juleps.git","svn_url":"https://github.com/JuliaLang/Juleps","homepage":null,"size":35,"stargazers_count":4,"watchers_count":4,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":14,"forks":5,"open_issues":14,"watchers":4,"default_branch":"master"}},"base":{"label":"JuliaLang:master","ref":"master","sha":"fae0718b0046f5ed36ece7a96713ab65c9e1fdda","user":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"repo":{"id":71597220,"name":"Juleps","full_name":"JuliaLang/Juleps","owner":{"login":"JuliaLang","id":743164,"avatar_url":"https://avatars.githubusercontent.com/u/743164?v=3","gravatar_id":"","url":"https://api.github.com/users/JuliaLang","html_url":"https://github.com/JuliaLang","followers_url":"https://api.github.com/users/JuliaLang/followers","following_url":"https://api.github.com/users/JuliaLang/following{/other_user}","gists_url":"https://api.github.com/users/JuliaLang/gists{/gist_id}","starred_url":"https://api.github.com/users/JuliaLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JuliaLang/subscriptions","organizations_url":"https://api.github.com/users/JuliaLang/orgs","repos_url":"https://api.github.com/users/JuliaLang/repos","events_url":"https://api.github.com/users/JuliaLang/events{/privacy}","received_events_url":"https://api.github.com/users/JuliaLang/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/JuliaLang/Juleps","description":"Julia Enhancement Proposals","fork":false,"url":"https://api.github.com/repos/JuliaLang/Juleps","forks_url":"https://api.github.com/repos/JuliaLang/Juleps/forks","keys_url":"https://api.github.com/repos/JuliaLang/Juleps/keys{/key_id}","collaborators_url":"https://api.github.com/repos/JuliaLang/Juleps/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/JuliaLang/Juleps/teams","hooks_url":"https://api.github.com/repos/JuliaLang/Juleps/hooks","issue_events_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/events{/number}","events_url":"https://api.github.com/repos/JuliaLang/Juleps/events","assignees_url":"https://api.github.com/repos/JuliaLang/Juleps/assignees{/user}","branches_url":"https://api.github.com/repos/JuliaLang/Juleps/branches{/branch}","tags_url":"https://api.github.com/repos/JuliaLang/Juleps/tags","blobs_url":"https://api.github.com/repos/JuliaLang/Juleps/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/JuliaLang/Juleps/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/JuliaLang/Juleps/git/refs{/sha}","trees_url":"https://api.github.com/repos/JuliaLang/Juleps/git/trees{/sha}","statuses_url":"https://api.github.com/repos/JuliaLang/Juleps/statuses/{sha}","languages_url":"https://api.github.com/repos/JuliaLang/Juleps/languages","stargazers_url":"https://api.github.com/repos/JuliaLang/Juleps/stargazers","contributors_url":"https://api.github.com/repos/JuliaLang/Juleps/contributors","subscribers_url":"https://api.github.com/repos/JuliaLang/Juleps/subscribers","subscription_url":"https://api.github.com/repos/JuliaLang/Juleps/subscription","commits_url":"https://api.github.com/repos/JuliaLang/Juleps/commits{/sha}","git_commits_url":"https://api.github.com/repos/JuliaLang/Juleps/git/commits{/sha}","comments_url":"https://api.github.com/repos/JuliaLang/Juleps/comments{/number}","issue_comment_url":"https://api.github.com/repos/JuliaLang/Juleps/issues/comments{/number}","contents_url":"https://api.github.com/repos/JuliaLang/Juleps/contents/{+path}","compare_url":"https://api.github.com/repos/JuliaLang/Juleps/compare/{base}...{head}","merges_url":"https://api.github.com/repos/JuliaLang/Juleps/merges","archive_url":"https://api.github.com/repos/JuliaLang/Juleps/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/JuliaLang/Juleps/downloads","issues_url":"https://api.github.com/repos/JuliaLang/Juleps/issues{/number}","pulls_url":"https://api.github.com/repos/JuliaLang/Juleps/pulls{/number}","milestones_url":"https://api.github.com/repos/JuliaLang/Juleps/milestones{/number}","notifications_url":"https://api.github.com/repos/JuliaLang/Juleps/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/JuliaLang/Juleps/labels{/name}","releases_url":"https://api.github.com/repos/JuliaLang/Juleps/releases{/id}","deployments_url":"https://api.github.com/repos/JuliaLang/Juleps/deployments","created_at":"2016-10-21T21:11:21Z","updated_at":"2016-11-12T15:35:37Z","pushed_at":"2016-12-13T18:25:51Z","git_url":"git://github.com/JuliaLang/Juleps.git","ssh_url":"git@github.com:JuliaLang/Juleps.git","clone_url":"https://github.com/JuliaLang/Juleps.git","svn_url":"https://github.com/JuliaLang/Juleps","homepage":null,"size":35,"stargazers_count":4,"watchers_count":4,"language":null,"has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":5,"mirror_url":null,"open_issues_count":14,"forks":5,"open_issues":14,"watchers":4,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21"},"html":{"href":"https://github.com/JuliaLang/Juleps/pull/21"},"issue":{"href":"https://api.github.com/repos/JuliaLang/Juleps/issues/21"},"comments":{"href":"https://api.github.com/repos/JuliaLang/Juleps/issues/21/comments"},"review_comments":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21/comments"},"review_comment":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/JuliaLang/Juleps/pulls/21/commits"},"statuses":{"href":"https://api.github.com/repos/JuliaLang/Juleps/statuses/04311d28aac500e6163ccb68eac266333348a234"}}}}
{"actor":{"display_login":"ararslan"}}