## [Operations on Types](#Operations-on-Types)
Since types in Julia are themselves objects, ordinary functions can operate on them. Some functions that are particularly useful for working with or exploring types have already been introduced, such as the `<:` operator, which indicates whether its left hand operand is a subtype of its right hand operand.
The [`isa`](../../base/base/#Core.isa) function tests if an object is of a given type and returns true or false:
```julia-repl
julia> isa(1, Int)
true

julia> isa(1, AbstractFloat)
false
```
The [`typeof`](../../base/base/#Core.typeof) function, already used throughout the manual in examples, returns the type of its argument. Since, as noted above, types are objects, they also have types, and we can ask what their types are:
```julia-repl
julia> typeof(Rational{Int})
DataType

julia> typeof(Union{Real,String})
Union
```
What if we repeat the process? What is the type of a type of a type? As it happens, types are all composite values and thus all have a type of `DataType`:
```julia-repl
julia> typeof(DataType)
DataType

julia> typeof(Union)
DataType
```
`DataType` is its own type.
Another operation that applies to some types is [`supertype`](../../base/base/#Base.supertype), which reveals a type's supertype. Only declared types (`DataType`) have unambiguous supertypes:
```julia-repl
julia> supertype(Float64)
AbstractFloat

julia> supertype(Number)
Any

julia> supertype(AbstractString)
Any

julia> supertype(Any)
Any
```


## [Operations on Types](#Operations-on-Types)
If you apply [`supertype`](../../base/base/#Base.supertype) to other type objects (or non-type objects), a [`MethodError`](../../base/base/#Core.MethodError) is raised:
```julia-repl
julia> supertype(Union{Float64,Int64})
ERROR: MethodError: no method matching supertype(::Type{Union{Float64, Int64}})
The function `supertype` exists, but no method is defined for this combination of argument types.

Closest candidates are:
[...]
```


## [Custom pretty-printing](#man-custom-pretty-printing)
Often, one wants to customize how instances of a type are displayed. This is accomplished by overloading the [`show`](../../base/io-network/#Base.show-Tuple%7BIO,%20Any%7D) function. For example, suppose we define a type to represent complex numbers in polar form:
```julia-repl
julia> struct Polar{T<:Real} <: Number
           r::T
           Θ::T
       end

julia> Polar(r::Real,Θ::Real) = Polar(promote(r,Θ)...)
Polar
```
Here, we've added a custom constructor function so that it can take arguments of different [`Real`](../../base/numbers/#Core.Real) types and promote them to a common type (see [Constructors](../constructors/#man-constructors) and [Conversion and Promotion](../conversion-and-promotion/#conversion-and-promotion)). (Of course, we would have to define lots of other methods, too, to make it act like a [`Number`](../../base/numbers/#Core.Number), e.g. `+`, `*`, `one`, `zero`, promotion rules and so on.) By default, instances of this type display rather simply, with information about the type name and the field values, as e.g. `Polar{Float64}(3.0,4.0)`.
If we want it to display instead as `3.0 * exp(4.0im)`, we would define the following method to print the object to a given output object `io` (representing a file, terminal, buffer, etcetera; see [Networking and Streams](../networking-and-streams/#Networking-and-Streams)):
```julia-repl
julia> Base.show(io::IO, z::Polar) = print(io, z.r, " * exp(", z.Θ, "im)")
```


## [Custom pretty-printing](#man-custom-pretty-printing)
More fine-grained control over display of `Polar` objects is possible. In particular, sometimes one wants both a verbose multi-line printing format, used for displaying a single object in the REPL and other interactive environments, and also a more compact single-line format used for [`print`](../../base/io-network/#Base.print) or for displaying the object as part of another object (e.g. in an array). Although by default the `show(io, z)` function is called in both cases, you can define a *different* multi-line format for displaying an object by overloading a three-argument form of `show` that takes the `text/plain` MIME type as its second argument (see [Multimedia I/O](../../base/io-network/#Multimedia-I/O)), for example:
```julia-repl
julia> Base.show(io::IO, ::MIME"text/plain", z::Polar{T}) where{T} =
           print(io, "Polar{$T} complex number:\n   ", z)
```
(Note that `print(..., z)` here will call the 2-argument `show(io, z)` method.) This results in:
```julia-repl
julia> Polar(3, 4.0)
Polar{Float64} complex number:
   3.0 * exp(4.0im)

julia> [Polar(3, 4.0), Polar(4.0,5.3)]
2-element Vector{Polar{Float64}}:
 3.0 * exp(4.0im)
 4.0 * exp(5.3im)
```


## [Custom pretty-printing](#man-custom-pretty-printing)
where the single-line `show(io, z)` form is still used for an array of `Polar` values. Technically, the REPL calls `display(z)` to display the result of executing a line, which defaults to `show(stdout, MIME("text/plain"), z)`, which in turn defaults to `show(stdout, z)`, but you should *not* define new [`display`](../../base/io-network/#Base.Multimedia.display) methods unless you are defining a new multimedia display handler (see [Multimedia I/O](../../base/io-network/#Multimedia-I/O)).
Moreover, you can also define `show` methods for other MIME types in order to enable richer display (HTML, images, etcetera) of objects in environments that support this (e.g. IJulia). For example, we can define formatted HTML display of `Polar` objects, with superscripts and italics, via:
```julia-repl
julia> Base.show(io::IO, ::MIME"text/html", z::Polar{T}) where {T} =
           println(io, "<code>Polar{$T}</code> complex number: ",
                   z.r, " <i>e</i><sup>", z.Θ, " <i>i</i></sup>")
```
A `Polar` object will then display automatically using HTML in an environment that supports HTML display, but you can call `show` manually to get HTML output if you want:
```julia-repl
julia> show(stdout, "text/html", Polar(3.0,4.0))
<code>Polar{Float64}</code> complex number: 3.0 <i>e</i><sup>4.0 <i>i</i></sup>
```
An HTML renderer would display this as: `Polar{Float64}` complex number: 3.0 *e*4.0 *i*


## [Custom pretty-printing](#man-custom-pretty-printing)
As a rule of thumb, the single-line `show` method should print a valid Julia expression for creating the shown object. When this `show` method contains infix operators, such as the multiplication operator (`*`) in our single-line `show` method for `Polar` above, it may not parse correctly when printed as part of another object. To see this, consider the expression object (see [Program representation](../metaprogramming/#Program-representation)) which takes the square of a specific instance of our `Polar` type:
```julia-repl
julia> a = Polar(3, 4.0)
Polar{Float64} complex number:
   3.0 * exp(4.0im)

julia> print(:($a^2))
3.0 * exp(4.0im) ^ 2
```
Because the operator `^` has higher precedence than `*` (see [Operator Precedence and Associativity](../mathematical-operations/#Operator-Precedence-and-Associativity)), this output does not faithfully represent the expression `a ^ 2` which should be equal to `(3.0 * exp(4.0im)) ^ 2`. To solve this issue, we must make a custom method for `Base.show_unquoted(io::IO, z::Polar, indent::Int, precedence::Int)`, which is called internally by the expression object when printing:
```julia-repl
julia> function Base.show_unquoted(io::IO, z::Polar, ::Int, precedence::Int)
           if Base.operator_precedence(:*) <= precedence
               print(io, "(")
               show(io, z)
               print(io, ")")
           else
               show(io, z)
           end
       end

julia> :($a^2)
:((3.0 * exp(4.0im)) ^ 2)
```


## [Custom pretty-printing](#man-custom-pretty-printing)
The method defined above adds parentheses around the call to `show` when the precedence of the calling operator is higher than or equal to the precedence of multiplication. This check allows expressions which parse correctly without the parentheses (such as `:($a + 2)` and `:($a == 2)`) to omit them when printing:
```julia-repl
julia> :($a + 2)
:(3.0 * exp(4.0im) + 2)

julia> :($a == 2)
:(3.0 * exp(4.0im) == 2)
```
In some cases, it is useful to adjust the behavior of `show` methods depending on the context. This can be achieved via the [`IOContext`](../../base/io-network/#Base.IOContext) type, which allows passing contextual properties together with a wrapped IO stream. For example, we can build a shorter representation in our `show` method when the `:compact` property is set to `true`, falling back to the long representation if the property is `false` or absent:
```julia-repl
julia> function Base.show(io::IO, z::Polar)
           if get(io, :compact, false)::Bool
               print(io, z.r, "ℯ", z.Θ, "im")
           else
               print(io, z.r, " * exp(", z.Θ, "im)")
           end
       end
```
This new compact representation will be used when the passed IO stream is an `IOContext` object with the `:compact` property set. In particular, this is the case when printing arrays with multiple columns (where horizontal space is limited):


## [Custom pretty-printing](#man-custom-pretty-printing)
```julia-repl
julia> show(IOContext(stdout, :compact=>true), Polar(3, 4.0))
3.0ℯ4.0im

julia> [Polar(3, 4.0) Polar(4.0,5.3)]
1×2 Matrix{Polar{Float64}}:
 3.0ℯ4.0im  4.0ℯ5.3im
```
See the [`IOContext`](../../base/io-network/#Base.IOContext) documentation for a list of common properties which can be used to adjust printing.


## ["Value types"](#%22Value-types%22)
In Julia, you can't dispatch on a *value* such as `true` or `false`. However, you can dispatch on parametric types, and Julia allows you to include "plain bits" values (Types, Symbols, Integers, floating-point numbers, tuples, etc.) as type parameters. A common example is the dimensionality parameter in `Array{T,N}`, where `T` is a type (e.g., [`Float64`](../../base/numbers/#Core.Float64)) but `N` is just an `Int`.
You can create your own custom types that take values as parameters, and use them to control dispatch of custom types. By way of illustration of this idea, let's introduce the parametric type `Val{x}`, and its constructor `Val(x) = Val{x}()`, which serves as a customary way to exploit this technique for cases where you don't need a more elaborate hierarchy.
[`Val`](../../base/base/#Base.Val) is defined as:
```julia-repl
julia> struct Val{x}
       end

julia> Val(x) = Val{x}()
Val
```
There is no more to the implementation of `Val` than this. Some functions in Julia's standard library accept `Val` instances as arguments, and you can also use it to write your own functions. For example:
```julia-repl
julia> firstlast(::Val{true}) = "First"
firstlast (generic function with 1 method)

julia> firstlast(::Val{false}) = "Last"
firstlast (generic function with 2 methods)

julia> firstlast(Val(true))
"First"

julia> firstlast(Val(false))
"Last"
```
For consistency across Julia, the call site should always pass a `Val` *instance* rather than using a *type*, i.e., use `foo(Val(:bar))` rather than `foo(Val{:bar})`.


## ["Value types"](#%22Value-types%22)
It's worth noting that it's extremely easy to mis-use parametric "value" types, including `Val`; in unfavorable cases, you can easily end up making the performance of your code much *worse*. In particular, you would never want to write actual code as illustrated above. For more information about the proper (and improper) uses of `Val`, please read [the more extensive discussion in the performance tips](../performance-tips/#man-performance-value-type).
-   [1](#citeref-1)"Small" is defined by the `max_union_splitting` configuration, which currently defaults to 4.
-   [2](#citeref-2)A few popular languages have singleton types, including Haskell, Scala and Ruby.
------------------------------------------------------------------------


# Methods · The Julia Language
Source: https://docs.julialang.org/en/v1/manual/methods/


# [Methods](#Methods)
Recall from [Functions](../functions/#man-functions) that a function is an object that maps a tuple of arguments to a return value, or throws an exception if no appropriate value can be returned. It is common for the same conceptual function or operation to be implemented quite differently for different types of arguments: adding two integers is very different from adding two floating-point numbers, both of which are distinct from adding an integer to a floating-point number. Despite their implementation differences, these operations all fall under the general concept of "addition". Accordingly, in Julia, these behaviors all belong to a single object: the `+` function.


# [Methods](#Methods)
To facilitate using many different implementations of the same concept smoothly, functions need not be defined all at once, but can rather be defined piecewise by providing specific behaviors for certain combinations of argument types and counts. A definition of one possible behavior for a function is called a *method*. Thus far, we have presented only examples of functions defined with a single method, applicable to all types of arguments. However, the signatures of method definitions can be annotated to indicate the types of arguments in addition to their number, and more than a single method definition may be provided. When a function is applied to a particular tuple of arguments, the most specific method applicable to those arguments is applied. Thus, the overall behavior of a function is a patchwork of the behaviors of its various method definitions. If the patchwork is well designed, even though the implementations of the methods may be quite different, the outward behavior of the function will appear seamless and consistent.


# [Methods](#Methods)
The choice of which method to execute when a function is applied is called *dispatch*. Julia allows the dispatch process to choose which of a function's methods to call based on the number of arguments given, and on the types of all of the function's arguments. This is different than traditional object-oriented languages, where dispatch occurs based only on the first argument, which often has a special argument syntax, and is sometimes implied rather than explicitly written as an argument. <sup>[[1\]](#footnote-1)</sup> Using all of a function's arguments to choose which method should be invoked, rather than just the first, is known as [multiple dispatch](https://en.wikipedia.org/wiki/Multiple_dispatch). Multiple dispatch is particularly useful for mathematical code, where it makes little sense to artificially deem the operations to "belong" to one argument more than any of the others: does the addition operation in `x + y` belong to `x` any more than it does to `y`? The implementation of a mathematical operator generally depends on the types of all of its arguments. Even beyond mathematical operations, however, multiple dispatch ends up being a powerful and convenient paradigm for structuring and organizing programs.
All the examples in this chapter assume that you are defining methods for a function in the *same* module. If you want to add methods to a function in *another* module, you have to `import` it or use the name qualified with module names. See the section on [namespace management](../modules/#namespace-management).


## [Defining Methods](#Defining-Methods)
Until now, we have, in our examples, defined only functions with a single method having unconstrained argument types. Such functions behave just like they would in traditional dynamically typed languages. Nevertheless, we have used multiple dispatch and methods almost continually without being aware of it: all of Julia's standard functions and operators, like the aforementioned `+` function, have many methods defining their behavior over various possible combinations of argument type and count.
When defining a function, one can optionally constrain the types of parameters it is applicable to, using the `::` type-assertion operator, introduced in the section on [Composite Types](../types/#Composite-Types):
```julia-repl
julia> f(x::Float64, y::Float64) = 2x + y
f (generic function with 1 method)
```
This function definition applies only to calls where `x` and `y` are both values of type [`Float64`](../../base/numbers/#Core.Float64):
```julia-repl
julia> f(2.0, 3.0)
7.0
```
Applying it to any other types of arguments will result in a [`MethodError`](../../base/base/#Core.MethodError):


## [Defining Methods](#Defining-Methods)
```julia-repl
julia> f(2.0, 3)
ERROR: MethodError: no method matching f(::Float64, ::Int64)
The function `f` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  f(::Float64, !Matched::Float64)
   @ Main none:1

Stacktrace:
[...]

julia> f(Float32(2.0), 3.0)
ERROR: MethodError: no method matching f(::Float32, ::Float64)
The function `f` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  f(!Matched::Float64, ::Float64)
   @ Main none:1

Stacktrace:
[...]

julia> f(2.0, "3.0")
ERROR: MethodError: no method matching f(::Float64, ::String)
The function `f` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  f(::Float64, !Matched::Float64)
   @ Main none:1

Stacktrace:
[...]

julia> f("2.0", "3.0")
ERROR: MethodError: no method matching f(::String, ::String)
The function `f` exists, but no method is defined for this combination of argument types.
```
As you can see, the arguments must be precisely of type [`Float64`](../../base/numbers/#Core.Float64). Other numeric types, such as integers or 32-bit floating-point values, are not automatically converted to 64-bit floating-point, nor are strings parsed as numbers. Because `Float64` is a concrete type and concrete types cannot be subclassed in Julia, such a definition can only be applied to arguments that are exactly of type `Float64`. It may often be useful, however, to write more general methods where the declared parameter types are abstract:


## [Defining Methods](#Defining-Methods)
```julia-repl
julia> f(x::Number, y::Number) = 2x - y
f (generic function with 2 methods)

julia> f(2.0, 3)
1.0
```
This method definition applies to any pair of arguments that are instances of [`Number`](../../base/numbers/#Core.Number). They need not be of the same type, so long as they are each numeric values. The problem of handling disparate numeric types is delegated to the arithmetic operations in the expression `2x - y`.
To define a function with multiple methods, one simply defines the function multiple times, with different numbers and types of arguments. The first method definition for a function creates the function object, and subsequent method definitions add new methods to the existing function object. The most specific method definition matching the number and types of the arguments will be executed when the function is applied. Thus, the two method definitions above, taken together, define the behavior for `f` over all pairs of instances of the abstract type `Number` – but with a different behavior specific to pairs of [`Float64`](../../base/numbers/#Core.Float64) values. If one of the arguments is a 64-bit float but the other one is not, then the `f(Float64,Float64)` method cannot be called and the more general `f(Number,Number)` method must be used:
```julia-repl
julia> f(2.0, 3.0)
7.0

julia> f(2, 3.0)
1.0

julia> f(2.0, 3)
1.0

julia> f(2, 3)
1
```


## [Defining Methods](#Defining-Methods)
The `2x + y` definition is only used in the first case, while the `2x - y` definition is used in the others. No automatic casting or conversion of function arguments is ever performed: all conversion in Julia is non-magical and completely explicit. [Conversion and Promotion](../conversion-and-promotion/#conversion-and-promotion), however, shows how clever application of sufficiently advanced technology can be indistinguishable from magic. <sup>[[Clarke61\]](#footnote-Clarke61)</sup>
For non-numeric values, and for fewer or more than two arguments, the function `f` remains undefined, and applying it will still result in a [`MethodError`](../../base/base/#Core.MethodError):
```julia-repl
julia> f("foo", 3)
ERROR: MethodError: no method matching f(::String, ::Int64)
The function `f` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  f(!Matched::Number, ::Number)
   @ Main none:1
  f(!Matched::Float64, !Matched::Float64)
   @ Main none:1

Stacktrace:
[...]

julia> f()
ERROR: MethodError: no method matching f()
The function `f` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  f(!Matched::Float64, !Matched::Float64)
   @ Main none:1
  f(!Matched::Number, !Matched::Number)
   @ Main none:1

Stacktrace:
[...]
```
You can easily see which methods exist for a function by entering the function object itself in an interactive session:
```julia-repl
julia> f
f (generic function with 2 methods)
```


## [Defining Methods](#Defining-Methods)
This output tells us that `f` is a function object with two methods. To find out what the signatures of those methods are, use the [`methods`](../../base/base/#Base.methods) function:
```julia-repl
julia> methods(f)
# 2 methods for generic function "f" from Main:
 [1] f(x::Float64, y::Float64)
     @ none:1
 [2] f(x::Number, y::Number)
     @ none:1
```
which shows that `f` has two methods, one taking two `Float64` arguments and one taking arguments of type `Number`. It also indicates the file and line number where the methods were defined: because these methods were defined at the REPL, we get the apparent line number `none:1`.
In the absence of a type declaration with `::`, the type of a method parameter is `Any` by default, meaning that it is unconstrained since all values in Julia are instances of the abstract type `Any`. Thus, we can define a catch-all method for `f` like so:
```julia-repl
julia> f(x,y) = println("Whoa there, Nelly.")
f (generic function with 3 methods)

julia> methods(f)
# 3 methods for generic function "f" from Main:
 [1] f(x::Float64, y::Float64)
     @ none:1
 [2] f(x::Number, y::Number)
     @ none:1
 [3] f(x, y)
     @ none:1

julia> f("foo", 1)
Whoa there, Nelly.
```
This catch-all is less specific than any other possible method definition for a pair of parameter values, so it will only be called on pairs of arguments to which no other method definition applies.


## [Defining Methods](#Defining-Methods)
Note that in the signature of the third method, there is no type specified for the arguments `x` and `y`. This is a shortened way of expressing `f(x::Any, y::Any)`.
Although it seems a simple concept, multiple dispatch on the types of values is perhaps the single most powerful and central feature of the Julia language. Core operations typically have dozens of methods:
```julia-repl
julia> methods(+)
# 180 methods for generic function "+":
[1] +(x::Bool, z::Complex{Bool}) in Base at complex.jl:227
[2] +(x::Bool, y::Bool) in Base at bool.jl:89
[3] +(x::Bool) in Base at bool.jl:86
[4] +(x::Bool, y::T) where T<:AbstractFloat in Base at bool.jl:96
[5] +(x::Bool, z::Complex) in Base at complex.jl:234
[6] +(a::Float16, b::Float16) in Base at float.jl:373
[7] +(x::Float32, y::Float32) in Base at float.jl:375
[8] +(x::Float64, y::Float64) in Base at float.jl:376
[9] +(z::Complex{Bool}, x::Bool) in Base at complex.jl:228
[10] +(z::Complex{Bool}, x::Real) in Base at complex.jl:242
[11] +(x::Char, y::Integer) in Base at char.jl:40
[12] +(c::BigInt, x::BigFloat) in Base.MPFR at mpfr.jl:307
[13] +(a::BigInt, b::BigInt, c::BigInt, d::BigInt, e::BigInt) in Base.GMP at gmp.jl:392
[14] +(a::BigInt, b::BigInt, c::BigInt, d::BigInt) in Base.GMP at gmp.jl:391
[15] +(a::BigInt, b::BigInt, c::BigInt) in Base.GMP at gmp.jl:390
[16] +(x::BigInt, y::BigInt) in Base.GMP at gmp.jl:361
[17] +(x::BigInt, c::Union{UInt16, UInt32, UInt64, UInt8}) in Base.GMP at gmp.jl:398
...
[180] +(a, b, c, xs...) in Base at operators.jl:424
```


## [Defining Methods](#Defining-Methods)
Multiple dispatch together with the flexible parametric type system give Julia its ability to abstractly express high-level algorithms decoupled from implementation details.


## [Method specializations](#man-method-specializations)
When you create multiple methods of the same function, this is sometimes called "specialization." In this case, you're specializing the *function* by adding additional methods to it: each new method is a new specialization of the function. As shown above, these specializations are returned by `methods`.
There's another kind of specialization that occurs without programmer intervention: Julia's compiler can automatically specialize the *method* for the specific argument types used. Such specializations are *not* listed by `methods`, as this doesn't create new `Method`s, but tools like [`@code_typed`](../../stdlib/InteractiveUtils/#InteractiveUtils.@code_typed) allow you to inspect such specializations.
For example, if you create a method
```julia
mysum(x::Real, y::Real) = x + y
```
you've given the function `mysum` one new method (possibly its only method), and that method takes any pair of `Real` number inputs. But if you then execute
```julia-repl
julia> mysum(1, 2)
3

julia> mysum(1.0, 2.0)
3.0
```


## [Method specializations](#man-method-specializations)
Julia will compile `mysum` twice, once for `x::Int, y::Int` and again for `x::Float64, y::Float64`. The point of compiling twice is performance: the methods that get called for `+` (which `mysum` uses) vary depending on the specific types of `x` and `y`, and by compiling different specializations Julia can do all the method lookup ahead of time. This allows the program to run much more quickly, since it does not have to bother with method lookup while it is running. Julia's automatic specialization allows you to write generic algorithms and expect that the compiler will generate efficient, specialized code to handle each case you need.
In cases where the number of potential specializations might be effectively unlimited, Julia may avoid this default specialization. See [Be aware of when Julia avoids specializing](../performance-tips/#Be-aware-of-when-Julia-avoids-specializing) for more information.


## [Method Ambiguities](#man-ambiguities)
It is possible to define a set of function methods such that there is no unique most specific method applicable to some combinations of arguments:
```julia-repl
julia> g(x::Float64, y) = 2x + y
g (generic function with 1 method)

julia> g(x, y::Float64) = x + 2y
g (generic function with 2 methods)

julia> g(2.0, 3)
7.0

julia> g(2, 3.0)
8.0

julia> g(2.0, 3.0)
ERROR: MethodError: g(::Float64, ::Float64) is ambiguous.

Candidates:
  g(x, y::Float64)
    @ Main none:1
  g(x::Float64, y)
    @ Main none:1

Possible fix, define
  g(::Float64, ::Float64)

Stacktrace:
[...]
```
Here the call `g(2.0, 3.0)` could be handled by either the `g(::Float64, ::Any)` or the `g(::Any, ::Float64)` method. The order in which the methods are defined does not matter and neither is more specific than the other. In such cases, Julia raises a [`MethodError`](../../base/base/#Core.MethodError) rather than arbitrarily picking a method. You can avoid method ambiguities by specifying an appropriate method for the intersection case:
```julia-repl
julia> g(x::Float64, y::Float64) = 2x + 2y
g (generic function with 3 methods)

julia> g(2.0, 3)
7.0

julia> g(2, 3.0)
8.0

julia> g(2.0, 3.0)
10.0
```
It is recommended that the disambiguating method be defined first, since otherwise the ambiguity exists, if transiently, until the more specific method is defined.
In more complex cases, resolving method ambiguities involves a certain element of design; this topic is explored further [below](#man-method-design-ambiguities).


## [Parametric Methods](#Parametric-Methods)
Method definitions can optionally have type parameters qualifying the signature:
```julia-repl
julia> same_type(x::T, y::T) where {T} = true
same_type (generic function with 1 method)

julia> same_type(x,y) = false
same_type (generic function with 2 methods)
```
The first method applies whenever both arguments are of the same concrete type, regardless of what type that is, while the second method acts as a catch-all, covering all other cases. Thus, overall, this defines a boolean function that checks whether its two arguments are of the same type:
```julia-repl
julia> same_type(1, 2)
true

julia> same_type(1, 2.0)
false

julia> same_type(1.0, 2.0)
true

julia> same_type("foo", 2.0)
false

julia> same_type("foo", "bar")
true

julia> same_type(Int32(1), Int64(2))
false
```
Such definitions correspond to methods whose type signatures are `UnionAll` types (see [UnionAll Types](../types/#UnionAll-Types)).
This kind of definition of function behavior by dispatch is quite common – idiomatic, even – in Julia. Method type parameters are not restricted to being used as the types of arguments: they can be used anywhere a value would be in the signature of the function or body of the function. Here's an example where the method type parameter `T` is used as the type parameter to the parametric type `Vector{T}` in the method signature:
```julia-repl
julia> function myappend(v::Vector{T}, x::T) where {T}
           return [v..., x]
       end
myappend (generic function with 1 method)
```


## [Parametric Methods](#Parametric-Methods)
The type parameter `T` in this example ensures that the added element `x` is a subtype of the existing eltype of the vector `v`. The `where` keyword introduces a list of those constraints after the method signature definition. This works the same for one-line definitions, as seen above, and must appear *before* the [return type declaration](../functions/#man-functions-return-type), if present, as illustrated below:
```julia-repl
julia> (myappend(v::Vector{T}, x::T)::Vector) where {T} = [v..., x]
myappend (generic function with 1 method)

julia> myappend([1,2,3],4)
4-element Vector{Int64}:
 1
 2
 3
 4

julia> myappend([1,2,3],2.5)
ERROR: MethodError: no method matching myappend(::Vector{Int64}, ::Float64)
The function `myappend` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  myappend(::Vector{T}, !Matched::T) where T
   @ Main none:1

Stacktrace:
[...]

julia> myappend([1.0,2.0,3.0],4.0)
4-element Vector{Float64}:
 1.0
 2.0
 3.0
 4.0

julia> myappend([1.0,2.0,3.0],4)
ERROR: MethodError: no method matching myappend(::Vector{Float64}, ::Int64)
The function `myappend` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  myappend(::Vector{T}, !Matched::T) where T
   @ Main none:1

Stacktrace:
[...]
```


## [Parametric Methods](#Parametric-Methods)
If the type of the appended element does not match the element type of the vector it is appended to, a [`MethodError`](../../base/base/#Core.MethodError) is raised. In the following example, the method's type parameter `T` is used as the return value:
```julia-repl
julia> mytypeof(x::T) where {T} = T
mytypeof (generic function with 1 method)

julia> mytypeof(1)
Int64

julia> mytypeof(1.0)
Float64
```
Just as you can put subtype constraints on type parameters in type declarations (see [Parametric Types](../types/#Parametric-Types)), you can also constrain type parameters of methods:


## [Parametric Methods](#Parametric-Methods)
```julia-repl
julia> same_type_numeric(x::T, y::T) where {T<:Number} = true
same_type_numeric (generic function with 1 method)

julia> same_type_numeric(x::Number, y::Number) = false
same_type_numeric (generic function with 2 methods)

julia> same_type_numeric(1, 2)
true

julia> same_type_numeric(1, 2.0)
false

julia> same_type_numeric(1.0, 2.0)
true

julia> same_type_numeric("foo", 2.0)
ERROR: MethodError: no method matching same_type_numeric(::String, ::Float64)
The function `same_type_numeric` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  same_type_numeric(!Matched::T, ::T) where T<:Number
   @ Main none:1
  same_type_numeric(!Matched::Number, ::Number)
   @ Main none:1

Stacktrace:
[...]

julia> same_type_numeric("foo", "bar")
ERROR: MethodError: no method matching same_type_numeric(::String, ::String)
The function `same_type_numeric` exists, but no method is defined for this combination of argument types.

julia> same_type_numeric(Int32(1), Int64(2))
false
```
The `same_type_numeric` function behaves much like the `same_type` function defined above, but is only defined for pairs of numbers.


## [Parametric Methods](#Parametric-Methods)
Parametric methods allow the same syntax as `where` expressions used to write types (see [UnionAll Types](../types/#UnionAll-Types)). If there is only a single parameter, the enclosing curly braces (in `where {T}`) can be omitted, but are often preferred for clarity. Multiple parameters can be separated with commas, e.g. `where {T, S<:Real}`, or written using nested `where`, e.g. `where S<:Real where T`.


## [Redefining Methods](#Redefining-Methods)
When redefining a method or adding new methods, it is important to realize that these changes don't take effect immediately. This is key to Julia's ability to statically infer and compile code to run fast, without the usual JIT tricks and overhead. Indeed, any new method definition won't be visible to the current runtime environment, including Tasks and Threads (and any previously defined `@generated` functions). Let's start with an example to see what this means:
```julia-repl
julia> function tryeval()
           @eval newfun() = 1
           newfun()
       end
tryeval (generic function with 1 method)

julia> tryeval()
ERROR: MethodError: no method matching newfun()
The applicable method may be too new: running in world age xxxx1, while current world is xxxx2.
Closest candidates are:
  newfun() at none:1 (method too new to be called from this world context.)
 in tryeval() at none:1
 ...

julia> newfun()
1
```
In this example, observe that the new definition for `newfun` has been created, but can't be immediately called. The new global is immediately visible to the `tryeval` function, so you could write `return newfun` (without parentheses). But neither you, nor any of your callers, nor the functions they call, or etc. can call this new method definition!
But there's an exception: future calls to `newfun` *from the REPL* work as expected, being able to both see and call the new definition of `newfun`.


## [Redefining Methods](#Redefining-Methods)
However, future calls to `tryeval` will continue to see the definition of `newfun` as it was *at the previous statement at the REPL*, and thus before that call to `tryeval`.
You may want to try this for yourself to see how it works.
The implementation of this behavior is a "world age counter". This monotonically increasing value tracks each method definition operation. This allows describing "the set of method definitions visible to a given runtime environment" as a single number, or "world age". It also allows comparing the methods available in two worlds just by comparing their ordinal value. In the example above, we see that the "current world" (in which the method `newfun` exists), is one greater than the task-local "runtime world" that was fixed when the execution of `tryeval` started.
Sometimes it is necessary to get around this (for example, if you are implementing the above REPL). Fortunately, there is an easy solution: call the function using [`Base.invokelatest`](../../base/base/#Base.invokelatest):
```julia-repl
julia> function tryeval2()
           @eval newfun2() = 2
           Base.invokelatest(newfun2)
       end
tryeval2 (generic function with 1 method)

julia> tryeval2()
2
```
Finally, let's take a look at some more complex examples where this rule comes into play. Define a function `f(x)`, which initially has one method:
```julia-repl
julia> f(x) = "original definition"
f (generic function with 1 method)
```
Start some other operations that use `f(x)`:


## [Redefining Methods](#Redefining-Methods)
```julia-repl
julia> g(x) = f(x)
g (generic function with 1 method)

julia> t = @async f(wait()); yield();
```
Now we add some new methods to `f(x)`:
```julia-repl
julia> f(x::Int) = "definition for Int"
f (generic function with 2 methods)

julia> f(x::Type{Int}) = "definition for Type{Int}"
f (generic function with 3 methods)
```
Compare how these results differ:
```julia-repl
julia> f(1)
"definition for Int"

julia> g(1)
"definition for Int"

julia> fetch(schedule(t, 1))
"original definition"

julia> t = @async f(wait()); yield();

julia> fetch(schedule(t, 1))
"definition for Int"
```


## [Design Patterns with Parametric Methods](#Design-Patterns-with-Parametric-Methods)
While complex dispatch logic is not required for performance or usability, sometimes it can be the best way to express some algorithm. Here are a few common design patterns that come up sometimes when using dispatch in this way.


### [Extracting the type parameter from a super-type](#Extracting-the-type-parameter-from-a-super-type)
Here is a correct code template for returning the element-type `T` of any arbitrary subtype of `AbstractArray` that has well-defined element type:
```julia
abstract type AbstractArray{T, N} end
eltype(::Type{<:AbstractArray{T}}) where {T} = T
```
using so-called triangular dispatch. Note that `UnionAll` types, for example `eltype(AbstractArray{T} where T <: Integer)`, do not match the above method. The implementation of `eltype` in `Base` adds a fallback method to `Any` for such cases.
One common mistake is to try and get the element-type by using introspection:
```julia
eltype_wrong(::Type{A}) where {A<:AbstractArray} = A.parameters[1]
```
However, it is not hard to construct cases where this will fail:
```julia
struct BitVector <: AbstractArray{Bool, 1}; end
```
Here we have created a type `BitVector` which has no parameters, but where the element-type is still fully specified, with `T` equal to `Bool`!
Another mistake is to try to walk up the type hierarchy using `supertype`:
```julia
eltype_wrong(::Type{AbstractArray{T}}) where {T} = T
eltype_wrong(::Type{AbstractArray{T, N}}) where {T, N} = T
eltype_wrong(::Type{A}) where {A<:AbstractArray} = eltype_wrong(supertype(A))
```
While this works for declared types, it fails for types without supertypes:


### [Extracting the type parameter from a super-type](#Extracting-the-type-parameter-from-a-super-type)
```julia-repl
julia> eltype_wrong(Union{AbstractArray{Int}, AbstractArray{Float64}})
ERROR: MethodError: no method matching supertype(::Type{Union{AbstractArray{Float64,N} where N, AbstractArray{Int64,N} where N}})
Closest candidates are:
  supertype(::DataType) at operators.jl:43
  supertype(::UnionAll) at operators.jl:48
```


### [Building a similar type with a different type parameter](#Building-a-similar-type-with-a-different-type-parameter)
When building generic code, there is often a need for constructing a similar object with some change made to the layout of the type, also necessitating a change of the type parameters. For instance, you might have some sort of abstract array with an arbitrary element type and want to write your computation on it with a specific element type. We must implement a method for each `AbstractArray{T}` subtype that describes how to compute this type transform. There is no general transform of one subtype into another subtype with a different parameter.
The subtypes of `AbstractArray` typically implement two methods to achieve this: A method to convert the input array to a subtype of a specific `AbstractArray{T, N}` abstract type; and a method to make a new uninitialized array with a specific element type. Sample implementations of these can be found in Julia Base. Here is a basic example usage of them, guaranteeing that `input` and `output` are of the same type:
```julia
input = convert(AbstractArray{Eltype}, input)
output = similar(input, Eltype)
```


### [Building a similar type with a different type parameter](#Building-a-similar-type-with-a-different-type-parameter)
As an extension of this, in cases where the algorithm needs a copy of the input array, [`convert`](../../base/base/#Base.convert) is insufficient as the return value may alias the original input. Combining [`similar`](../../base/arrays/#Base.similar) (to make the output array) and [`copyto!`](../../base/c/#Base.copyto!) (to fill it with the input data) is a generic way to express the requirement for a mutable copy of the input argument:
```julia
copy_with_eltype(input, Eltype) = copyto!(similar(input, Eltype), input)
```


### [Iterated dispatch](#Iterated-dispatch)
In order to dispatch a multi-level parametric argument list, often it is best to separate each level of dispatch into distinct functions. This may sound similar in approach to single-dispatch, but as we shall see below, it is still more flexible.
For example, trying to dispatch on the element-type of an array will often run into ambiguous situations. Instead, commonly code will dispatch first on the container type, then recurse down to a more specific method based on eltype. In most cases, the algorithms lend themselves conveniently to this hierarchical approach, while in other cases, this rigor must be resolved manually. This dispatching branching can be observed, for example, in the logic to sum two matrices:
```julia
# First dispatch selects the map algorithm for element-wise summation.
+(a::Matrix, b::Matrix) = map(+, a, b)
# Then dispatch handles each element and selects the appropriate
# common element type for the computation.
+(a, b) = +(promote(a, b)...)
# Once the elements have the same type, they can be added.
# For example, via primitive operations exposed by the processor.
+(a::Float64, b::Float64) = Core.add(a, b)
```


### [Trait-based dispatch](#Trait-based-dispatch)
A natural extension to the iterated dispatch above is to add a layer to method selection that allows to dispatch on sets of types which are independent from the sets defined by the type hierarchy. We could construct such a set by writing out a `Union` of the types in question, but then this set would not be extensible as `Union`-types cannot be altered after creation. However, such an extensible set can be programmed with a design pattern often referred to as a ["Holy-trait"](https://github.com/JuliaLang/julia/issues/2345#issuecomment-54537633).
This pattern is implemented by defining a generic function which computes a different singleton value (or type) for each trait-set to which the function arguments may belong to. If this function is pure there is no impact on performance compared to normal dispatch.


### [Trait-based dispatch](#Trait-based-dispatch)
The example in the previous section glossed over the implementation details of [`map`](../../base/collections/#Base.map) and [`promote`](../../base/base/#Base.promote), which both operate in terms of these traits. When iterating over a matrix, such as in the implementation of `map`, one important question is what order to use to traverse the data. When `AbstractArray` subtypes implement the [`Base.IndexStyle`](../../base/arrays/#Base.IndexStyle) trait, other functions such as `map` can dispatch on this information to pick the best algorithm (see [Abstract Array Interface](../interfaces/#man-interface-array)). This means that each subtype does not need to implement a custom version of `map`, since the generic definitions + trait classes will enable the system to select the fastest version. Here is a toy implementation of `map` illustrating the trait-based dispatch:
```julia
map(f, a::AbstractArray, b::AbstractArray) = map(Base.IndexStyle(a, b), f, a, b)
# generic implementation:
map(::Base.IndexCartesian, f, a::AbstractArray, b::AbstractArray) = ...
# linear-indexing implementation (faster)
map(::Base.IndexLinear, f, a::AbstractArray, b::AbstractArray) = ...
```


### [Trait-based dispatch](#Trait-based-dispatch)
This trait-based approach is also present in the [`promote`](../../base/base/#Base.promote) mechanism employed by the scalar `+`. It uses [`promote_type`](../../base/base/#Base.promote_type), which returns the optimal common type to compute the operation given the two types of the operands. This makes it possible to reduce the problem of implementing every function for every pair of possible type arguments, to the much smaller problem of implementing a conversion operation from each type to a common type, plus a table of preferred pair-wise promotion rules.


### [Output-type computation](#Output-type-computation)
The discussion of trait-based promotion provides a transition into our next design pattern: computing the output element type for a matrix operation.
For implementing primitive operations, such as addition, we use the [`promote_type`](../../base/base/#Base.promote_type) function to compute the desired output type. (As before, we saw this at work in the `promote` call in the call to `+`).
For more complex functions on matrices, it may be necessary to compute the expected return type for a more complex sequence of operations. This is often performed by the following steps:
1.  Write a small function `op` that expresses the set of operations performed by the kernel of the algorithm.
2.  Compute the element type `R` of the result matrix as `promote_op(op, argument_types...)`, where `argument_types` is computed from `eltype` applied to each input array.
3.  Build the output matrix as `similar(R, dims)`, where `dims` are the desired dimensions of the output array.
For a more specific example, a generic square-matrix multiply pseudo-code might look like:


### [Output-type computation](#Output-type-computation)
```julia
function matmul(a::AbstractMatrix, b::AbstractMatrix)
    op = (ai, bi) -> ai * bi + ai * bi

    ## this is insufficient because it assumes `one(eltype(a))` is constructable:
    # R = typeof(op(one(eltype(a)), one(eltype(b))))

    ## this fails because it assumes `a[1]` exists and is representative of all elements of the array
    # R = typeof(op(a[1], b[1]))

    ## this is incorrect because it assumes that `+` calls `promote_type`
    ## but this is not true for some types, such as Bool:
    # R = promote_type(ai, bi)

    # this is wrong, since depending on the return value
    # of type-inference is very brittle (as well as not being optimizable):
    # R = Base.return_types(op, (eltype(a), eltype(b)))

    ## but, finally, this works:
    R = promote_op(op, eltype(a), eltype(b))
    ## although sometimes it may give a larger type than desired
    ## it will always give a correct type

    output = similar(b, R, (size(a, 1), size(b, 2)))
    if size(a, 2) > 0
        for j in 1:size(b, 2)
            for i in 1:size(a, 1)
                ## here we don't use `ab = zero(R)`,
                ## since `R` might be `Any` and `zero(Any)` is not defined
                ## we also must declare `ab::R` to make the type of `ab` constant in the loop,
                ## since it is possible that typeof(a * b) != typeof(a * b + a * b) == R
                ab::R = a[i, 1] * b[1, j]
                for k in 2:size(a, 2)
                    ab += a[i, k] * b[k, j]
                end
                output[i, j] = ab
            end
        end
    end
    return output
end
```


### [Separate convert and kernel logic](#Separate-convert-and-kernel-logic)
One way to significantly cut down on compile-times and testing complexity is to isolate the logic for converting to the desired type and the computation. This lets the compiler specialize and inline the conversion logic independent from the rest of the body of the larger kernel.
This is a common pattern seen when converting from a larger class of types to the one specific argument type that is actually supported by the algorithm:
```julia
complexfunction(arg::Int) = ...
complexfunction(arg::Any) = complexfunction(convert(Int, arg))

matmul(a::T, b::T) = ...
matmul(a, b) = matmul(promote(a, b)...)
```


## [Parametrically-constrained Varargs methods](#Parametrically-constrained-Varargs-methods)
Function parameters can also be used to constrain the number of arguments that may be supplied to a "varargs" function ([Varargs Functions](../functions/#Varargs-Functions)). The notation `Vararg{T,N}` is used to indicate such a constraint. For example:
```julia-repl
julia> bar(a,b,x::Vararg{Any,2}) = (a,b,x)
bar (generic function with 1 method)

julia> bar(1,2,3)
ERROR: MethodError: no method matching bar(::Int64, ::Int64, ::Int64)
The function `bar` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  bar(::Any, ::Any, ::Any, !Matched::Any)
   @ Main none:1

Stacktrace:
[...]

julia> bar(1,2,3,4)
(1, 2, (3, 4))

julia> bar(1,2,3,4,5)
ERROR: MethodError: no method matching bar(::Int64, ::Int64, ::Int64, ::Int64, ::Int64)
The function `bar` exists, but no method is defined for this combination of argument types.

Closest candidates are:
  bar(::Any, ::Any, ::Any, ::Any)
   @ Main none:1

Stacktrace:
[...]
```
More usefully, it is possible to constrain varargs methods by a parameter. For example:
```julia
function getindex(A::AbstractArray{T,N}, indices::Vararg{Number,N}) where {T,N}
```
would be called only when the number of `indices` matches the dimensionality of the array.
When only the type of supplied arguments needs to be constrained `Vararg{T}` can be equivalently written as `T...`. For instance `f(x::Int...) = x` is a shorthand for `f(x::Vararg{Int}) = x`.


## [Note on Optional and keyword Arguments](#Note-on-Optional-and-keyword-Arguments)
As mentioned briefly in [Functions](../functions/#man-functions), optional arguments are implemented as syntax for multiple method definitions. For example, this definition:
```julia
f(a=1,b=2) = a+2b
```
translates to the following three methods:
```julia
f(a,b) = a+2b
f(a) = f(a,2)
f() = f(1,2)
```
This means that calling `f()` is equivalent to calling `f(1,2)`. In this case the result is `5`, because `f(1,2)` invokes the first method of `f` above. However, this need not always be the case. If you define a fourth method that is more specialized for integers:
```julia
f(a::Int,b::Int) = a-2b
```
then the result of both `f()` and `f(1,2)` is `-3`. In other words, optional arguments are tied to a function, not to any specific method of that function. It depends on the types of the optional arguments which method is invoked. When optional arguments are defined in terms of a global variable, the type of the optional argument may even change at run-time.
Keyword arguments behave quite differently from ordinary positional arguments. In particular, they do not participate in method dispatch. Methods are dispatched based only on positional arguments, with keyword arguments processed after the matching method is identified.


## [Function-like objects](#Function-like-objects)
Methods are associated with types, so it is possible to make any arbitrary Julia object "callable" by adding methods to its type. (Such "callable" objects are sometimes called "functors.")
For example, you can define a type that stores the coefficients of a polynomial, but behaves like a function evaluating the polynomial:
```julia-repl
julia> struct Polynomial{R}
           coeffs::Vector{R}
       end

julia> function (p::Polynomial)(x)
           v = p.coeffs[end]
           for i = (length(p.coeffs)-1):-1:1
               v = v*x + p.coeffs[i]
           end
           return v
       end

julia> (p::Polynomial)() = p(5)
```
Notice that the function is specified by type instead of by name. As with normal functions there is a terse syntax form. In the function body, `p` will refer to the object that was called. A `Polynomial` can be used as follows:
```julia-repl
julia> p = Polynomial([1,10,100])
Polynomial{Int64}([1, 10, 100])

julia> p(3)
931

julia> p()
2551
```
This mechanism is also the key to how type constructors and closures (inner functions that refer to their surrounding environment) work in Julia.


## [Empty generic functions](#Empty-generic-functions)
Occasionally it is useful to introduce a generic function without yet adding methods. This can be used to separate interface definitions from implementations. It might also be done for the purpose of documentation or code readability. The syntax for this is an empty `function` block without a tuple of arguments:
```julia
function emptyfunc end
```


## [Method design and the avoidance of ambiguities](#man-method-design-ambiguities)
Julia's method polymorphism is one of its most powerful features, yet exploiting this power can pose design challenges. In particular, in more complex method hierarchies it is not uncommon for [ambiguities](#man-ambiguities) to arise.
Above, it was pointed out that one can resolve ambiguities like
```julia
f(x, y::Int) = 1
f(x::Int, y) = 2
```
by defining a method
```julia
f(x::Int, y::Int) = 3
```
This is often the right strategy; however, there are circumstances where following this advice mindlessly can be counterproductive. In particular, the more methods a generic function has, the more possibilities there are for ambiguities. When your method hierarchies get more complicated than this simple example, it can be worth your while to think carefully about alternative strategies.
Below we discuss particular challenges and some alternative ways to resolve such issues.


### [Tuple and NTuple arguments](#Tuple-and-NTuple-arguments)
`Tuple` (and `NTuple`) arguments present special challenges. For example,
```julia
f(x::NTuple{N,Int}) where {N} = 1
f(x::NTuple{N,Float64}) where {N} = 2
```
are ambiguous because of the possibility that `N == 0`: there are no elements to determine whether the `Int` or `Float64` variant should be called. To resolve the ambiguity, one approach is define a method for the empty tuple:
```julia
f(x::Tuple{}) = 3
```
Alternatively, for all methods but one you can insist that there is at least one element in the tuple:
```julia
f(x::NTuple{N,Int}) where {N} = 1           # this is the fallback
f(x::Tuple{Float64, Vararg{Float64}}) = 2   # this requires at least one Float64
```


### [Orthogonalize your design](#man-methods-orthogonalize)
When you might be tempted to dispatch on two or more arguments, consider whether a "wrapper" function might make for a simpler design. For example, instead of writing multiple variants:
```julia
f(x::A, y::A) = ...
f(x::A, y::B) = ...
f(x::B, y::A) = ...
f(x::B, y::B) = ...
```
you might consider defining
```julia
f(x::A, y::A) = ...
f(x, y) = f(g(x), g(y))
```
where `g` converts the argument to type `A`. This is a very specific example of the more general principle of [orthogonal design](https://en.wikipedia.org/wiki/Orthogonality_(programming)), in which separate concepts are assigned to separate methods. Here, `g` will most likely need a fallback definition
```julia
g(x::A) = x
```
A related strategy exploits `promote` to bring `x` and `y` to a common type:
```julia
f(x::T, y::T) where {T} = ...
f(x, y) = f(promote(x, y)...)
```
One risk with this design is the possibility that if there is no suitable promotion method converting `x` and `y` to the same type, the second method will recurse on itself infinitely and trigger a stack overflow.


### [Dispatch on one argument at a time](#Dispatch-on-one-argument-at-a-time)
If you need to dispatch on multiple arguments, and there are many fallbacks with too many combinations to make it practical to define all possible variants, then consider introducing a "name cascade" where (for example) you dispatch on the first argument and then call an internal method:
```julia
f(x::A, y) = _fA(x, y)
f(x::B, y) = _fB(x, y)
```
Then the internal methods `_fA` and `_fB` can dispatch on `y` without concern about ambiguities with each other with respect to `x`.
Be aware that this strategy has at least one major disadvantage: in many cases, it is not possible for users to further customize the behavior of `f` by defining further specializations of your exported function `f`. Instead, they have to define specializations for your internal methods `_fA` and `_fB`, and this blurs the lines between exported and internal methods.


### [Abstract containers and element types](#Abstract-containers-and-element-types)
Where possible, try to avoid defining methods that dispatch on specific element types of abstract containers. For example,
```julia
-(A::AbstractArray{T}, b::Date) where {T<:Date}
```
generates ambiguities for anyone who defines a method
```julia
-(A::MyArrayType{T}, b::T) where {T}
```
The best approach is to avoid defining *either* of these methods: instead, rely on a generic method `-(A::AbstractArray, b)` and make sure this method is implemented with generic calls (like `similar` and `-`) that do the right thing for each container type and element type *separately*. This is just a more complex variant of the advice to [orthogonalize](#man-methods-orthogonalize) your methods.
When this approach is not possible, it may be worth starting a discussion with other developers about resolving the ambiguity; just because one method was defined first does not necessarily mean that it can't be modified or eliminated. As a last resort, one developer can define the "band-aid" method
```julia
-(A::MyArrayType{T}, b::Date) where {T<:Date} = ...
```
that resolves the ambiguity by brute force.


### [Complex method "cascades" with default arguments](#Complex-method-%22cascades%22-with-default-arguments)
If you are defining a method "cascade" that supplies defaults, be careful about dropping any arguments that correspond to potential defaults. For example, suppose you're writing a digital filtering algorithm and you have a method that handles the edges of the signal by applying padding:
```julia
function myfilter(A, kernel, ::Replicate)
    Apadded = replicate_edges(A, size(kernel))
    myfilter(Apadded, kernel)  # now perform the "real" computation
end
```
This will run afoul of a method that supplies default padding:
```julia
myfilter(A, kernel) = myfilter(A, kernel, Replicate()) # replicate the edge by default
```
Together, these two methods generate an infinite recursion with `A` constantly growing bigger.
The better design would be to define your call hierarchy like this:
```julia
struct NoPad end  # indicate that no padding is desired, or that it's already applied

myfilter(A, kernel) = myfilter(A, kernel, Replicate())  # default boundary conditions

function myfilter(A, kernel, ::Replicate)
    Apadded = replicate_edges(A, size(kernel))
    myfilter(Apadded, kernel, NoPad())  # indicate the new boundary conditions
end

# other padding methods go here

function myfilter(A, kernel, ::NoPad)
    # Here's the "real" implementation of the core computation
end
```


### [Complex method "cascades" with default arguments](#Complex-method-%22cascades%22-with-default-arguments)
`NoPad` is supplied in the same argument position as any other kind of padding, so it keeps the dispatch hierarchy well organized and with reduced likelihood of ambiguities. Moreover, it extends the "public" `myfilter` interface: a user who wants to control the padding explicitly can call the `NoPad` variant directly.


## [Defining methods in local scope](#Defining-methods-in-local-scope)
You can define methods within a [local scope](../variables-and-scoping/#scope-of-variables), for example
```julia-repl
julia> function f(x)
           g(y::Int) = y + x
           g(y) = y - x
           g
       end
f (generic function with 1 method)

julia> h = f(3);

julia> h(4)
7

julia> h(4.0)
1.0
```
However, you should *not* define local methods conditionally or subject to control flow, as in
```julia
function f2(inc)
    if inc
        g(x) = x + 1
    else
        g(x) = x - 1
    end
end

function f3()
    function g end
    return g
    g() = 0
end
```
as it is not clear what function will end up getting defined. In the future, it might be an error to define local methods in this manner.
For cases like this use anonymous functions instead:
```julia
function f2(inc)
    g = if inc
        x -> x + 1
    else
        x -> x - 1
    end
end
```
-   [1](#citeref-1)In C++ or Java, for example, in a method call like `obj.meth(arg1,arg2)`, the object obj "receives" the method call and is implicitly passed to the method via the `this` keyword, rather than as an explicit method argument. When the current `this` object is the receiver of a method call, it can be omitted altogether, writing just `meth(arg1,arg2)`, with `this` implied as the receiving object.
-   [Clarke61](#citeref-Clarke61)Arthur C. Clarke, *Profiles of the Future* (1961): Clarke's Third Law.
------------------------------------------------------------------------


# Constructors · The Julia Language
Source: https://docs.julialang.org/en/v1/manual/constructors/


# [Constructors](#man-constructors)
Constructors <sup>[[1\]](#footnote-1)</sup> are functions that create new objects – specifically, instances of [Composite Types](../types/#Composite-Types). In Julia, type objects also serve as constructor functions: they create new instances of themselves when applied to an argument tuple as a function. This much was already mentioned briefly when composite types were introduced. For example:
```julia-repl
julia> struct Foo
           bar
           baz
       end

julia> foo = Foo(1, 2)
Foo(1, 2)

julia> foo.bar
1

julia> foo.baz
2
```
For many types, forming new objects by binding their field values together is all that is ever needed to create instances. However, in some cases more functionality is required when creating composite objects. Sometimes invariants must be enforced, either by checking arguments or by transforming them. [Recursive data structures](https://en.wikipedia.org/wiki/Recursion_%28computer_science%29#Recursive_data_structures_.28structural_recursion.29), especially those that may be self-referential, often cannot be constructed cleanly without first being created in an incomplete state and then altered programmatically to be made whole, as a separate step from object creation. Sometimes, it's just convenient to be able to construct objects with fewer or different types of parameters than they have fields. Julia's system for object construction addresses all of these cases and more.


## [Outer Constructor Methods](#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 by simply defining new methods. For example, let's say you want to add a constructor method for `Foo` objects that takes only one argument and uses the given value for both the `bar` and `baz` fields. This is simple:
```julia-repl
julia> Foo(x) = Foo(x,x)
Foo

julia> Foo(1)
Foo(1, 1)
```
You could also add a zero-argument `Foo` constructor method that supplies default values for both of the `bar` and `baz` fields:
```julia-repl
julia> Foo() = Foo(0)
Foo

julia> Foo()
Foo(0, 0)
```
Here the zero-argument constructor method calls the single-argument constructor method, which in turn calls the automatically provided two-argument constructor method. For reasons that will become clear very shortly, additional constructor methods declared as normal methods like this 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](#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 introduction of this chapter: enforcing invariants, and allowing construction of self-referential objects. For these problems, one needs *inner* constructor methods. An inner constructor method is like an outer constructor method, except for two differences:
1.  It is declared inside the block of a type declaration, rather than outside of it like normal methods.
2.  It has access to a special locally existent function called [`new`](../../base/base/#new) that creates objects of the block's type.
For example, suppose one wants to declare a type that holds a pair of real numbers, subject to the constraint that the first number is not greater than the second one. One could declare it like this:
```julia-repl
julia> struct OrderedPair
           x::Real
           y::Real
           OrderedPair(x,y) = x > y ? error("out of order") : new(x,y)
       end
```
Now `OrderedPair` objects can only be constructed such that `x <= y`:
```julia-repl
julia> OrderedPair(1, 2)
OrderedPair(1, 2)

julia> OrderedPair(2,1)
ERROR: out of order
Stacktrace:
 [1] error at ./error.jl:33 [inlined]
 [2] OrderedPair(::Int64, ::Int64) at ./none:4
 [3] top-level scope
```


## [Inner Constructor Methods](#man-inner-constructor-methods)
If the type were declared `mutable`, you could reach in and directly change the field values to violate this invariant. Of course, messing around with an object's internals uninvited is bad practice. You (or someone else) can also provide additional outer constructor methods at any later point, but once a type is declared, there is no way to add more inner constructor methods. Since outer constructor methods can only create objects by calling other constructor methods, ultimately, some inner constructor must be called to create an object. This guarantees that all objects of the declared type must come into existence by a call to one of the inner constructor methods provided with the type, thereby giving some degree of enforcement of a type's invariants.
If any inner constructor method is defined, no default constructor method is provided: it is presumed that you have supplied yourself with all the inner constructors you need. The default constructor is equivalent to writing your own inner constructor method that takes all of the object's fields as parameters (constrained to be of the correct type, if the corresponding field has a type), and passes them to `new`, returning the resulting object:
```julia-repl
julia> struct Foo
           bar
           baz
           Foo(bar,baz) = new(bar,baz)
       end
```


## [Inner Constructor Methods](#man-inner-constructor-methods)
This declaration has the same effect as the earlier definition of the `Foo` type without an explicit inner constructor method. The following two types are equivalent – one with a default constructor, the other with an explicit constructor:
```julia-repl
julia> struct T1
           x::Int64
       end

julia> struct T2
           x::Int64
           T2(x) = new(x)
       end

julia> T1(1)
T1(1)

julia> T2(1)
T2(1)

julia> T1(1.0)
T1(1)

julia> T2(1.0)
T2(1)
```
It is good practice to provide as few inner constructor methods as possible: only those taking all arguments explicitly and enforcing essential error checking and transformation. Additional convenience constructor methods, supplying default values or auxiliary transformations, should be provided as outer constructors that call the inner constructors to do the heavy lifting. This separation is typically quite natural.


## [Incomplete Initialization](#Incomplete-Initialization)
The final problem which has still not been addressed is construction of self-referential objects, or more generally, recursive data structures. Since the fundamental difficulty may not be immediately obvious, let us briefly explain it. Consider the following recursive type declaration:
```julia-repl
julia> mutable struct SelfReferential
           obj::SelfReferential
       end
```
This type may appear innocuous enough, until one considers how to construct an instance of it. If `a` is an instance of `SelfReferential`, then a second instance can be created by the call:
```julia-repl
julia> b = SelfReferential(a)
```
But how does one construct the first instance when no instance exists to provide as a valid value for its `obj` field? The only solution is to allow creating an incompletely initialized instance of `SelfReferential` with an unassigned `obj` field, and using that incomplete instance as a valid value for the `obj` field of another instance, such as, for example, itself.


## [Incomplete Initialization](#Incomplete-Initialization)
To allow for the creation of incompletely initialized objects, Julia allows the [`new`](../../base/base/#new) function to be called with fewer than the number of fields that the type has, returning an object with the unspecified fields uninitialized. The inner constructor method can then use the incomplete object, finishing its initialization before returning it. Here, for example, is another attempt at defining the `SelfReferential` type, this time using a zero-argument inner constructor returning instances having `obj` fields pointing to themselves:
```julia-repl
julia> mutable struct SelfReferential
           obj::SelfReferential
           SelfReferential() = (x = new(); x.obj = x)
       end
```
We can verify that this constructor works and constructs objects that are, in fact, self-referential:
```julia-repl
julia> x = SelfReferential();

julia> x === x
true

julia> x === x.obj
true

julia> x === x.obj.obj
true
```
Although it is generally a good idea to return a fully initialized object from an inner constructor, it is possible to return incompletely initialized objects:
```julia-repl
julia> mutable struct Incomplete
           data
           Incomplete() = new()
       end

julia> z = Incomplete();
```
While you are allowed to create objects with uninitialized fields, any access to an uninitialized reference is an immediate error:
```julia-repl
julia> z.data
ERROR: UndefRefError: access to undefined reference
```


## [Incomplete Initialization](#Incomplete-Initialization)
This avoids the need to continually check for `null` values. However, not all object fields are references. Julia considers some types to be "plain data", meaning all of their data is self-contained and does not reference other objects. The plain data types consist of primitive types (e.g. `Int`) and immutable structs of other plain data types (see also: [`isbits`](../../base/base/#Base.isbits), [`isbitstype`](../../base/base/#Base.isbitstype)). The initial contents of a plain data type is undefined:
```julia-repl
julia> struct HasPlain
           n::Int
           HasPlain() = new()
       end

julia> HasPlain()
HasPlain(438103441441)
```
Arrays of plain data types exhibit the same behavior.
You can pass incomplete objects to other functions from inner constructors to delegate their completion:
```julia-repl
julia> mutable struct Lazy
           data
           Lazy(v) = complete_me(new(), v)
       end
```
As with incomplete objects returned from constructors, if `complete_me` or any of its callees try to access the `data` field of the `Lazy` object before it has been initialized, an error will be thrown immediately.


## [Parametric Constructors](#Parametric-Constructors)
Parametric types add a few wrinkles to the constructor story. Recall from [Parametric Types](../types/#Parametric-Types) that, by default, instances of parametric composite types can be constructed either with explicitly given type parameters or with type parameters implied by the types of the arguments given to the constructor. Here are some examples:
```julia-repl
julia> struct Point{T<:Real}
           x::T
           y::T
       end

julia> Point(1,2) ## implicit T ##
Point{Int64}(1, 2)

julia> Point(1.0,2.5) ## implicit T ##
Point{Float64}(1.0, 2.5)

julia> Point(1,2.5) ## implicit T ##
ERROR: MethodError: no method matching Point(::Int64, ::Float64)
The type `Point` exists, but no method is defined for this combination of argument types when trying to construct it.

Closest candidates are:
  Point(::T, ::T) where T<:Real at none:2

julia> Point{Int64}(1, 2) ## explicit T ##
Point{Int64}(1, 2)

julia> Point{Int64}(1.0,2.5) ## explicit T ##
ERROR: InexactError: Int64(2.5)
Stacktrace:
[...]

julia> Point{Float64}(1.0, 2.5) ## explicit T ##
Point{Float64}(1.0, 2.5)

julia> Point{Float64}(1,2) ## explicit T ##
Point{Float64}(1.0, 2.0)
```


## [Parametric Constructors](#Parametric-Constructors)
As you can see, for constructor calls with explicit type parameters, the arguments are converted to the implied field types: `Point{Int64}(1,2)` works, but `Point{Int64}(1.0,2.5)` raises an [`InexactError`](../../base/base/#Core.InexactError) when converting `2.5` to [`Int64`](../../base/numbers/#Core.Int64). When the type is implied by the arguments to the constructor call, as in `Point(1,2)`, then the types of the arguments must agree – otherwise the `T` cannot be determined – but any pair of real arguments with matching type may be given to the generic `Point` constructor.
What's really going on here is that `Point`, `Point{Float64}` and `Point{Int64}` are all different constructor functions. In fact, `Point{T}` is a distinct constructor function for each type `T`. Without any explicitly provided inner constructors, the declaration of the composite type `Point{T<:Real}` automatically provides an inner constructor, `Point{T}`, for each possible type `T<:Real`, that behaves just like non-parametric default inner constructors do. It also provides a single general outer `Point` constructor that takes pairs of real arguments, which must be of the same type. This automatic provision of constructors is equivalent to the following explicit declaration:
```julia-repl
julia> struct Point{T<:Real}
           x::T
           y::T
           Point{T}(x,y) where {T<:Real} = new(x,y)
       end

julia> Point(x::T, y::T) where {T<:Real} = Point{T}(x,y);
```


## [Parametric Constructors](#Parametric-Constructors)
Notice that each definition looks like the form of constructor call that it handles. The call `Point{Int64}(1,2)` will invoke the definition `Point{T}(x,y)` inside the `struct` block. The outer constructor declaration, on the other hand, defines a method for the general `Point` constructor which only applies to pairs of values of the same real type. This declaration makes constructor calls without explicit type parameters, like `Point(1,2)` and `Point(1.0,2.5)`, work. Since the method declaration restricts the arguments to being of the same type, calls like `Point(1,2.5)`, with arguments of different types, result in "no method" errors.
Suppose we wanted to make the constructor call `Point(1,2.5)` work by "promoting" the integer value `1` to the floating-point value `1.0`. The simplest way to achieve this is to define the following additional outer constructor method:
```julia-repl
julia> Point(x::Int64, y::Float64) = Point(convert(Float64,x),y);
```
This method uses the [`convert`](../../base/base/#Base.convert) function to explicitly convert `x` to [`Float64`](../../base/numbers/#Core.Float64) and then delegates construction to the general constructor for the case where both arguments are [`Float64`](../../base/numbers/#Core.Float64). With this method definition what was previously a [`MethodError`](../../base/base/#Core.MethodError) now successfully creates a point of type `Point{Float64}`:
```julia-repl
julia> p = Point(1,2.5)
Point{Float64}(1.0, 2.5)

julia> typeof(p)
Point{Float64}
```


## [Parametric Constructors](#Parametric-Constructors)
However, other similar calls still don't work:
```julia-repl
julia> Point(1.5,2)
ERROR: MethodError: no method matching Point(::Float64, ::Int64)
The type `Point` exists, but no method is defined for this combination of argument types when trying to construct it.

Closest candidates are:
  Point(::T, !Matched::T) where T<:Real
   @ Main none:1
  Point(!Matched::Int64, !Matched::Float64)
   @ Main none:1

Stacktrace:
[...]
```
For a more general way to make all such calls work sensibly, see [Conversion and Promotion](../conversion-and-promotion/#conversion-and-promotion). At the risk of spoiling the suspense, we can reveal here that all it takes is the following outer method definition to make all calls to the general `Point` constructor work as one would expect:
```julia-repl
julia> Point(x::Real, y::Real) = Point(promote(x,y)...);
```
The `promote` function converts all its arguments to a common type – in this case [`Float64`](../../base/numbers/#Core.Float64). With this method definition, the `Point` constructor promotes its arguments the same way that numeric operators like [`+`](../../base/math/#Base.:+) do, and works for all kinds of real numbers:
```julia-repl
julia> Point(1.5,2)
Point{Float64}(1.5, 2.0)

julia> Point(1,1//2)
Point{Rational{Int64}}(1//1, 1//2)

julia> Point(1.0,1//2)
Point{Float64}(1.0, 0.5)
```


## [Parametric Constructors](#Parametric-Constructors)
Thus, while the implicit type parameter constructors provided by default in Julia are fairly strict, it is possible to make them behave in a more relaxed but sensible manner quite easily. Moreover, since constructors can leverage all of the power of the type system, methods, and multiple dispatch, defining sophisticated behavior is typically quite simple.


## [Case Study: Rational](#Case-Study:-Rational)
Perhaps the best way to tie all these pieces together is to present a real world example of a parametric composite type and its constructor methods. To that end, we implement our own rational number type `OurRational`, similar to Julia's built-in [`Rational`](../../base/numbers/#Base.Rational) type, defined in [`rational.jl`](https://github.com/JuliaLang/julia/blob/master/base/rational.jl):
```julia-repl
julia> struct OurRational{T<:Integer} <: Real
           num::T
           den::T
           function OurRational{T}(num::T, den::T) where T<:Integer
               if num == 0 && den == 0
                    error("invalid rational: 0//0")
               end
               num = flipsign(num, den)
               den = flipsign(den, den)
               g = gcd(num, den)
               num = div(num, g)
               den = div(den, g)
               new(num, den)
           end
       end

julia> OurRational(n::T, d::T) where {T<:Integer} = OurRational{T}(n,d)
OurRational

julia> OurRational(n::Integer, d::Integer) = OurRational(promote(n,d)...)
OurRational

julia> OurRational(n::Integer) = OurRational(n,one(n))
OurRational

julia> ⊘(n::Integer, d::Integer) = OurRational(n,d)
⊘ (generic function with 1 method)

julia> ⊘(x::OurRational, y::Integer) = x.num ⊘ (x.den*y)
⊘ (generic function with 2 methods)

julia> ⊘(x::Integer, y::OurRational) = (x*y.den) ⊘ y.num
⊘ (generic function with 3 methods)

julia> ⊘(x::Complex, y::Real) = complex(real(x) ⊘ y, imag(x) ⊘ y)
⊘ (generic function with 4 methods)

julia> ⊘(x::Real, y::Complex) = (x*y') ⊘ real(y*y')
⊘ (generic function with 5 methods)

julia> function ⊘(x::Complex, y::Complex)
           xy = x*y'
           yy = real(y*y')
           complex(real(xy) ⊘ yy, imag(xy) ⊘ yy)
       end
⊘ (generic function with 6 methods)
```


## [Case Study: Rational](#Case-Study:-Rational)
The first line – `struct OurRational{T<:Integer} <: Real` – declares that `OurRational` takes one type parameter of an integer type, and is itself a real type. The field declarations `num::T` and `den::T` indicate that the data held in a `OurRational{T}` object are a pair of integers of type `T`, one representing the rational value's numerator and the other representing its denominator.
Now things get interesting. `OurRational` has a single inner constructor method which checks that `num` and `den` aren't both zero and ensures that every rational is constructed in "lowest terms" with a non-negative denominator. This is accomplished by first flipping the signs of numerator and denominator if the denominator is negative. Then, both are divided by their greatest common divisor (`gcd` always returns a non-negative number, regardless of the sign of its arguments). Because this is the only inner constructor for `OurRational`, we can be certain that `OurRational` objects are always constructed in this normalized form.


## [Case Study: Rational](#Case-Study:-Rational)
`OurRational` also provides several outer constructor methods for convenience. The first is the "standard" general constructor that infers the type parameter `T` from the type of the numerator and denominator when they have the same type. The second applies when the given numerator and denominator values have different types: it promotes them to a common type and then delegates construction to the outer constructor for arguments of matching type. The third outer constructor turns integer values into rationals by supplying a value of `1` as the denominator.


## [Case Study: Rational](#Case-Study:-Rational)
Following the outer constructor definitions, we defined a number of methods for the `⊘` operator, which provides a syntax for writing rationals (e.g. `1 ⊘ 2`). Julia's `Rational` type uses the [`//`](../../base/math/#Base.://) operator for this purpose. Before these definitions, `⊘` is a completely undefined operator with only syntax and no meaning. Afterwards, it behaves just as described in [Rational Numbers](../complex-and-rational-numbers/#Rational-Numbers) – its entire behavior is defined in these few lines. Note that the infix use of `⊘` works because Julia has a set of symbols that are recognized to be infix operators. The first and most basic definition just makes `a ⊘ b` construct a `OurRational` by applying the `OurRational` constructor to `a` and `b` when they are integers. When one of the operands of `⊘` is already a rational number, we construct a new rational for the resulting ratio slightly differently; this behavior is actually identical to division of a rational with an integer. Finally, applying `⊘` to complex integral values creates an instance of `Complex{<:OurRational}` – a complex number whose real and imaginary parts are rationals:
```julia-repl
julia> z = (1 + 2im) ⊘ (1 - 2im);

julia> typeof(z)
Complex{OurRational{Int64}}

julia> typeof(z) <: Complex{<:OurRational}
true
```


## [Case Study: Rational](#Case-Study:-Rational)
Thus, although the `⊘` operator usually returns an instance of `OurRational`, if either of its arguments are complex integers, it will return an instance of `Complex{<:OurRational}` instead. The interested reader should consider perusing the rest of [`rational.jl`](https://github.com/JuliaLang/julia/blob/master/base/rational.jl): it is short, self-contained, and implements an entire basic Julia type.


## [Outer-only constructors](#Outer-only-constructors)
As we have seen, a typical parametric type has inner constructors that are called when type parameters are known; e.g. they apply to `Point{Int}` but not to `Point`. Optionally, outer constructors that determine type parameters automatically can be added, for example constructing a `Point{Int}` from the call `Point(1,2)`. Outer constructors call inner constructors to actually make instances. However, in some cases one would rather not provide inner constructors, so that specific type parameters cannot be requested manually.
For example, say we define a type that stores a vector along with an accurate representation of its sum:
```julia-repl
julia> struct SummedArray{T<:Number,S<:Number}
           data::Vector{T}
           sum::S
       end

julia> SummedArray(Int32[1; 2; 3], Int32(6))
SummedArray{Int32, Int32}(Int32[1, 2, 3], 6)
```
The problem is that we want `S` to be a larger type than `T`, so that we can sum many elements with less information loss. For example, when `T` is [`Int32`](../../base/numbers/#Core.Int32), we would like `S` to be [`Int64`](../../base/numbers/#Core.Int64). Therefore we want to avoid an interface that allows the user to construct instances of the type `SummedArray{Int32,Int32}`. One way to do this is to provide a constructor only for `SummedArray`, but inside the `struct` definition block to suppress generation of default constructors:


## [Outer-only constructors](#Outer-only-constructors)
```julia-repl
julia> struct SummedArray{T<:Number,S<:Number}
           data::Vector{T}
           sum::S
           function SummedArray(a::Vector{T}) where T
               S = widen(T)
               new{T,S}(a, sum(S, a))
           end
       end

julia> SummedArray(Int32[1; 2; 3], Int32(6))
ERROR: MethodError: no method matching SummedArray(::Vector{Int32}, ::Int32)
The type `SummedArray` exists, but no method is defined for this combination of argument types when trying to construct it.

Closest candidates are:
  SummedArray(::Vector{T}) where T
   @ Main none:4

Stacktrace:
[...]
```
This constructor will be invoked by the syntax `SummedArray(a)`. The syntax `new{T,S}` allows specifying parameters for the type to be constructed, i.e. this call will return a `SummedArray{T,S}`. `new{T,S}` can be used in any constructor definition, but for convenience the parameters to `new{}` are automatically derived from the type being constructed when possible.


## [Constructors are just callable objects](#Constructors-are-just-callable-objects)
An object of any type may be [made callable](../methods/#Function-like-objects) by defining a method. This includes types, i.e., objects of type [`Type`](../../base/base/#Core.Type); and constructors may, in fact, be viewed as just callable type objects. For example, there are many methods defined on `Bool` and various supertypes of it:
```julia-repl
julia> methods(Bool)
# 10 methods for type constructor:
  [1] Bool(x::BigFloat)
     @ Base.MPFR mpfr.jl:393
  [2] Bool(x::Float16)
     @ Base float.jl:338
  [3] Bool(x::Rational)
     @ Base rational.jl:138
  [4] Bool(x::Real)
     @ Base float.jl:233
  [5] (dt::Type{<:Integer})(ip::Sockets.IPAddr)
     @ Sockets ~/tmp/jl/jl/julia-nightly-assert/share/julia/stdlib/v1.11/Sockets/src/IPAddr.jl:11
  [6] (::Type{T})(x::Enum{T2}) where {T<:Integer, T2<:Integer}
     @ Base.Enums Enums.jl:19
  [7] (::Type{T})(z::Complex) where T<:Real
     @ Base complex.jl:44
  [8] (::Type{T})(x::Base.TwicePrecision) where T<:Number
     @ Base twiceprecision.jl:265
  [9] (::Type{T})(x::T) where T<:Number
     @ boot.jl:894
 [10] (::Type{T})(x::AbstractChar) where T<:Union{AbstractChar, Number}
     @ char.jl:50
```
The usual constructor syntax is exactly equivalent to the function-like object syntax, so trying to define a method with each syntax will cause the first method to be overwritten by the next one:


## [Constructors are just callable objects](#Constructors-are-just-callable-objects)
```julia-repl
julia> struct S
           f::Int
       end

julia> S() = S(7)
S

julia> (::Type{S})() = S(8)  # overwrites the previous constructor method

julia> S()
S(8)
```
-   [1](#citeref-1)Nomenclature: while the term "constructor" generally refers to the entire function which constructs objects of a type, it is common to abuse terminology slightly and refer to specific constructor methods as "constructors". In such situations, it is generally clear from the context that the term 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.
------------------------------------------------------------------------


# Conversion and Promotion · The Julia Language
Source: https://docs.julialang.org/en/v1/manual/conversion-and-promotion/


# [Conversion and Promotion](#conversion-and-promotion)
Julia has a system for promoting arguments of mathematical operators to a common type, which has been mentioned in various other sections, including [Integers and Floating-Point Numbers](../integers-and-floating-point-numbers/#Integers-and-Floating-Point-Numbers), [Mathematical Operations and Elementary Functions](../mathematical-operations/#Mathematical-Operations-and-Elementary-Functions), [Types](../types/#man-types), and [Methods](../methods/#Methods). In this section, we explain how this promotion system works, as well as how to extend it to new types and apply it to functions besides built-in mathematical operators. Traditionally, programming languages fall into two camps with respect to promotion of arithmetic arguments:


# [Conversion and Promotion](#conversion-and-promotion)
-   **Automatic promotion for built-in arithmetic types and operators.** In most languages, built-in numeric types, when used as operands to arithmetic operators with infix syntax, such as `+`, `-`, `*`, and `/`, are automatically promoted to a common type to produce the expected results. C, Java, Perl, and Python, to name a few, all correctly compute the sum `1 + 1.5` as the floating-point value `2.5`, even though one of the operands to `+` is an integer. These systems are convenient and designed carefully enough that they are generally all-but-invisible to the programmer: hardly anyone consciously thinks of this promotion taking place when writing such an expression, but compilers and interpreters must perform conversion before addition since integers and floating-point values cannot be added as-is. Complex rules for such automatic conversions are thus inevitably part of specifications and implementations for such languages.


# [Conversion and Promotion](#conversion-and-promotion)
-   **No automatic promotion.** This camp includes Ada and ML – very "strict" statically typed languages. In these languages, every conversion must be explicitly specified by the programmer. Thus, the example expression `1 + 1.5` would be a compilation error in both Ada and ML. Instead one must write `real(1) + 1.5`, explicitly converting the integer `1` to a floating-point value before performing addition. Explicit conversion everywhere is so inconvenient, however, that even Ada has some degree of automatic conversion: integer literals are promoted to the expected integer type automatically, and floating-point literals are similarly promoted to appropriate floating-point types.


# [Conversion and Promotion](#conversion-and-promotion)
In a sense, Julia falls into the "no automatic promotion" category: mathematical operators are just functions with special syntax, and the arguments of functions are never automatically converted. However, one may observe that applying mathematical operations to a wide variety of mixed argument types is just an extreme case of polymorphic multiple dispatch – something which Julia's dispatch and type systems are particularly well-suited to handle. "Automatic" promotion of mathematical operands simply emerges as a special application: Julia comes with pre-defined catch-all dispatch rules for mathematical operators, invoked when no specific implementation exists for some combination of operand types. These catch-all rules first promote all operands to a common type using user-definable promotion rules, and then invoke a specialized implementation of the operator in question for the resulting values, now of the same type. User-defined types can easily participate in this promotion system by defining methods for conversion to and from other types, and providing a handful of promotion rules defining what types they should promote to when mixed with other types.


## [Conversion](#Conversion)
The standard way to obtain a value of a certain type `T` is to call the type's constructor, `T(x)`. However, there are cases where it's convenient to convert a value from one type to another without the programmer asking for it explicitly. One example is assigning a value into an array: if `A` is a `Vector{Float64}`, the expression `A[1] = 2` should work by automatically converting the `2` from `Int` to `Float64`, and storing the result in the array. This is done via the [`convert`](../../base/base/#Base.convert) function.
The `convert` function generally takes two arguments: the first is a type object and the second is a value to convert to that type. The returned value is the value converted to an instance of given type. The simplest way to understand this function is to see it in action:
```julia-repl
julia> x = 12
12

julia> typeof(x)
Int64

julia> xu = convert(UInt8, x)
0x0c

julia> typeof(xu)
UInt8

julia> xf = convert(AbstractFloat, x)
12.0

julia> typeof(xf)
Float64

julia> a = Any[1 2 3; 4 5 6]
2×3 Matrix{Any}:
 1  2  3
 4  5  6

julia> convert(Array{Float64}, a)
2×3 Matrix{Float64}:
 1.0  2.0  3.0
 4.0  5.0  6.0
```
Conversion isn't always possible, in which case a [`MethodError`](../../base/base/#Core.MethodError) is thrown indicating that `convert` doesn't know how to perform the requested conversion:
```julia-repl
julia> convert(AbstractFloat, "foo")
ERROR: MethodError: Cannot `convert` an object of type String to an object of type AbstractFloat
[...]
```


## [Conversion](#Conversion)
Some languages consider parsing strings as numbers or formatting numbers as strings to be conversions (many dynamic languages will even perform conversion for you automatically). This is not the case in Julia. Even though some strings can be parsed as numbers, most strings are not valid representations of numbers, and only a very limited subset of them are. Therefore in Julia the dedicated [`parse`](../../base/numbers/#Base.parse) function must be used to perform this operation, making it more explicit.


### [When is convert called?](#When-is-convert-called?)
The following language constructs call `convert`:
-   Assigning to an array converts to the array's element type.
-   Assigning to a field of an object converts to the declared type of the field.
-   Constructing an object with [`new`](../../base/base/#new) converts to the object's declared field types.
-   Assigning to a variable with a declared type (e.g. `local x::T`) converts to that type.
-   A function with a declared return type converts its return value to that type.
-   Passing a value to [`ccall`](../../base/c/#ccall) converts it to the corresponding argument type.


### [Conversion vs. Construction](#Conversion-vs.-Construction)
Note that the behavior of `convert(T, x)` appears to be nearly identical to `T(x)`. Indeed, it usually is. However, there is a key semantic difference: since `convert` can be called implicitly, its methods are restricted to cases that are considered "safe" or "unsurprising". `convert` will only convert between types that represent the same basic kind of thing (e.g. different representations of numbers, or different string encodings). It is also usually lossless; converting a value to a different type and back again should result in the exact same value.
There are four general kinds of cases where constructors differ from `convert`:


#### [Constructors for types unrelated to their arguments](#Constructors-for-types-unrelated-to-their-arguments)
Some constructors don't implement the concept of "conversion". For example, `Timer(2)` creates a 2-second timer, which is not really a "conversion" from an integer to a timer.


#### [Mutable collections](#Mutable-collections)
`convert(T, x)` is expected to return the original `x` if `x` is already of type `T`. In contrast, if `T` is a mutable collection type then `T(x)` should always make a new collection (copying elements from `x`).


#### [Wrapper types](#Wrapper-types)
For some types which "wrap" other values, the constructor may wrap its argument inside a new object even if it is already of the requested type. For example `Some(x)` wraps `x` to indicate that a value is present (in a context where the result might be a `Some` or `nothing`). However, `x` itself might be the object `Some(y)`, in which case the result is `Some(Some(y))`, with two levels of wrapping. `convert(Some, x)`, on the other hand, would just return `x` since it is already a `Some`.


#### [Constructors that don't return instances of their own type](#Constructors-that-don't-return-instances-of-their-own-type)
In *very rare* cases it might make sense for the constructor `T(x)` to return an object not of type `T`. This could happen if a wrapper type is its own inverse (e.g. `Flip(Flip(x)) === x`), or to support an old calling syntax for backwards compatibility when a library is restructured. But `convert(T, x)` should always return a value of type `T`.


### [Defining New Conversions](#Defining-New-Conversions)
When defining a new type, initially all ways of creating it should be defined as constructors. If it becomes clear that implicit conversion would be useful, and that some constructors meet the above "safety" criteria, then `convert` methods can be added. These methods are typically quite simple, as they only need to call the appropriate constructor. Such a definition might look like this:
```julia
import Base: convert
convert(::Type{MyType}, x) = MyType(x)
```
The type of the first argument of this method is [`Type{MyType}`](../types/#man-typet-type), the only instance of which is `MyType`. Thus, this method is only invoked when the first argument is the type value `MyType`. Notice the syntax used for the first argument: the argument name is omitted prior to the `::` symbol, and only the type is given. This is the syntax in Julia for a function argument whose type is specified but whose value does not need to be referenced by name.
All instances of some abstract types are by default considered "sufficiently similar" that a universal `convert` definition is provided in Julia Base. For example, this definition states that it's valid to `convert` any `Number` type to any other by calling a 1-argument constructor:
```julia
convert(::Type{T}, x::Number) where {T<:Number} = T(x)::T
```
This means that new `Number` types only need to define constructors, since this definition will handle `convert` for them. An identity conversion is also provided to handle the case where the argument is already of the requested type:


### [Defining New Conversions](#Defining-New-Conversions)
```julia
convert(::Type{T}, x::T) where {T<:Number} = x
```
Similar definitions exist for `AbstractString`, [`AbstractArray`](../../base/arrays/#Core.AbstractArray), and [`AbstractDict`](../../base/collections/#Base.AbstractDict).


## [Promotion](#Promotion)
Promotion refers to converting values of mixed types to a single common type. Although it is not strictly necessary, it is generally implied that the common type to which the values are converted can faithfully represent all of the original values. In this sense, the term "promotion" is appropriate since the values are converted to a "greater" type – i.e. one which can represent all of the input values in a single common type. It is important, however, not to confuse this with object-oriented (structural) super-typing, or Julia's notion of abstract super-types: promotion has nothing to do with the type hierarchy, and everything to do with converting between alternate representations. For instance, although every [`Int32`](../../base/numbers/#Core.Int32) value can also be represented as a [`Float64`](../../base/numbers/#Core.Float64) value, `Int32` is not a subtype of `Float64`.
Promotion to a common "greater" type is performed in Julia by the [`promote`](../../base/base/#Base.promote) function, which takes any number of arguments, and returns a tuple of the same number of values, converted to a common type, or throws an exception if promotion is not possible. The most common use case for promotion is to convert numeric arguments to a common type:
```julia-repl
julia> promote(1, 2.5)
(1.0, 2.5)

julia> promote(1, 2.5, 3)
(1.0, 2.5, 3.0)

julia> promote(2, 3//4)
(2//1, 3//4)

julia> promote(1, 2.5, 3, 3//4)
(1.0, 2.5, 3.0, 0.75)

julia> promote(1.5, im)
(1.5 + 0.0im, 0.0 + 1.0im)

julia> promote(1 + 2im, 3//4)
(1//1 + 2//1*im, 3//4 + 0//1*im)
```