{"action":"created","issue":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/13222","labels_url":"https://api.github.com/repos/JuliaLang/julia/issues/13222/labels{/name}","comments_url":"https://api.github.com/repos/JuliaLang/julia/issues/13222/comments","events_url":"https://api.github.com/repos/JuliaLang/julia/issues/13222/events","html_url":"https://github.com/JuliaLang/julia/pull/13222","id":107329773,"number":13222,"title":"WIP/RFC: Sweet Holy Traits","user":{"login":"mauro3","id":4098145,"avatar_url":"https://avatars.githubusercontent.com/u/4098145?v=3","gravatar_id":"","url":"https://api.github.com/users/mauro3","html_url":"https://github.com/mauro3","followers_url":"https://api.github.com/users/mauro3/followers","following_url":"https://api.github.com/users/mauro3/following{/other_user}","gists_url":"https://api.github.com/users/mauro3/gists{/gist_id}","starred_url":"https://api.github.com/users/mauro3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mauro3/subscriptions","organizations_url":"https://api.github.com/users/mauro3/orgs","repos_url":"https://api.github.com/users/mauro3/repos","events_url":"https://api.github.com/users/mauro3/events{/privacy}","received_events_url":"https://api.github.com/users/mauro3/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":24,"created_at":"2015-09-19T12:19:17Z","updated_at":"2015-09-24T07:28:26Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/JuliaLang/julia/pulls/13222","html_url":"https://github.com/JuliaLang/julia/pull/13222","diff_url":"https://github.com/JuliaLang/julia/pull/13222.diff","patch_url":"https://github.com/JuliaLang/julia/pull/13222.patch"},"body":"This PR implements macro-sugar for Holy Traits (HT).  This is [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl) ported to Base (so to check it out, cloning SimpleTraits will be faster than building this PR).\r\n\r\nThe idea behind this PR is to make HT easier to use.  An added benefit is that this marks them, so they could be easily updated once a more proper trait system is in place.  (I suspect that the semantics of a trait-system-to-be will be a superset of HT, so the migration should be reasonably easy.)  At the moment only the linear-indexing HT is in Base, but judging by the chat on julia-issues this may change (e.g. #13157, #10385, ...), thus a more structured approach may make sense.\r\n\r\nThe readme of [SimpleTraits.jl](https://github.com/mauro3/SimpleTraits.jl) gives an overview of the functionality.  The short is:\r\n\r\n```julia\r\n@traitdef LinearFastTr{X}\r\n@traitimpl LinearFastTr{Array}\r\n@traitimpl LinearFastTr{Range}\r\n@traitfn f1{X<:AbstractArray;  LinearFastTr{X}}(a::X) = 1\r\n@traitfn f1{X<:AbstractArray; !LinearFastTr{X}}(a::X) = 2\r\nf1(1:3)      # -> 1\r\nf1([1,2])    # -> 1\r\nf1(speye(2)) # -> 2\r\n```\r\n\r\nwhich is quite a bit shorter and more readable than the manual implementation (as done for `LinearIndexing` in Base):\r\n\r\n```julia\r\n# the trait\r\nabstract LinearIndexing\r\nimmutable LinearFast <: LinearIndexing end\r\nimmutable LinearSlow <: LinearIndexing end\r\n\r\n# the trait-implementation\r\nlinearindexing(A::AbstractArray) = linearindexing(typeof(A))\r\nlinearindexing{T<:AbstractArray}(::Type{T}) = LinearSlow()\r\nlinearindexing{T<:Array}(::Type{T}) = LinearFast()\r\nlinearindexing{T<:Range}(::Type{T}) = LinearFast()\r\n\r\n# a traitfunction\r\n@inline f2(A::AbstractArray) = f2(linearindexing(A), A)\r\nf2(::LinearFast, A::AbstractArray) = 1\r\nf2(::LinearSlow, A::AbstractArray) = 2\r\n\r\n# use it\r\nf2(1:3)      # -> 1\r\nf2([1,2])    # -> 1\r\nf2(speye(2)) # -> 2\r\n```\r\n\r\nFor testing and illustrating, I've implemented some HT usages in Base (which should be purged again).  The next step would be to refactor the `LinearIndexing` HT (the only HT currently used in Base, as far as I know).  However, before embarking on that reasonably big task, I have this question: *Does this PR have any chance of being merged?* (Any other comments are of course welcome too!)\r\n\r\nOther things to consider:\r\n\r\n- function/macro names?\r\n- should the HT-interface be exported?\r\n\r\n# TODO\r\n\r\n- [ ] refactor `LinearIndexing` trait\r\n- [ ] add documentation\r\n- [ ] move to earlier in the bootstrap?\r\n- [ ] add doc-capability to traitfn after #13006\r\n\r\nRemove:\r\n\r\n- [ ] example HTs\r\n- [ ] bootstrap tests\r\n"},"comment":{"url":"https://api.github.com/repos/JuliaLang/julia/issues/comments/142838497","html_url":"https://github.com/JuliaLang/julia/pull/13222#issuecomment-142838497","issue_url":"https://api.github.com/repos/JuliaLang/julia/issues/13222","id":142838497,"user":{"login":"mauro3","id":4098145,"avatar_url":"https://avatars.githubusercontent.com/u/4098145?v=3","gravatar_id":"","url":"https://api.github.com/users/mauro3","html_url":"https://github.com/mauro3","followers_url":"https://api.github.com/users/mauro3/followers","following_url":"https://api.github.com/users/mauro3/following{/other_user}","gists_url":"https://api.github.com/users/mauro3/gists{/gist_id}","starred_url":"https://api.github.com/users/mauro3/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mauro3/subscriptions","organizations_url":"https://api.github.com/users/mauro3/orgs","repos_url":"https://api.github.com/users/mauro3/repos","events_url":"https://api.github.com/users/mauro3/events{/privacy}","received_events_url":"https://api.github.com/users/mauro3/received_events","type":"User","site_admin":false},"created_at":"2015-09-24T07:28:26Z","updated_at":"2015-09-24T07:28:26Z","body":"This PR cannot do intersections, however, Traits.jl can in two related ways.  A trait can inherit from several others:\r\n```julia\r\n@traitdef Tr{X} <: Tr1{X}, Tr2{X} begin\r\n    ...\r\nend\r\n```\r\nSo any `X` belongs to `Tr` if it belongs to both `Tr1` and `Tr2` plus any other constraints present in the traitdef-body.  Then, @mbauman's example above would read in Traits.jl:\r\n```julia\r\n@traitfn getindex{X<:AbstractArray; LinearFast{X}}(x::X, ...) =...\r\n@traitfn getindex{X<:AbstractArray; LinearFast{X}, Strided{X}}(x::X, ...) =...\r\n```\r\n(Note that in the second function essentially an ad-hoc trait is created which is the intersection of LinearFast and Strided.  Or framed differently the trait inheriting from those two and not adding any other constraints.)\r\n\r\nBut @mbauman is right, it becomes tricky to figure out dispatch, i.e. the most specific trait intersection a type belongs to.  And in general ambiguities cannot be avoided. Traits.jl can do this dispatch (probably not quite right though) see [issue 5](https://github.com/mauro3/Traits.jl/issues/5) where @tonyhffong and I discussed this and see the [function containing the logic](https://github.com/mauro3/Traits.jl/blob/9af756cfa39150a72e77cbce4d56f5cd3e9bb383/src/traitfns.jl#L226).  Please experiment with it, it would be great to put together more test cases and document them better, the start is [here](https://github.com/mauro3/Traits.jl/blob/9af756cfa39150a72e77cbce4d56f5cd3e9bb383/test/traitdispatch.jl).  I think Traits.jl can do this in all generality thanks to staged functions, so it should be suited to prototype this.  And indeed, a type-theorist's input is sorely needed."}}