# Stack overflow from unexpected mutual constructor recursion on type alias

**URL:** <https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495>\
**Category:** General Usage\
**Created:** [January 10, 2019, 9:51pm UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495 "2019-01-10T21:51:41Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![andyljones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyljones/32/6669_2.png) [@andyljones](https://discourse.julialang.org/u/andyljones)\
**Post date:** [January 10, 2019, 9:51pm UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/1 "2019-01-10T21:51:41Z")

</div>

Define

```julia
using DataStructures
const Bar = OrderedDict{Int64, Int64}
Bar() = Bar(1=>2, 2=>3)

```

Then calling `Bar()` gets me

```julia
**ERROR:** StackOverflowError:
Stacktrace:
 [1] **OrderedDict{Int64,Int64}()** at **./REPL[3]:1**
 [2] **OrderedDict{Int64,Int64}(** ::Pair{Int64,Int64}, ::Vararg{Pair{Int64,Int64},N} where N **)** at **/Users/andyjones/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:28**
 ... (the last 2 lines are repeated 39998 more times)
 [79999] **OrderedDict{Int64,Int64}()** at **./REPL[3]:1**

```

For reference, `OrderedDict`’s implementation is [here](https://github.com/JuliaCollections/OrderedCollections.jl/blob/master/src/ordered_dict.jl#L20), and the relevant constructor is

```julia
function OrderedDict{K,V}(kv) where {K,V}
    h = OrderedDict{K,V}()
    # etc
end 

```

What’s happening here is that `Bar()` calls `OrderedConstructor(kv)` calls `Bar()` calls `OrderedConstructor(kv)`, etc.

What I _expected_ to happen is that `Bar()` calls `OrderedConstructor(kv)` calls `OrderedConstructor()`. I seem to have overridden `OrderedConstructor()` by defining the type alias, which is a surprise - I’d expect to have to define `DataStructures.OrderedConstructor() = xyz` to do that, [going by this table](https://docs.julialang.org/en/v1/manual/modules/index.html#Summary-of-module-usage-1).

So, two questions:

- Which part of the documentation do I need to read more carefully to understand why this is happening?
- How’d I get my expected behaviour? I’d ideally like to keep the names `Bar` and `Bar()`.

Thanks!

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 10, 2019, 11:51pm UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/2 "2019-01-10T23:51:16Z")

</div>

It looks like there is a difference between exported types and functions.

Extending a type constructor seems to work (and is indeed what happens in your case):

```julia
julia> using DataStructures

julia> methods(OrderedDict)
# 14 methods for generic function "(::Type)":
[1] (::Type{OrderedDict})() in OrderedCollections at /home/francois/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:43
[2] (::Type{OrderedDict})(kv::Tuple{}) in OrderedCollections at /home/francois/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:44
[3] (::Type{OrderedDict})(kv::Tuple{Vararg{Pair{K,V},N} where N}) where {K, V} in OrderedCollections at /home/francois/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:52                                                                                                                                                             
...

julia> OrderedDict() = "OK"
OrderedDict

julia> methods(OrderedDict)
# 14 methods for generic function "(::Type)":
[1] (::Type{OrderedDict})() in Main at REPL[3]:1
[2] (::Type{OrderedDict})(kv::Tuple{}) in OrderedCollections at /home/francois/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:44
[3] (::Type{OrderedDict})(kv::Tuple{Vararg{Pair{K,V},N} where N}) where {K, V} in OrderedCollections at /home/francois/.julia/packages/OrderedCollections/Pr9Pa/src/ordered_dict.jl:52
....

```

whereas extending functions does not work (as expected):

```julia
julia> methods(complement)
# 1 method for generic function "complement":
[1] complement(s::DataStructures.IntSet) in DataStructures at /home/francois/.julia/packages/DataStructures/6r6kb/src/int_set.jl:199

julia> complement() = "error"
ERROR: error in method definition: function DataStructures.complement must be explicitly imported to be extended
Stacktrace:
 [1] top-level scope at none:0

```

  

When looking at the documentation for [modules](https://docs.julialang.org/en/v1/manual/modules/), I found hints that the restriction forbidding methods extension might apply only to functions (maybe this means: “as opposed to type constructors”). For example (emphasis mine):

> The statement `using BigLib: thing1, thing2` brings just the identifiers `thing1` and `thing2` into scope from module `BigLib` . _If these names refer to functions_, adding methods to them will not be allowed (you may only “use” them, not extend them).

So I’m not sure if this difference is to be expected, but if it is, the documentation could perhaps be made more explicit.

---

<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:** [January 11, 2019, 1:22am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/3 "2019-01-11T01:22:17Z")

</div>

By doing `const Bar = OrderedDict{Int64, Int64}`, your `Bar` _is_ `OrderedDict{Int64, Int64}`. They are now just two names for the exact same thing, so when you add a method to `Bar` you’re also adding a method to `OrderedDict{Int, Int}`. I do agree that it’s a bit confusing that this is possible for types, while achieving the same result with a function would require you to import it.

As to your question, I don’t think it’s possible to do exactly what you’re asking for, for the precise reason you’ve found. Perhaps if you can give more context it will be easier to come up with a solution to the problem you’re actually trying to solve in your code.

By the way, the reason that you’re seeing a change in the behavior of the ordereddict constructor is that your `Bar()` method definition is an example of “type piracy”. You’re defining a method of a function you don’t own (the ordereddict constructor) on arguments you don’t own (an empty argument list). We specifically discourage type piracy because it can cause errors at a distance just like what you’ve run into.

---

<div class="post-metadata">

**Author:** ![andyljones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyljones/32/6669_2.png) [@andyljones](https://discourse.julialang.org/u/andyljones)\
**Post date:** [January 11, 2019, 8:39am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/4 "2019-01-11T08:39:28Z")

</div>

Both of your replies are really helpful, thanks!

> is an example of “type piracy”.

Bingo, that’s the Googlable phrase I was looking for. I’m still surprised that - as @ffevotte points out - I can add a method to the imported constructor without error, but adding a method to an imported function will raise an error. Are (outer) constructors special-cased in some way? So far I’ve assumed they’re just another method.

> Perhaps if you can give more context it will be easier to come up with a solution to the problem you’re actually trying to solve in your code.

I’m after a way to pass a list of functions around, keyed by some identifier and (indirectly) by their insertion order. Specifically, I’d like

- A type `Actions` that behaves exactly like `OrderedDict{Symbol, Function}`. Aliasing it like this makes a lot of function declarations more readable.
- I’d like the default instantiation to be `Actions(:f=>forward, :b=>backward)`. I’d like this because in the context of the program I’m writing, it’s what you’d expect `Actions` to contain - an empty `Actions` would be surprising.
- I’d like to keep the idiom that to get the default instantiation of an object, you call the empty constructor `Actions()`.

Having written that out I see the fundamental conflict - I want something that’s exactly like `OrderedDict`, but that isn’t like it in how it’s constructors are defined. If the constructors are part of the type (?), rather than just some random methods lying around, then replacing the constructors makes it not exactly like it.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [January 11, 2019, 9:16am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/5 "2019-01-11T09:16:42Z")

</div>

Couldn’t you just use an ordinary method to construct your OrderedDict:

```julia
julia> using OrderedCollections

julia> Bar() = OrderedDict(1=>2, 2=>3)
Bar (generic function with 1 method)

julia> Bar()
OrderedDict{Int64,Int64} with 2 entries:
  1 => 2
  2 => 3

```

?

---

<div class="post-metadata">

**Author:** ![andyljones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyljones/32/6669_2.png) [@andyljones](https://discourse.julialang.org/u/andyljones)\
**Post date:** [January 11, 2019, 9:21am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/6 "2019-01-11T09:21:06Z")

</div>

I can if I don’t have the type alias `const Bar = OrderedDict{Int64, Int64}`! But that’s a core part of what I’m after, because it’s much nicer to write `foo(bar::Bar)` than `foo(bar::OrderedDict{Int64, Int64})`.

If I _do_ have the type alias, then `Bar()` pirates `OrderedDict()` and I get an infinite recursion.

---

<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 11, 2019, 9:55am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/7 "2019-01-11T09:55:58Z")

</div>

> [@andyljones](#):
>
> If I _do_ have the type alias, then `Bar()` pirates `OrderedDict()` and I get an infinite recursion.

I wonder if you could name it something else then — eg `bar`.

---

<div class="post-metadata">

**Author:** ![andyljones](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/andyljones/32/6669_2.png) [@andyljones](https://discourse.julialang.org/u/andyljones)\
**Post date:** [January 11, 2019, 9:58am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/8 "2019-01-11T09:58:02Z")

</div>

Yep, that’s the simplest solution. But it breaks the idiom that when you want a default `Foo` you call `Foo()`. Possibly unavoidable from what everyone here has said, but a bit annoying.

---

<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 11, 2019, 10:04am UTC](https://discourse.julialang.org/t/stack-overflow-from-unexpected-mutual-constructor-recursion-on-type-alias/19495/9 "2019-01-11T10:04:23Z")

</div>

You can also make `Bar` a thin wrapper of `OrderedDict`:

```julia
struct Foo{T <: OrderedDict}
    dict::T
end

# and then forward the methods to dict

```

> [@andyljones](#):
>
> idiom that when you want a default `Foo` you call `Foo()` .

IMO a function the creates a special/specifc value of `T` should not need to be called `T` — eg `eps()` is not called `Float64`.
