# Destructuring syntax in julia 1.7

**URL:** <https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236>\
**Category:** Internals & Design\
**Tags:** destructuring\
**Created:** [September 15, 2021, 11:01pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236 "2021-09-15T23:01:36Z")\
**Posts on this page:** 7\
**Page:** 4

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 19, 2022, 12:17pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/63 "2022-10-19T12:17:42Z")

</div>

> [@uniment](#):
>
> However, for all of `PropDicts`, `PropertyDicts`, and for my own datatype too, tab-autocomplete doesn’t work beyond the first nesting level

The problem is that `getproperty` may execute arbitrary code (as opposed to just looking up `struct` fields), so when we implemented tab completion we wanted to be a bit conservative/cautious about whether this is good idea to do during completion. Might be worth revisiting.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 19, 2022, 8:41pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/64 "2022-10-19T20:41:12Z")

</div>

> [@aplavin](#):
>
> Would it really infer `Any`? Even for something like `NamedTuple{NS, NTuple{N, Int}} where {NS, N}`?

You’re right, it doesn’t infer `Any`. Running this constructor, the resulting `NamedTuple` adopts the types of the `Dict`’s values:

```julia-auto
julia>NamedTuple(d::Dict{String,T} where T) = NamedTuple{Tuple(Symbol(k) for k ∈ keys(d))}(v for v ∈ values(d))
NamedTuple

julia> typeof(NamedTuple(Dict("a"=>1, "b"=>2)))
NamedTuple{(:b, :a), Tuple{Int64, Int64}}

```

I suppose one could _force_ the types, but I’m yak shaving now:

```julia-auto
NamedTuple(d::Dict{String,T}) where T = 
    NamedTuple{Tuple(Symbol(k) for k ∈ keys(d)), NTuple{length(d), T}}(v for v ∈ values(d))

```

Nonetheless, running `@code_warntype` on these constructors flags some `Vararg` types.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 19, 2022, 8:58pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/65 "2022-10-19T20:58:00Z")

</div>

> [@uniment](#):
>
> You’re right, it doesn’t infer `Any`. Running this constructor, the resulting `NamedTuple` adopts the types of the `Dict`’s values:

Any julia _object_ always has a concrete type - this is not related to what inference thinks the object type might be:

```julia
julia> MyTuple(d::Dict{String,T}) where T = NamedTuple{Tuple(Symbol(k) for k ∈ keys(d))}(v for v ∈ values(d))
MyTuple (generic function with 1 method)

julia> @code_warntype MyTuple(Dict("foo" => :bar))
MethodInstance for MyTuple(::Dict{String, Symbol})
  from MyTuple(d::Dict{String}) @ Main REPL[1]:1
Arguments
  #self#::Core.Const(MyTuple)
  d::Dict{String, Symbol}
Locals
  #3::var"#3#4"
Body::NamedTuple
1 ─ (#3 = %new(Main.:(var"#3#4")))
│ %2 = #3::Core.Const(var"#3#4"())
│ %3 = Main.keys(d)::Base.KeySet{String, Dict{String, Symbol}}
│ %4 = Base.Generator(%2, %3)::Base.Generator{Base.KeySet{String, Dict{String, Symbol}}, var"#3#4"}
│ %5 = Main.Tuple(%4)::Tuple{Vararg{Symbol}}
│ %6 = Core.apply_type(Main.NamedTuple, %5)::Type{NamedTuple{_A}} where _A
│ %7 = Main.values(d)::Base.ValueIterator{Dict{String, Symbol}}
│ %8 = Base.Generator(Base.identity, %7)::Base.Generator{Base.ValueIterator{Dict{String, Symbol}}, typeof(identity)}
│ %9 = (%6)(%8)::NamedTuple
└── return %9

```

The inferred `NamedTuple` return type visible in `@code_warntype` is ultimately what matters to inference, _NOT_ the concrete type of the actual `NamedTuple` object. Inference doesn’t know about the object and its concrete type - it can’t, since the object doesn’t exist when inference runs.

Moreover, since the names in the `Dict` are not part of its type, it cannot be type stable, no matter how much you twist it - this will always be type unstable.

> [@uniment](#):
>
> Nonetheless, running `@code_warntype` on these constructors flags some `Vararg` types.

You see those `Vararg` due to the number of the elements of the `Dict` being unknown to the compiler.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 26, 2022, 9:02pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/66 "2022-10-26T21:02:55Z")

</div>

I’m revisiting this, now that I’ve learned (a lot) more about the type system, and you’re right about the type instability. The lessons learned here have been quite useful in some recent work. 🙏

That said, it’s not unique to my custom `NamedTuple` constructor, because the built-in constructor is already type-unstable when you feed it a `Dict{Symbol}` or `Tuple{Pair{Symbol}}`.

```julia
@code_warntype NamedTuple(Dict(:a=>1, :b=>2))
@code_warntype NamedTuple((:a=>1, :b=>2))

```

---

<div class="post-metadata">

**Author:** ![Raf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/raf/32/3383_2.png) [@Raf](https://discourse.julialang.org/u/Raf)\
**Post date:** [October 26, 2022, 10:21pm UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/67 "2022-10-26T22:21:46Z")

</div>

This is what we expect though right?

Those symbols are runtime values you are lifting back to the type domain as `NamedTuple` keys (the classic case for type instability). I guess you are hoping constant propagation and escape analysis could work through the `Dict`/`Pair` constructors? In the `Dict` constructor `:a` and `:b` are copied to a `keys` vector, then they are read back out of it in the `NamedTuple` constructor.

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [October 27, 2022, 1:01am UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/68 "2022-10-27T01:01:06Z")

</div>

Yes, it’s expected behavior. I had originally thought @Sukera’s critique was somehow unique to my custom constructor, so I didn’t correctly understand what was meant by it.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [October 27, 2022, 7:21am UTC](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236/69 "2022-10-27T07:21:46Z")

</div>

> [@uniment](#):
>
> I had originally thought @Sukera’s critique was somehow unique to my custom constructor, so I didn’t correctly understand what was meant by it.

It’s always helpful to have a concrete example at hand, but yeah, the problem of type stability is not unique to your particular code. Lots of people encounter it.

[Previous page](https://discourse.julialang.org/t/destructuring-syntax-in-julia-1-7/68236.md?page=3)
