From ed9c17def0dd254d031b253bccd0a5e64168520a Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Tue, 22 Oct 2019 15:25:10 +0200 Subject: [PATCH 1/5] =?UTF-8?q?Add=20a=20FAQ=20entry=20for=20=E2=80=9Ccomp?= =?UTF-8?q?uted/constrained=20type=20parameters=E2=80=9D.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base/docs/basedocs.jl | 3 ++- doc/src/manual/constructors.md | 4 ++-- doc/src/manual/faq.md | 27 +++++++++++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) diff --git a/base/docs/basedocs.jl b/base/docs/basedocs.jl index 62de1099212ce..125cf50f98539 100644 --- a/base/docs/basedocs.jl +++ b/base/docs/basedocs.jl @@ -945,7 +945,8 @@ kw"mutable struct" Special function available to inner constructors which created a new object of the type. -See the manual section on [Inner Constructor Methods](@ref) for more information. +See the manual section on [Inner Constructor Methods](@ref man-inner-constructor-methods) +for more information. """ kw"new" diff --git a/doc/src/manual/constructors.md b/doc/src/manual/constructors.md index 33f6d8fc44e1b..2a2c8dd4507bd 100644 --- a/doc/src/manual/constructors.md +++ b/doc/src/manual/constructors.md @@ -38,7 +38,7 @@ addresses all of these cases and more. is used to mean "constructor method" rather than "constructor function", especially as it is often used in the sense of singling out a particular method of the constructor from all of the others. -## Outer Constructor Methods +## [Outer Constructor Methods](@id man-outer-constructor-methods) A constructor is just like any other function in Julia in that its overall behavior is defined by the combined behavior of its methods. Accordingly, you can add functionality to a constructor @@ -71,7 +71,7 @@ become clear very shortly, additional constructor methods declared as normal met are called *outer* constructor methods. Outer constructor methods can only ever create a new instance by calling another constructor method, such as the automatically provided default ones. -## Inner Constructor Methods +## [Inner Constructor Methods](@id man-inner-constructor-methods) While outer constructor methods succeed in addressing the problem of providing additional convenience methods for constructing objects, they fail to address the other two use cases mentioned in the diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 1b86e18986595..c7f038f00bd2f 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -352,6 +352,33 @@ julia> sqrt(-2.0+0im) 0.0 + 1.4142135623730951im ``` +### How can I constrain or compute type parameters? + +Julia does not support a special syntax for expressing constraints for type parameters, but these can be enforced in [constructors](@ref man-constructors). + +As an example, consider +```julia +struct ConstrainedType{T,N,N+1} # NOTE: INVALID SYNTAX + A::Array{T,N} + B::Array{T,N+1} +end +``` +where the user would like to enforce that the third type parameter is always the second plus one. This can be implemented with an explicit type parameter that is checked by an [inner constructor method](@ref man-inner-constructor-methods) (where it can be combined with other checks): +```jldoctest +struct ConstrainedType{T,N,M} + A::Array{T,N} + B::Array{T,M} + function ConstrainedType(A::Array{T,N}, B::Array{T,M}) where {T,N,M} + N == M || throw(ArgumentError("second argument should have one more axis" )) + new{T,N,M}(A, B) + end +end +``` +This check is usually *costless*, as the compiler can elide the check for valid concrete types. If the second argument is also computed, it may be advantageous to provide an [outer constructor method](@ref man-outer-constructor-methods) that performs this calculation: +```jldoctest +ConstrainedType(A) = ConstrainedType(A, compute_B(A)) +``` + ### [Why does Julia use native machine integer arithmetic?](@id faq-integer-arithmetic) Julia uses machine arithmetic for integer computations. This means that the range of `Int` values From 0b396fb3a41017167d8a2b2fc90445a77c21b2b5 Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Tue, 22 Oct 2019 15:38:51 +0200 Subject: [PATCH 2/5] correction (thanks @rdeits) --- doc/src/manual/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index c7f038f00bd2f..de2007fb35d6f 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -369,7 +369,7 @@ struct ConstrainedType{T,N,M} A::Array{T,N} B::Array{T,M} function ConstrainedType(A::Array{T,N}, B::Array{T,M}) where {T,N,M} - N == M || throw(ArgumentError("second argument should have one more axis" )) + N + 1 == M || throw(ArgumentError("second argument should have one more axis" )) new{T,N,M}(A, B) end end From ece0df46732fc5373ea5c360aa2556cc8a042de6 Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Tue, 22 Oct 2019 18:44:39 +0200 Subject: [PATCH 3/5] Update doc/src/manual/faq.md Co-Authored-By: Matt Bauman --- doc/src/manual/faq.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index de2007fb35d6f..b55580c1c253c 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -354,7 +354,19 @@ julia> sqrt(-2.0+0im) ### How can I constrain or compute type parameters? -Julia does not support a special syntax for expressing constraints for type parameters, but these can be enforced in [constructors](@ref man-constructors). +The parameters of a [parametric type](@ref man-parametric-types) can hold either +types or bits values, and the type itself chooses how it makes use of these parameters. +For example, `Array{Float64, 2}` is parameterized by the type `Float64` to express its +element type and the integer value `2` to express its number of dimensions. When +defining your own parametric type, you can use subtype constraints to declare that a +certain parameter must be a subtype ([`<:`](@ref)) of some abstract type or a previous +type parameter. There is not, however, a dedicated syntax to declare that a parameter +must be a _value_ of a given type — that is, you cannot directly declare that a +dimensionality-like parameter [`isa`](@ref) `Int` within the `struct` definition, for +example. Similarly, you cannot do computations (including simple things like addition +or subtraction) on type parameters. Instead, these sorts of constraints and +relationships may be expressed through additional type parameters that are computed +and enforced within the type's [constructors](@ref man-constructors). As an example, consider ```julia From c49edda391e570de65aa3c37735f7426d5922147 Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Thu, 24 Oct 2019 08:37:58 +0200 Subject: [PATCH 4/5] revert from jldoctest to julia --- doc/src/manual/faq.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index b55580c1c253c..218985455947d 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -376,7 +376,7 @@ struct ConstrainedType{T,N,N+1} # NOTE: INVALID SYNTAX end ``` where the user would like to enforce that the third type parameter is always the second plus one. This can be implemented with an explicit type parameter that is checked by an [inner constructor method](@ref man-inner-constructor-methods) (where it can be combined with other checks): -```jldoctest +```julia struct ConstrainedType{T,N,M} A::Array{T,N} B::Array{T,M} @@ -387,7 +387,7 @@ struct ConstrainedType{T,N,M} end ``` This check is usually *costless*, as the compiler can elide the check for valid concrete types. If the second argument is also computed, it may be advantageous to provide an [outer constructor method](@ref man-outer-constructor-methods) that performs this calculation: -```jldoctest +```julia ConstrainedType(A) = ConstrainedType(A, compute_B(A)) ``` From 695ae94da535f0f309c0b33d7338213b2510b494 Mon Sep 17 00:00:00 2001 From: "Tamas K. Papp" Date: Thu, 24 Oct 2019 16:51:39 +0200 Subject: [PATCH 5/5] fix reference --- doc/src/manual/faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/manual/faq.md b/doc/src/manual/faq.md index 218985455947d..e3a94bdf9c1cb 100644 --- a/doc/src/manual/faq.md +++ b/doc/src/manual/faq.md @@ -354,7 +354,7 @@ julia> sqrt(-2.0+0im) ### How can I constrain or compute type parameters? -The parameters of a [parametric type](@ref man-parametric-types) can hold either +The parameters of a [parametric type](@ref Parametric-Types) can hold either types or bits values, and the type itself chooses how it makes use of these parameters. For example, `Array{Float64, 2}` is parameterized by the type `Float64` to express its element type and the integer value `2` to express its number of dimensions. When