Skip to content
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

Add a FAQ entry for “computed/constrained type parameters”. #33631

Merged
merged 5 commits into from
Oct 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion base/docs/basedocs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
4 changes: 2 additions & 2 deletions doc/src/manual/constructors.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
39 changes: 39 additions & 0 deletions doc/src/manual/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,45 @@ julia> sqrt(-2.0+0im)
0.0 + 1.4142135623730951im
```

### How can I constrain or compute type parameters?

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
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
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):
```julia
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 + 1 == 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:
```julia
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
Expand Down