-
-
Notifications
You must be signed in to change notification settings - Fork 5.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Better introduction to parametric types in the manual #43811
Comments
@adigitoleo I would like to work on this issue, can you please guide me to get started to contribute to Julia. Thanks! |
@Preetham-Reddy-007 My idea when writing the issue was to improve the types page in the manual, focusing on the parametric types section. I don't yet completely understand the answers to all of the points I raised in the first post 😄, so the first step would be to research Julia's parametric type implementation and come up with a concise overview. Have a play around with the type system and see if you can understand it. Check for things that are surprising compared to what the manual says. not an example
makes it sound like only julia> abstract type Bar{T} end
julia> struct Barbarian{T} <: Bar{T}
a::T
b::T
end
julia> barbarian = Barbarian("axe", "axe")
Barbarian{String}("axe", "axe")
julia> barbarian isa Bar
true
julia> struct Bard{T} <: Bar{T}
a::T
b::T
end
julia> jaskier = Bard('ó', 'ñ')
Bard{Char}('ó', 'ñ')
julia> jaskier isa Bar
true
julia> Bar <: DataType
false
julia> struct Barf{T} <: Bar
a::T
b::T
end
ERROR: invalid subtyping in definition of Barf
Stacktrace:
[1] top-level scope
@ REPL[10]:1
EDIT: This was just me not getting it, |
I just came across another package which once again defined an abstract container like (very simplified): julia> struct Foo{T<:Real,N} <: AbstractArray{T,N}
a::Array{T,N}
b::String
end which leads to problems like: julia> Foo(transpose([1, 2, 3, 4]), "wtf")
ERROR: MethodError: no method matching Foo(::LinearAlgebra.Transpose{Int64, Vector{Int64}}, ::String)
Closest candidates are:
Foo(::Array{T, N}, ::String) where {T<:Real, N} at REPL[1]:2
Stacktrace:
[1] top-level scope
@ REPL[2]:1
The solution is: julia> struct Foo{T<:AbstractArray}
a::T
b::String
end
julia> Foo(transpose([1, 2, 3, 4]), "yay")
Foo{LinearAlgebra.Transpose{Int64, Vector{Int64}}}([1 2 3 4], "yay")
However, it looks a bit like julia> foo = Foo(transpose([1, 2, 3, 4]), "yay")
Foo{LinearAlgebra.Transpose{Int64, Vector{Int64}}}([1 2 3 4], "yay")
julia> typeof(foo)
Foo{LinearAlgebra.Transpose{Int64, Vector{Int64}}}
julia> isconcretetype(typeof(foo.a))
true
I think this is one of the main things that deserves stronger demonstration. When people start using the first option, it leads down the rabbit hole of over-constraining of argument types to avoid a MethodError from the constructor. |
I've found that some of the relevant information is in the constructors section, there's even a case study example. However, the focus is more on advanced constructor logic. |
At the risk of overloading this thread, I'll also mention that the last example from the constructors section suffers from the same problem: julia> struct SummedArray{T<:Number,S<:Number}
data::Vector{T}
sum::S
end
julia> SummedArray([1; 2; 3], 6)
SummedArray{Int64, Int64}([1, 2, 3], 6)
julia> SummedArray(transpose([1; 2; 3]), 6)
ERROR: MethodError: no method matching SummedArray(::LinearAlgebra.Transpose{Int64, Vector{Int64}}, ::Int64)
Closest candidates are:
SummedArray(::Vector{T}, ::S) where {T<:Number, S<:Number} at REPL[5]:2
Stacktrace:
[1] top-level scope
@ REPL[7]:1 I'm using |
You seem to have a pretty clear idea for how you want that section to look like, would you you like to just propose a PR yourself? I do think this could definitely be useful. |
@simeonschaub Sure, I'll have a go. Might take another day or two for me to grok all the details and come up with something concise. Wouldn't want to upload something that's misleading. |
@adigitoleo thanks for the precise details. I am a beginner and just started with Julia, might take some time. |
@Preetham-Reddy-007 these issues might be simpler to start with, they are also about improving documentation: #30469, #28712 |
First step towards JuliaLang#43811. The intro section felt a bit long-winded, I've made some changes there first.
Closes JuliaLang#43811. Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. Shifted some paragraphs around to reflect their importance, and changed the wording in some places.
Closes JuliaLang#43811. - The intro section felt a bit long-winded, I've made some changes there first. - Clarify that `typeof` returns the concrete type - Rename Type Declarations section to Type Annotations, avoid confusion with Declaring Types section and distinguish use of "type declaration" to mean "declaring new types" - Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. - Shifted some paragraphs around to reflect their importance, and changed the wording in some places. - Rename type declaration -> annotation in other places (docstrings/comments)
Closes JuliaLang#43811. - The intro section felt a bit long-winded, I've made some changes there first. - Clarify that `typeof` returns the concrete type - Rename Type Declarations section to Type Annotations, avoid confusion with Declaring Types section and distinguish use of "type declaration" to mean "declaring new types" - Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. - Shifted some paragraphs around to reflect their importance, and changed the wording in some places. - Rename type declaration -> annotation in other places (docstrings/comments)
I want to work on this. If the issue is open, please assign it to me. |
@MashiatK Same as with the other issues, just open a PR and we can go from there, assignment isn't really necessary ;) |
Closes JuliaLang#43811. - The intro section felt a bit long-winded, I've made some changes there first. - Clarify that `typeof` returns the concrete type - Rename Type Declarations section to Type Annotations, avoid confusion with Declaring Types section and distinguish use of "type declaration" to mean "declaring new types" - Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. - Shifted some paragraphs around to reflect their importance, and changed the wording in some places. - Rename type declaration -> annotation in other places (docstrings/comments)
I just rebased onto master if there is still interest. The linked PR (#43891) was my attemt to clarify some of the documentation on parametric types, but feel free to open a new PR if you have other ideas. |
Closes JuliaLang#43811. - The intro section felt a bit long-winded, I've made some changes there first. - Clarify that `typeof` returns the concrete type - Rename Type Declarations section to Type Annotations, avoid confusion with Declaring Types section and distinguish use of "type declaration" to mean "declaring new types" - Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. - Shifted some paragraphs around to reflect their importance, and changed the wording in some places. - Rename type declaration -> annotation in other places (docstrings/comments)
Closes JuliaLang#43811. - The intro section felt a bit long-winded, I've made some changes there first. - Clarify that `typeof` returns the concrete type - Rename Type Declarations section to Type Annotations, avoid confusion with Declaring Types section and distinguish use of "type declaration" to mean "declaring new types" - Removed some of the jargon and wikipedia links to make room for a brief alternative `Point{T1,T2}` demonstration. - Shifted some paragraphs around to reflect their importance, and changed the wording in some places. - Rename type declaration -> annotation in other places (docstrings/comments)
After a discussion in IRC today I realised that there were a few things about parametric types that aren't easily understood. It seems that the manual could help a bit more in introducing parametric types. I'm opening this issue to outline some of the things I think could be documented better, and also to gather ideas or examples that might help to write a more hands-on parametric types section in the manual. Not sure if this belongs on the forum but I am thinking of linking a PR at some point.
For the parametric type
Foo
and an instancefoo
, I think the docs could clarifyisabstracttype(Foo)
andisconcretetype(Foo)
return false for the parametric typeFoo
, i.e. that parametric types are neither abstract nor concreteFoo
typeof(foo) <: Foo
is true, howeversupertype(typeof(foo)) == Foo
is false (it'sAny
)Foo isa DataType
is falseand (more visibly) inform
that parametric types cannot be subtypedthey can, parametric abstract types are a thingtypeof(foo) != Foo
wherefoo
is an instance ofFoo
foo isa Foo
must be used to test iffoo
is an instance ofFoo
I also think there should be one example on how to set up a simple but complete type hierarchy (without going into all of the gritty details of the Advanced Types section). Something like the comment by wasshin in #4935.
There might be some other things I've forgotten, feel free to suggest related improvements. I feel that parametric types are one of the major features of Julia's type system, however they can be confusing when coming from languages with more traditional/simple OOP systems. Understanding parametric types should help to reduce common antipatterns like over-constraining argument types, and help people to leverage the dispatch system (what are all those
<:
needed for anyway?)The text was updated successfully, but these errors were encountered: