# Same constructors, less code written

**URL:** <https://discourse.julialang.org/t/same-constructors-less-code-written/44120>\
**Category:** Internals & Design\
**Created:** [August 2, 2020, 6:40am UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120 "2020-08-02T06:40:08Z")\
**Posts on this page:** 8\
**Page:** 1

<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:** [August 2, 2020, 6:40am UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/1 "2020-08-02T06:40:08Z")

</div>

Now that Julia constructors are so well supported, we could avoid writing `convert` functions where there is a `promote_rule` and the proper conversion is to apply the promotion selected type constructor.

Please see my next comment (post 3) for a use case.

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [August 2, 2020, 9:20am UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/2 "2020-08-02T09:20:41Z")

</div>

Is it though? I always thought that `convert` can be a no-op (`convert(::Type{T}, a::T) === a`), whereas constructor always create a new object? Replacing `converts` by calls to constructor (what I understand you suggest) leads to data copy e.g. when assigning to structs fields (which calls `convert`), hence major inefficiency.

```julia
julia> v = [1,2,3];

julia> convert(Vector{Int}, v) === v
true

julia> Vector{Int}(v) === v
false

```

---

<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:** [August 2, 2020, 10:13am UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/3 "2020-08-02T10:13:23Z")

</div>

I mean for this use to occur when appropriate, where there is a promotion and to realize the promotion, a conversion must occur. Often, the conversion is accomplished by applying a constructor of the promoted type to the targeted type. When there is need for special conversion logic, we have `convert`. For the other, common, occurrences, Julia could just use the appropriate constructor when it is available.

```julia
struct MyInt
  val::Int
end

Base.promote_rule(::Type{MyInt}, ::Type{Int}) = MyInt
# MyInt(x::Int) already constructs a MyInt ... yet

julia> add(x::Int, y::MyInt) = add(promote(x,y)...)
julia> add(x::MyInt, y::MyInt) = MyInt(x.val + y.val)

julia> anint = 8; myint = MyInt(5);
julia> add(anint, myint)
ERROR: MethodError: Cannot `convert` an object
   of type Int64 to an object of type MyInt
Closest candidates are:
  convert(::Type{T}, ::T) where T at essentials.jl:171
  MyInt(::Int64) at REPL[1]:2
  MyInt(::Any) at REPL[1]:2

julia> # this next line fixes it, imo it should not be needed
julia> Base.convert(::Type{MyInt}, x::Int) = MyInt(x)
julia> add(int, myint)
MyInt(13)

```

---

<div class="post-metadata">

**Author:** ![abulak](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/abulak/32/28314_2.png) [@abulak](https://discourse.julialang.org/u/abulak)\
**Post date:** [August 2, 2020, 3:35pm UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/4 "2020-08-02T15:35:49Z")

</div>

this the convert you suggest is already defined for “arithmetic types”, i.e. if You make `MyInt <: Number`:

```julia
julia> struct MyInt <: Number
         val::Int
       end

julia> Base.promote_rule(::Type{MyInt}, ::Type{Int}) = MyInt

julia> add(x::Int, y::MyInt) = add(promote(x,y)...)
add (generic function with 2 methods)

julia> add(x::MyInt, y::MyInt) = MyInt(x.val + y.val)
add (generic function with 2 methods)

julia> anint = 8; myint = MyInt(5);

julia> add(anint, myint)
MyInt(13)

```

It’s a valid question though if we’d want to have converts to fallback to constructors, unconditionally. I’d say no, as constructors for more complex types usually require much more information so You’d need to implement those converts nonetheless. I’ve seen also packages opting out of using promote rules even for arithmetic types , but your use-case may be different.

---

<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:** [August 2, 2020, 5:27pm UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/5 "2020-08-02T17:27:03Z")

</div>

My experience has been that constructors for nonsimple types are stratified, keeping the specifics of working away from the constructive api. Using AbstractFloat as an abstract supertype (often a closest fitting supertype for me) caused problems in the past, because of the very special attention given Floating Point types from the early dev days. I do not know if this has been revisited. Falling back to Real pulls in Bool (Bool \<: Real), and that brings the need for unobvious accommodations to preclude ambiguities. Number is useful for broader than Complex numeric (and for Complex too, as there is no abstract type between Complex and Number). Yet Number and Real feel too broad a blanket for e.g. Float8.

It’s not that I disagree with the view you write, I just see some low hanging fruit. If my construct benefits from some specialized conversion logic, Julia already facilitates that. Where my construct comports with recent Julia best practice (favoring the use of Constructors over Conversions where there is no special reason to have Conversions doing that work) and the way it is promulgating in Base and through the ecosystem, why not apply the constructor if one has defined a constructor that accepts the promotion target type.

The absence of such a constructor would raise a similar error to that we see at present. The presence of such a constructor in the absence of a defined converter for the promotion target type very strongly indicates the intent of the software designer. There is no additional benefit to explicitly typing (essentially rewriting) that intent, as all the methods and relevant contexts are fully at hand. So we allow that “Julia just works” correctly with a dollop more serendipity.

---

<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:** [August 3, 2020, 2:08pm UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/6 "2020-08-03T14:08:57Z")

</div>

> [@JeffreySarnoff](#):
>
> Now that Julia constructors are so well supported

I am confused by this. At what point were they _weren’t_ well-supported? What changed?

AFAIK they are one of the oldest feature of the language.

---

<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:** [August 3, 2020, 2:57pm UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/7 "2020-08-03T14:57:22Z")

</div>

…so well supported in the designs of community packages  
(years ago, explicit calls to `convert` were more common,  
and constructors were more focused, like funnels)

---

<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:** [August 3, 2020, 3:03pm UTC](https://discourse.julialang.org/t/same-constructors-less-code-written/44120/8 "2020-08-03T15:03:48Z")

</div>

AFAIK there was a change in the language, see

[https://github.com/JuliaLang/julia/issues/15120](https://github.com/JuliaLang/julia/issues/15120)

and related issues/PRs.
