# Convert() vs constructors

**URL:** <https://discourse.julialang.org/t/convert-vs-constructors/4159>\
**Category:** General Usage\
**Tags:** convert, constructors\
**Created:** [June 8, 2017, 2:26am UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159 "2017-06-08T02:26:54Z")\
**Posts on this page:** 16\
**Page:** 2

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 8, 2017, 7:53pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/21 "2017-06-08T19:53:02Z")

</div>

> [@mohamed82008](#):
>
> A special of case is when the type T has one field only, yet convert(T, a) does not call T(a)

convert never call constructors by default, types with one field is no exception. The special case about such type is that their constructor won’t call `convert` by default.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 8, 2017, 7:57pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/22 "2017-06-08T19:57:32Z")

</div>

> [@stevengj](#):
>
> See [https://docs.julialang.org/en/latest/manual/constructors/#constructors-and-conversion-1](https://docs.julialang.org/en/latest/manual/constructors/#constructors-and-conversion-1)

I checked the documentation in the link and it said the following:

> However, in some cases you could consider adding methods to Base.convert instead of defining a constructor, because Julia falls back to calling convert() if no matching constructor is found. For example, if no constructor T(args…) = … exists Base.convert(::Type{T}, args…) = … is called.

Then I tested the following but it seems inconsistent.

```julia
julia> type T
           a
           b
       end

julia> convert(::Type{T}, args::Int...) = T(args[1], args[2])
convert (generic function with 599 methods)

julia> T(1,2,3,4)
ERROR: MethodError: no method matching T(::Int64, ::Int64, ::Int64, ::Int64)
Closest candidates are:
  T(::Any, ::Any) at REPL[52]:2
  T{T}(::Any) at sysimg.jl:53

```

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 8, 2017, 8:04pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/23 "2017-06-08T20:04:41Z")

</div>

That doc is out of date. Don’t define multiple argument `convert`. It doesn’t make any sense.

---

<div class="post-metadata">

**Author:** ![gdkrmr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdkrmr/32/2791_2.png) [@gdkrmr](https://discourse.julialang.org/u/gdkrmr)\
**Post date:** [June 9, 2017, 10:01am UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/24 "2017-06-09T10:01:48Z")

</div>

I find this thread more confusing than helpful, may I summarize, please correct me if I am wrong:

- Constructors and convert can be defined independently of each other.
- Constructor calls with a single argument will fall back to convert if they are not defined.
- In contrast to constructors (see [https://docs.julialang.org/en/stable/manual/constructors/](https://docs.julialang.org/en/stable/manual/constructors/)), methods for `convert` are never defined automatically.
- For most basic types like e.g. `Float64` constructors fall back to convert and therefore `T(x)` are identical `convert(T, x)`.
- If I assign a `T2` into a field/slot of type `T1`, e.g. object fields, array elements, typed local variables, return type annotation, conversion happens automatically by calling `convert` and I do not have to specify it, e.g

```julia
x = zeros(Float64, 5)
y = one(Float32)
x[1] = y
@assert eltype(x) == Float64

```

The last point was what confused me, because @yuyichao said that constructors are always explicit, therefore I wondered if `T(x)` and `convert(T, x)` were no-ops for `x::T`.

update: corrections  
update: added assignment bullet  
update: clarified the assignment conversion bullet  
update: expanded assignment into typed fields etc.  
update: clarification: no automatic definition of constructors

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 9, 2017, 10:13am UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/25 "2017-06-09T10:13:46Z")

</div>

> [@gdkrmr](#):
>
> Constructors will fall back to convert if they are not defined.

Correction: “Constructor calls **with a single argument** will fall back to convert if they are not defined either implicitly or explicitly. A constructor with a single argument is defined implicitly for types with a single field. If the type T has multiple fields, then calling T(x), when no constructor T(x) has been explicitly defined, is like asking Julia to convert x to type T, which falls back to convert(T, x). In cases like this, you must define `convert(::Type{T}, x)`.”

I am not sure how basic types are defined exactly, or how many fields they actually have. But they should follow the same line of thought explained above, if all is to be consistent, which I suppose it is.

---

<div class="post-metadata">

**Author:** ![mohamed82008](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mohamed82008/32/18171_2.png) [@mohamed82008](https://discourse.julialang.org/u/mohamed82008)\
**Post date:** [June 9, 2017, 11:16am UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/26 "2017-06-09T11:16:58Z")

</div>

> [@gdkrmr](#):
>
> If I assign a T2 into an Array{T1} conversion happens automatically and I do not have to specify it, e.g x = zeros(Float64, 5); y = one(Float32); x[1] = y; @assert eltype(x) == Float64.

I thought this was worth clarifying further. I can see this happening for basic types “intuitively”, but for general user defined types (including basic types as well), I believe convert(T1, y) is called behind the scenes, here is my evidence code.

```julia
julia> type T1
           a
       end

julia> type T2
           a
       end

julia> b = T1[T1(1), T1(2), T1(3)]
3-element Array{T1,1}:
 T1(1)
 T1(2)
 T1(3)

julia> b[1] = T2(1)
ERROR: MethodError: Cannot `convert` an object of type T2 to an object of type T1
This may have arisen from a call to the constructor T1(...), since type constructors fall back to convert methods.
 in setindex!(::Array{T1,1}, ::T2, ::Int64) at .\array.jl:415

julia> b = Int[1,2,3]
3-element Array{Int64,1}:
 1
 2
 3

julia> b[1] = "S"
ERROR: MethodError: Cannot `convert` an object of type String to an object of type Int64
This may have arisen from a call to the constructor Int64(...), since type constructors fall back to convert methods.
 in setindex!(::Array{Int64,1}, ::String, ::Int64) at .\array.jl:415

```

---

<div class="post-metadata">

**Author:** ![gdkrmr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdkrmr/32/2791_2.png) [@gdkrmr](https://discourse.julialang.org/u/gdkrmr)\
**Post date:** [June 9, 2017, 12:26pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/27 "2017-06-09T12:26:05Z")

</div>

yes, with “conversion happens automatically” I meant a call to `convert`.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 9, 2017, 12:51pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/28 "2017-06-09T12:51:44Z")

</div>

> [@gdkrmr](#):
>
> If convert is not defined, it will fail with an error.

Well, true but unrelated… Anything will fail with an error if it’s not defined…

> [@gdkrmr](#):
>
> For most basic types like e.g. Float64 constructors fall back to convert and therefore T(x) are identical convert(T, x).

There’s nothing special about basic types. There’s just a catch-all single argument constructor as fallback unless overwritten.

> [@gdkrmr](#):
>
> If I assign a T2 into an Array{T1} conversion happens automatically, by calling convert, and I do not have to specify it,

This is not specific to `Array` but any typed field/slots. This includes object fields, `Array` element, typed local variable, return type annotation.

> [@gdkrmr](#):
>
> constructors are always explicit

I mean constructor calls are always explicit. Julia won’t automatically insert it anywhere so you can use it to do “convertion”(“construction”) that’s less intuitive.

> [@gdkrmr](#):
>
> if T(x) and convert(T, x) were no-ops for x::T

I don’t see how this is related to explicit vs implicit but both are true unless overwritten.

---

<div class="post-metadata">

**Author:** ![gdkrmr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdkrmr/32/2791_2.png) [@gdkrmr](https://discourse.julialang.org/u/gdkrmr)\
**Post date:** [June 9, 2017, 1:00pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/29 "2017-06-09T13:00:55Z")

</div>

> [@yuyichao](#):
>
> > [@gdkrmr](#):
> >
> > If convert is not defined, it will fail with an error.
> 
> Well, true but unrelated… Anything will fail with an error if it’s not defined…

Some type constructors are automatically defined.

> [@yuyichao](#):
>
> > [@gdkrmr](#):
> >
> > if T(x) and convert(T, x) were no-ops for x::T
> 
> I don’t see how this is related to explicit vs implicit but both are true unless overwritten.

Thanks, for clarifying that.

I updated my post above.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 9, 2017, 1:15pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/30 "2017-06-09T13:15:49Z")

</div>

> [@gdkrmr](#):
>
> are automatically defined

so it is still “defined”… It’s just not explicitly defined by the user.  
It’s also pretty confusing to say it this way. Maybe you mean convert are never automatically defined.

---

<div class="post-metadata">

**Author:** ![gdkrmr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdkrmr/32/2791_2.png) [@gdkrmr](https://discourse.julialang.org/u/gdkrmr)\
**Post date:** [June 9, 2017, 1:18pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/31 "2017-06-09T13:18:32Z")

</div>

if you come up with a better way to express it, I will edit my post.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [June 9, 2017, 1:19pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/32 "2017-06-09T13:19:07Z")

</div>

> [@gdkrmr](#):
>
> if you come up with a better way to express it, I will edit my post.

> [@yuyichao](#):
>
> convert are never automatically defined.

…

---

<div class="post-metadata">

**Author:** ![gdkrmr](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdkrmr/32/2791_2.png) [@gdkrmr](https://discourse.julialang.org/u/gdkrmr)\
**Post date:** [July 26, 2017, 8:18am UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/33 "2017-07-26T08:18:52Z")

</div>

Following up on this:

```julia
function conv_float(x)
    @time Array{Float64}(x) #no-op
    @time convert(Array{Float64}, x) #no-op
    @time Float64.(x) #converts and makes copy
    @time x .= Float64.(x) #converts without copy, no-op in Julia 0.6
end

```

gives me the following timings in 0.5.2:

```julia
julia> conv_float(randn(1000000));
  0.000000 seconds
  0.000000 seconds
  0.001493 seconds (3 allocations: 7.629 MB)
  0.000854 seconds (1 allocation: 16 bytes)

```

and in 0.6:

```julia
julia> conv_float(randn(1000000));
  0.000000 seconds
  0.000000 seconds
  0.001451 seconds (2 allocations: 7.629 MiB)
  0.000000 seconds

```

So in 0.6 broadcast can optimize the last line to a no-op.

---

<div class="post-metadata">

**Author:** ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)\
**Post date:** [August 28, 2017, 4:31pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/34 "2017-08-28T16:31:53Z")

</div>

I seem to understand the theory, but what is the practical advise that follows from it? As a designer of a new type T, what method(s) should I implement to ensure interoperability with say integers - `T(x::Integer)` or `Base.convert(::Type{T}, x::Integer)`? As a user of such type, when should I call `T(x)` and when `convert(Integer, x)`?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [August 28, 2017, 7:13pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/35 "2017-08-28T19:13:51Z")

</div>

If you want `T(x)` and `convert(T, x)` to both work, and you have no other single-argument constructor, then just defining `convert(::Type{T}, x::Integer)` is all you need to do. But there’s also a semantic choice that you can make when you decide which method to implement. When you define `convert()` for your type, you are implying that that conversion makes logical sense.

For example, you might have a new numeric type `Foo` that holds an integer:

```julia
struct Foo <: Number
  x::Int 
end

```

and you might want to define `convert(::Type{Foo}, y::Integer) = Foo(y)` since converting an integer to a Foo makes some logical sense.

But you might also have a type `Bar` that holds some data, whose constructor tells it how much data to hold:

```julia
struct Bar
  x::Vector{Float64}
end

Bar(y::Integer) = Bar(zeros(y))

```

I would argue that for `Foo` having the conversion makes sense if `Foo` is going to behave somehow like the original number (for example, tracking derivatives or something). But even though you can call `Bar(5)`, that’s not really a conversion from `5` to `Bar`, since the `Bar` type doesn’t behave anything like the number 5. So I would argue that it does _not_ make sense to define `convert(::Type{Bar}, y::Integer)`.

Another way to think about it is: if I have a vector `v` of `T`s, does it make sense to say: `push!(v, 5)`? By default, `push!()` will automatically call `convert(T, 5)`. I would argue that for `Foo` it makes sense for `push!()` to work (and convert to Foo), but for `Bar` it does not make sense. That’s a further argument in favor of defining `convert()` for `Foo` but not for `Bar`.

tl;dr `convert()` and constructors do similar things, but they have different meanings, and you can decide which meaning is appropriate for a given type.

---

<div class="post-metadata">

**Author:** ![Alexander\_Belopolsky](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/alexander_belopolsky/32/4882_2.png) [@Alexander\_Belopolsky](https://discourse.julialang.org/u/Alexander_Belopolsky)\
**Post date:** [August 29, 2017, 5:47pm UTC](https://discourse.julialang.org/t/convert-vs-constructors/4159/36 "2017-08-29T17:47:55Z")

</div>

If I want to explicitly convert an object `foo` of type `Foo` to `Bar`, what should I do `Bar(foo)` or `convert(Bar, foo)`?

[Previous page](https://discourse.julialang.org/t/convert-vs-constructors/4159.md?page=1)
