# Should passing Val(dims) to cat be better documented?

**URL:** <https://discourse.julialang.org/t/should-passing-val-dims-to-cat-be-better-documented/107294>\
**Category:** General Usage\
**Tags:** cat\
**Created:** [December 7, 2023, 6:58pm UTC](https://discourse.julialang.org/t/should-passing-val-dims-to-cat-be-better-documented/107294 "2023-12-07T18:58:14Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [December 7, 2023, 6:58pm UTC](https://discourse.julialang.org/t/should-passing-val-dims-to-cat-be-better-documented/107294/1 "2023-12-07T18:58:14Z")

</div>

Would documenting the reason for passing `Val(dims)` to to the `dims` keyword of `cat` lead to more purrfect documentation than what we have meow?

Currently the [documentation](https://docs.julialang.org/en/v1/base/arrays/#Base.cat) for `cat` indicates that one can pass a `Val` to dims, but it does not explain why.

An experienced Julia user might know this is due to type stability. Should the documentation include a note about that or is this obvious?

```julia-repl
julia> @code_warntype cat([5], [2], dims = 2)
MethodInstance for Core.kwcall(::NamedTuple{(:dims,), Tuple{Int64}}, ::typeof(cat), ::Vector{Int64}, ::Vector{Int64})
  from kwcall(::Any, ::typeof(cat), A...) @ Base abstractarray.jl:1981
Arguments
  _::Core.Const(Core.kwcall)
  @_2::NamedTuple{(:dims,), Tuple{Int64}}
  @_3::Core.Const(cat) A::Tuple{Vector{Int64}, Vector{Int64}}
Locals
  @_5::Int64
  dims::Int64
Body::Any 1 ─ nothing
│ Core.NewvarNode(:(@_5))
│ %3 = Core.isdefined(@_2, :dims)::Core.Const(true)
└── goto #3 if not %3
2 ─ (@_5 = Core.getfield(@_2, :dims))
└── goto #4
3 ─ Core.Const(:(Core.UndefKeywordError(:dims)))
└── Core.Const(:(@_5 = Core.throw(%7)))
4 ┄ %9 = @_5::Int64
│ (dims = %9)
│ %11 = (:dims,)::Core.Const((:dims,))
│ %12 = Core.apply_type(Core.NamedTuple, %11)::Core.Const(NamedTuple{(:dims,)})
│ %13 = Base.structdiff(@_2, %12)::Core.Const(NamedTuple())
│ %14 = Base.pairs(%13)::Core.Const(Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}())
│ %15 = Base.isempty(%14)::Core.Const(true)
└── goto #6 if not %15
5 ─ goto #7
6 ─ Core.Const(:(Core.tuple(@_2, @_3)))
└── Core.Const(:(Core._apply_iterate(Base.iterate, Base.kwerr, %18, A)))
7 ┄ %20 = Base.:(var"#cat#153")::Core.Const(Base.var"#cat#153")
│ %21 = Core.tuple(dims, @_3)::Tuple{Int64, typeof(cat)}
│ %22 = Core._apply_iterate(Base.iterate, %20, %21, A)::Any
└── return %22

julia> @code_warntype cat([5], [2], dims = Val(2))
MethodInstance for Core.kwcall(::NamedTuple{(:dims,), Tuple{Val{2}}}, ::typeof(cat), ::Vector{Int64}, ::Vector{Int64})
  from kwcall(::Any, ::typeof(cat), A...) @ Base abstractarray.jl:1981
Arguments _::Core.Const(Core.kwcall) @_2::Core.Const((dims = Val{2}(),)) @_3::Core.Const(cat) A::Tuple{Vector{Int64}, Vector{Int64}} Locals
  @_5::Val{2}
  dims::Val{2}
Body::Matrix{Int64}
1 ─ nothing
│ Core.NewvarNode(:(@_5))
│ %3 = Core.isdefined(@_2, :dims)::Core.Const(true)
└── goto #3 if not %3 2 ─ (@_5 = Core.getfield(@_2, :dims))
└── goto #4 3 ─ Core.Const(:(Core.UndefKeywordError(:dims)))
└── Core.Const(:(@_5 = Core.throw(%7)))
4 ┄ %9 = @_5::Core.Const(Val{2}())
│ (dims = %9)
│ %11 = (:dims,)::Core.Const((:dims,))
│ %12 = Core.apply_type(Core.NamedTuple, %11)::Core.Const(NamedTuple{(:dims,)})
│ %13 = Base.structdiff(@_2, %12)::Core.Const(NamedTuple()) │ %14 = Base.pairs(%13)::Core.Const(Base.Pairs{Symbol, Union{}, Tuple{}, NamedTuple{(), Tuple{}}}())
│ %15 = Base.isempty(%14)::Core.Const(true)
└── goto #6 if not %15
5 ─ goto #7
6 ─ Core.Const(:(Core.tuple(@_2, @_3)))
└── Core.Const(:(Core._apply_iterate(Base.iterate, Base.kwerr, %18, A)))
7 ┄ %20 = Base.:(var"#cat#153")::Core.Const(Base.var"#cat#153")
│ %21 = Core.tuple(dims, @_3)::Core.Const((Val{2}(), cat))
│ %22 = Core._apply_iterate(Base.iterate, %20, %21, A)::Matrix{Int64}
└── return %22

```

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [December 7, 2023, 7:34pm UTC](https://discourse.julialang.org/t/should-passing-val-dims-to-cat-be-better-documented/107294/2 "2023-12-07T19:34:31Z")

</div>

Do we need to document it at all now that Julia v1.10+ does the constant propagation as one would prefur?

```Julia-repl
julia> f(x, y) = cat(x, y; dims = 2)
f (generic function with 1 method)

julia> @code_warntype f([5],[2])
MethodInstance for f(::Vector{Int64}, ::Vector{Int64})
  from f(x, y) @ Main REPL[1]:1
Arguments
  #self#::Core.Const(f)
  x::Vector{Int64}
  y::Vector{Int64}
Body::Matrix{Int64}
1 ─ %1 = (:dims,)::Core.Const((:dims,))
│ %2 = Core.apply_type(Core.NamedTuple, %1)::Core.Const(NamedTuple{(:dims,)})
│ %3 = Core.tuple(2)::Core.Const((2,))
│ %4 = (%2)(%3)::Core.Const((dims = 2,))
│ %5 = Core.kwcall(%4, Main.cat, x, y)::Matrix{Int64}
└── return %5

```

I see `Val` as an ugly band-aid of Julia’s past. Now that the compiler is much better about constant propagation it’s largely not needed.
