Skip to content

Commit

Permalink
Add a FAQ entry for “computed/constrained type parameters”. (#33631)
Browse files Browse the repository at this point in the history
* Add a FAQ entry for “computed/constrained type parameters”.

* correction (thanks @rdeits)

* Update doc/src/manual/faq.md

Co-Authored-By: Matt Bauman <[email protected]>
  • Loading branch information
tpapp and mbauman committed Oct 28, 2019
1 parent dbaa6ff commit 88c34fc
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 3 deletions.
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

0 comments on commit 88c34fc

Please sign in to comment.