# Recommended style for conversion vs. constructors in v0.7

**URL:** <https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561>\
**Category:** General Usage\
**Tags:** type\
**Created:** [June 9, 2018, 7:41pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561 "2018-06-09T19:41:35Z")\
**Posts on this page:** 13\
**Page:** 1

<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:** [June 9, 2018, 7:41pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/1 "2018-06-09T19:41:35Z")

</div>

I’ve been upgrading a few packages to v0.7, and one of the biggest sources of deprecations is the removal of the default constructor-\>convert fallback. For those unfamiliar, previously if you had:

```julia
struct T
  ...
end

Base.convert(::Type{T}, x::Int) = (construct a new T from an Int)

```

then you you could call `T(1)` and, if there was not constructor matching `(::Int)`, then `convert(T, 1)` would automatically be called for you. That was convenient but also kind of muddied the distinction between conversion and construction, and led to awkward error messages. So I’m reasonably happy to see it go.

But my question is, when upgrading a library that used to rely on this pattern, we have two options:

1. Move with the language: where users were previously calling `T(x)`, they should instead be calling `convert(T, x)`, unless they actually meant to call a constructor
2. Maintain the API: define the fallback constructor `T(x::Int) = convert(T, x)` ourselves.

(1) seems easy (no code changes required in the library), but somewhat unfriendly, as it’s pretty unclear to most users of a library whether the `T(x)` they’re calling is a “real” constructor or a fallback.

Do you all have any recommendations? What’s the new thought process on when something should be a constructor or a convert method? And, likewise, what’s the thinking on when a user should be trying to construct vs. trying to convert?

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [June 9, 2018, 8:14pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/2 "2018-06-09T20:14:34Z")

</div>

I think the idea is that you should define the constructor manually. The difference between `convert` and constructors is that the former will avoid copying as much as possible, while the latter are guaranteed to return new objects which do not alias with the original object.

In many cases you can just define constructors in terms of `convert` or vice-versa, sometimes with a call to `copy` or `deepcopy`.

---

<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:** [June 9, 2018, 8:56pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/3 "2018-06-09T20:56:49Z")

</div>

So in a situation like [https://github.com/JuliaMath/FixedPointNumbers.jl/blob/cf9ebc49d5eaef7e1d8a348762e9a820b6885f3c/src/fixed.jl#L46-L72](https://github.com/JuliaMath/FixedPointNumbers.jl/blob/cf9ebc49d5eaef7e1d8a348762e9a820b6885f3c/src/fixed.jl#L46-L72)

would you suggest changing those `convert()` methods to constructors (since these are all bitstypes anyway) and then defining:

```julia
convert(::Type{T}, f::Fixed) where {T <: Number} = T(f)

```

?

---

<div class="post-metadata">

**Author:** ![JeffreySarnoff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeffreysarnoff/32/1980_2.png) [@JeffreySarnoff](https://discourse.julialang.org/u/JeffreySarnoff)\
**Post date:** [June 9, 2018, 10:24pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/4 "2018-06-09T22:24:08Z")

</div>

That is how I have been moving software into v0.7. After a while, the “niceness” of this comes through more clearly. The new conceptual separation puts the declarative (what linguists find “imperative”) at our fingertips and lets us specialize in situations where the interest is to enact conversion of one manner of expression into another [or not].

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [June 10, 2018, 11:21pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/5 "2018-06-10T23:21:19Z")

</div>

Yes, you should make them constructors. In the case of Number types, `convert` definitions are not usually necessary since this method exists:

```julia
convert(::Type{T}, x::Number) where {T<:Number} = T(x)

```

Constructors are considered the lowest-level way to make an instance of something, so all new types should have them. Then `convert` definitions are inherited or added on top as needed.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [June 11, 2018, 12:10am UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/6 "2018-06-11T00:10:47Z")

</div>

Is there a convention for what `T(x::T)` should do for non-isbits types? Should it make a deep copy or a shallow one, or even just return `x`? I know there was some discussion on this subject at some point, but I missed the conclusion if there was one.

> [@nalimilan](#):
>
> The difference between `convert` and constructors is that the former will avoid copying as much as possible, while the latter are guaranteed to return new objects which do not alias with the original object.

I suppose this would answer my question, but I wasn’t aware of such a guarantee.

---

<div class="post-metadata">

**Author:** ![nalimilan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nalimilan/32/147_2.png) [@nalimilan](https://discourse.julialang.org/u/nalimilan)\
**Post date:** [June 11, 2018, 8:11am UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/7 "2018-06-11T08:11:11Z")

</div>

> [@tkoolen](#):
>
> Is there a convention for what `T(x::T)` should do for non-isbits types? Should it make a deep copy or a shallow one, or even just return `x` ? I know there was some discussion on this subject at some point, but I missed the conclusion if there was one.

It should definitely make a copy, else you couldn’t modify the result safely without checking the type of the input first.

As for whether it should be a shallow or a deep copy, I’m not completely sure. FWIW, the `DataFrame` constructor doesn’t make a copy of column vectors when passed a `DataFrame`, as its doesn’t make a copy of vectors when called e.g. as `DataFrame(x=some_vector)`. But maybe for other types it makes more sense to make a deep copy.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 11, 2018, 8:57am UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/8 "2018-06-11T08:57:33Z")

</div>

> [@tkoolen](#):
>
> Is there a convention for what `T(x::T)` should do for non-isbits types? Should it make a deep copy or a shallow one, or even just return `x` ?

It should make a new object, so that

```julia
(T(x::T) ≡ x) == false

```

but I guess that conventions about sharing structure are up to the programmer.

Most of the time I use the following style:

1. never modify something unless you own it, use a functional approach,
2. unless you are sure you own something, make a `copy` / `deepcopy`, and modify that,
3. only do 2. when it is worth it (in terms of speed).

but I recognize that there are other viable approaches and interfacing them can be tricky.

---

<div class="post-metadata">

**Author:** ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)\
**Post date:** [June 11, 2018, 11:52am UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/9 "2018-06-11T11:52:20Z")

</div>

That seems reasonable.

Note that the behavior of, for example, `Vector` has changed (IMO, for the better) to match this in 0.7:

```julia
a = rand(3); b = Vector(a); a === b

```

returns true on 0.6, false on 0.7.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [June 11, 2018, 11:55am UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/10 "2018-06-11T11:55:40Z")

</div>

I assume that this is somehow implicit in the [documentation](https://docs.julialang.org/en/latest/manual/constructors/#man-constructors-1), which says that

> Constructors are functions that create new objects

but perhaps some clarification or emphasis would be useful.

In general, reasoning about shared structure can become difficult very quickly, which is why I ideally avoid it, or try to confine it when necessary.

---

<div class="post-metadata">

**Author:** ![jeff.bezanson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jeff.bezanson/32/48_2.png) [@jeff.bezanson](https://discourse.julialang.org/u/jeff.bezanson)\
**Post date:** [June 11, 2018, 4:40pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/11 "2018-06-11T16:40:43Z")

</div>

For mutable objects, a constructor should make a shallow copy. However, the definition of “shallow” depends on the semantics of the object. It should copy any structure that belongs to one instance. For example, if a DataFrame is considered a collection of columns, then the columns should not be copied, just the container holding them. But if a DataFrame is considered to be a collection of all the data inside it, then the columns should be copied as well. This also relates to the set of available operations. For example if a DataFrame has a function that inserts a row by mutation, then the DataFrame “manages” the columns and `copy` and the constructor should copy them. As always, there might be borderline cases that require judgment calls.

---

<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:** [June 11, 2018, 6:22pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/12 "2018-06-11T18:22:58Z")

</div>

Thanks! This is extremely helpful to have written out clearly.

---

<div class="post-metadata">

**Author:** ![ScottPJones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/scottpjones/32/146_2.png) [@ScottPJones](https://discourse.julialang.org/u/ScottPJones)\
**Post date:** [June 11, 2018, 6:38pm UTC](https://discourse.julialang.org/t/recommended-style-for-conversion-vs-constructors-in-v0-7/11561/13 "2018-06-11T18:38:48Z")

</div>

What about immutable objects that contain something that is _by convention_ immutable (such as my `Str` types,  
which have a `String` used as a low-overhead known to the GC buffer) or mutable objects that are by convention immutable? (such as BigFloat or BigInt [which caused a big discussion 2 years ago])
