# Type() vs type() -- Are constructor methods or conversion functions more idiomatic?

**URL:** <https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233>\
**Category:** General Usage\
**Tags:** constructors, multiple-dispatch\
**Created:** [January 19, 2023, 8:41pm UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233 "2023-01-19T20:41:20Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![SortofDamocles](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sortofdamocles/32/15709_2.png) [@SortofDamocles](https://discourse.julialang.org/u/SortofDamocles)\
**Post date:** [January 19, 2023, 8:41pm UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233/1 "2023-01-19T20:41:21Z")

</div>

I am writing some code with structs that represent dual forms of the same underlying thing, e.g.

```julia
struct NormalForm
    normal_data
    descriptive_parameter
end
NormalForm(data) = NormalForm(data, process(data))

struct DualForm
    dual_data
    descriptive_parameter
end
DualForm(data) = DualForm(data, process(data))

```

I also have functions which convert between them:

```julia
normal_form(df::DualForm) = NormalForm(lambda(df))
dual_form(nf:NormalForm) = DualForm(lambda(nf))

```

My instinct was to write the conversion functions as distinct functions like this, rather than as new methods for the type constructors. But since they do the same thing that a constructor method would, it has occurred to me that they could just as easily _be_ constructor methods. But should they?

The built-in struct `String` is similar – there is a constructor `String()`, and there is the conversion function `string()`. Both return objects of type `String`. So why is `string()` defined separately?

On the other hand, there is _not_ an `int()` function. If I want to convert another numeric type to an integer, I have to call the type’s constructor, `Int()`.

[The docs](https://docs.julialang.org/en/v1/manual/conversion-and-promotion/) suggest that conversion functions should not create new objects if they don’t have to, while constructors always should. That might explain the difference between `String` and `Int`, and may suggest that the constructor approach is correct here, since I’ll never call `dual_form` on a `DualForm` object?

Defining e.g. `Base.convert(::NormalForm, x::DualForm)` would work, but it seems like that’s really only designed for implicit conversions rather than explicit ones like I want here.

So what is the preferred style for writing a function which returns objects of user-defined types? Is a constructor method more idiomatic (as in `Int()`) or are distinct conversion functions (as in `string()`)?

---

<div class="post-metadata">

**Author:** ![CameronBieganek](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cameronbieganek/32/6915_2.png) [@CameronBieganek](https://discourse.julialang.org/u/CameronBieganek)\
**Post date:** [January 20, 2023, 4:05am UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233/3 "2023-01-20T04:05:18Z")

</div>

I’ve encountered a similar situation in the past where my code basically consisted of a bunch of constructors. But it felt weird. You need some verbs in there. What if you have one function (with two methods) called `flip` or `conjugate` or `dual` that turns a normal form into a dual form and vice versa?

I guess I would say the rule of thumb is that a constructor just assembles data with a minor amount of processing (along with enforcing invariants). As you mentioned, `convert` is meant primarily for the implicit conversion that Julia does inside default constructors and, e.g., when assigning elements of vectors.

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [January 20, 2023, 7:49am UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233/4 "2023-01-20T07:49:18Z")

</div>

> [@CameronBieganek](#):
>
> rule of thumb is that a constructor just assembles data with a minor amount of processing (along with enforcing invariants)

I agree, in Julia it makes more sense to use a constructor for the simple instantiation of a particular type, and leave the processing to a regular function. This works better for composability.

Imagine someone makes another package to cover some special case of dual forms, that needs different concrete types `SpecialNormalForm` and `SpecialDualForm`. They can overload your `normal_form` and `dual_form` functions so users can use the same functions to write generic code that works for both `NormalForm` and `SpecialNormalForm`. This would not make sense with constructors (calling `DualForm(x::SpecialNormalForm)` to make a `SpecialDualForm` instead of a `Dualform`, which is technically possible but discouraged).

---

<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:** [January 20, 2023, 9:55am UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233/5 "2023-01-20T09:55:54Z")

</div>

> [@SortofDamocles](#):
>
> So what is the preferred style for writing a function which returns objects of user-defined types?

I am not sure there is a consensus about this, but I try to avoid exposing type constructors in the API, and do

```julia
export make_foo

make_foo(args...) = Foo(args...)

```

even where no other validation or calculation is required. Where the `make_` distinguishes the function from the potential variable name so I get to use `foo` for the latter.

I find this extra layer works nice for refactoring and deprecations, which happen almost surely eventually.

---

<div class="post-metadata">

**Author:** ![Per](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/per/32/10387_2.png) [@Per](https://discourse.julialang.org/u/Per)\
**Post date:** [January 20, 2023, 10:17am UTC](https://discourse.julialang.org/t/type-vs-type-are-constructor-methods-or-conversion-functions-more-idiomatic/93233/6 "2023-01-20T10:17:55Z")

</div>

I use the following convention

- `convert(Foo, x)` creates a `Foo` from exactly one input, `x` via something that a human would call “conversion”. If might be: `convert(::Type{Foo}, x) = x isa Foo ? x : Foo(x)`
- `Foo(x, y, z)` creates a `Foo`, but not necessarily by “converting” anything (e.g. `Vector{Int}(undef, 3)`.)
- `foo(x)` might create a `Foo`, but it might also create a `DifferentFoo`, depending on what `x` is.
