# Shorter way to rename property, with Accessors

**URL:** <https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256>\
**Category:** General Usage\
**Tags:** accessors\
**Created:** [March 22, 2025, 7:48am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256 "2025-03-22T07:48:13Z")\
**Posts on this page:** 17\
**Page:** 1

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 22, 2025, 7:48am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/1 "2025-03-22T07:48:13Z")

</div>

How to do rename with Accessors? This is too long.

```julia
julia> let x = (;a=1)
           @delete (@insert x.b = x.a).a
       end
(b = 1,)

```

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [March 22, 2025, 9:06am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/2 "2025-03-22T09:06:47Z")

</div>

You could just put the `@delete @insert` into a dedicated method / macro:

```julia-repl
julia> macro rename(x, old_name, new_name)
           return esc(:(@delete (@insert $x.$new_name = $x.$old_name).$old_name))
       end

julia> let x = (;a=1,c=3)
           @rename x a b
       end
(c = 3, b = 1)

```

Or if you want some fancier syntax

```julia-repl
julia> using MacroTools: @capture, postwalk

julia> macro rename(ex)
           postwalk(ex) do x
               if @capture(x, t_.old_ --> t_.new_)
                   return :( @delete (@insert $t.$new = $t.$old).$old )
               else
                   return x
               end
           end |> esc
       end

julia> let x = (;a=1,c=3)
           @rename x.a --> x.b
       end
(c = 3, b = 1)
```

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [March 22, 2025, 9:18am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/3 "2025-03-22T09:18:39Z")

</div>

There’s `@replace` in AccessorsExtra.jl:

```julia-repl
julia> let x = (; a = 1, c = 3)
         @replace(x.b = x.a)
       end
(b = 1, c = 3)

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 22, 2025, 3:50pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/4 "2025-03-22T15:50:43Z")

</div>

Yes, `@replace` was introduced to AccessorsExtra.jl basically for this usecase. It’s also somewhat more general and supports nesting and arbitrary optics, not just property access:

```julia
julia> x = (a=(b=1, c=2), d=3)
(a = (b = 1, c = 2), d = 3)

julia> @replace x.f = x.a.b
(a = (c = 2,), d = 3, f = 1)

julia> @replace x.a.f = x[2]
(a = (b = 1, c = 2, f = 3),)

```

Tbh, I don’t find myself using it almost ever… Curious to hear about your usage scenarios!

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 22, 2025, 9:22pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/5 "2025-03-22T21:22:07Z")

</div>

I saw `@replace` was in my namespace but didn’t try it out because

```julia-auto
help?> @replace
  No documentation found for public symbol.

```

> [@aplavin](#):
>
> Curious to hear about your usage scenarios!

I want to change the column names of a `StructArray`. Ideally I’d be able to (1) manually set each as you’ve demonstrated, or (2) use a function to e.g. lowercase all of them.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 23, 2025, 3:18am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/6 "2025-03-23T03:18:26Z")

</div>

> [@jar1](#):
>
> `No documentation found for public symbol.`

I myself only used it a few times, and didn’t bother adding any docs because considered it unlikely many others would have usecases for it 🙂 A docs PR would definitely be welcome.

> [@jar1](#):
>
> (1) manually set each

`@replace A.newcol = A.oldcol`, or `@set propertynames(A)[3] = :newcol`, depending on what you mean by “set”.

> [@jar1](#):
>
> (2) use a function to e.g. lowercase all of them.

`@modify(lowercase, propertynames(A)[∗])`.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 23, 2025, 3:43am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/7 "2025-03-23T03:43:47Z")

</div>

Just a thought before we go documenting it:

Is `@replace` definitely the right name for this macro, not `@rename`? I’m just thinking `replace` already has a meaning (in Base) that’s quite unrelated to this, and `rename` has a quite related meaning in both NamedDims.jl and DataFrames.jl.

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [March 23, 2025, 4:31am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/8 "2025-03-23T04:31:46Z")

</div>

Yeah, it doesn’t have a docstring and wasn’t in the Pluto file that serves as docs for AccessorsExtra either, I had to go to the package’s tests to see its usage. But it _is_ an exported name, and that Pluto doc also mentions it (and suggests doing just that - looking up tests - to learn more about it).

As an aside, the message `No documentation found for public symbol.` is an additional reason to love the new `public` keyword and related work. It immediately makes it clear that this is a public, okay-to-use part of the API, despite it not having docs. Technically it doesn’t add any information (since the name being exported already meant that even back then), but makes for a much smoother dev experience.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 23, 2025, 4:49am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/9 "2025-03-23T04:49:44Z")

</div>

> [@digital\_carver](#):
>
> It immediately makes it clear that this is a public, okay-to-use part of the API, despite it not having docs.

My take on this is that a _function_ isn’t okay to use if it doesn’t have any defined semantics. The only thing we know here is that the _symbol_ is defined in the module.

---

<div class="post-metadata">

**Author:** ![digital\_carver](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/digital_carver/32/33818_2.png) [@digital\_carver](https://discourse.julialang.org/u/digital_carver)\
**Post date:** [March 23, 2025, 8:11am UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/10 "2025-03-23T08:11:24Z")

</div>

That stance makes sense in theory, but the reality is that a huge number of functions and macros in Julia - including many in Base - are so poorly defined by their docs in terms of semantics. This is better today than it was a few years ago, at least in Base, but still remains true in many cases. There are many docs that give a sentence or two of text that vaguely point towards what the function is intended to do, and a few examples that demonstrate other parts of the semantics (often things the text says nothing about).

And what people end up relying on for the most part are “reasonable” extrapolations of those docs, based on the observed behaviour of the function. And the assumption that that behaviour will not change for public names, excepting extreme edge cases/unintended interactions. And by “people” I don’t mean the unwary or the careless, this is pretty much what every Julia user does in practice.

The Pluto doc here references the tests for this macro, and those tests demonstrate the semantics of it at least as well as the usual docs do, if not better. So my take is that, at least in this case, the `export` makes it okay to use, and the tests give the semantics to base our understanding of the macro on, to the same extent or better as compared to basing it on the usual kind of docs.

(I’m not especially attached to this macro, just giving my philosophical take on this and also taking the chance to air out some frustration with our usual level of docs.)

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 23, 2025, 5:03pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/11 "2025-03-23T17:03:23Z")

</div>

> [@jar1](#):
>
> Is `@replace` definitely the right name for this macro, not `@rename`? I’m just thinking `replace` already has a meaning (in Base) that’s quite unrelated to this, and `rename` has a quite related meaning in both [NamedDims.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/NamedDims) and [DataFrames.jl](https://juliaregistries.github.io/General/packages/redirect_to_repo/DataFrames).

Maybe… And if it ends up widely useful, may make sense to upstream to Accessors.jl proper (with well-defined semantics).

I’m all for better names, but IMO `rename` sounds strange as soon as we move beyond single-level property replacing. Is it really “rename” in these examples?

```julia
@replace x.a = x.b.c[3]
@replace x.a = last(x.b.c)
@replace x.a = dirname(x.b)
...

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 23, 2025, 5:33pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/12 "2025-03-23T17:33:56Z")

</div>

Btw, for tables specifically, one can use `columntable()` to operate on columns even for tables that don’t support property access:

```julia
julia> tbl = [(a=1, b=2), (a=3, b=4)]
2-element Vector{@NamedTuple{a::Int64, b::Int64}}:
 (a = 1, b = 2)
 (a = 3, b = 4)

julia> @set columntable(tbl).b = [10, 20]
2-element Vector{@NamedTuple{a::Int64, b::Int64}}:
 (a = 1, b = 10)
 (a = 3, b = 20)

```

Should work with basically any table, and within `@replace` as well.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 23, 2025, 7:40pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/13 "2025-03-23T19:40:16Z")

</div>

> [@aplavin](#):
>
> ```julia-auto
> @replace x.a = x.b.c[3]
> @replace x.a = last(x.b.c)
> @replace x.a = dirname(x.b)
> 
> ```

Am I getting this? In general we have to pattern match a `@replace` RHS `e_n(e_{n-1}(...(e_1(e_0))))` into `f(optic(obj))`? So `dirname(x.b.c)` is `f=dirname` and `optic=@o _.b.c`?

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 23, 2025, 8:08pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/14 "2025-03-23T20:08:10Z")

</div>

Not really, there’s no special handling to `f(optic(obj))` vs `optic(obj)`. Tbh, I don’t even understand what you mean by that split `f` vs `optic`.  
Let’s look at `@o` and simpler functions, like `set` and `delete`, first:

```julia
julia> optic = @o last(_.b.c)
(@o last(_.b.c))

julia> dump(optic)
(@o last(_.b.c)) (function of type ComposedFunction{ComposedFunction{typeof(last), PropertyLens{:c}}, PropertyLens{:b}})
  outer: (@o last(_.c)) (function of type ComposedFunction{typeof(last), PropertyLens{:c}})
    outer: last (function of type typeof(last))
    inner: PropertyLens{:c} (@o _.c)
  inner: PropertyLens{:b} (@o _.b)

julia> x = (a=1, b=(c=[2,3,4], d=5))
(a = 1, b = (c = [2, 3, 4], d = 5))

julia> delete(x, optic)
(a = 1, b = (c = [2, 3], d = 5))

julia> set(x, optic, 100)
(a = 1, b = (c = [2, 3, 100], d = 5))

```

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 23, 2025, 8:39pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/15 "2025-03-23T20:39:58Z")

</div>

> [@aplavin](#):
>
> I don’t even understand what you mean by that split `f` vs `optic`.

I thought

```julia-auto
x = (b = (c = ["/2", "/3/3/", "/4/4/4"],), d = 5)
@replace x.a = dirname(last(x.b.c))

```

was going to be equivalent to

```julia-auto
oget = (@o last(_.b.c))
oset = (@o _.a)
f = dirname
insert(
  delete(x, oget), 
  oset,
  (f∘oget)(x),
)

```

but it turns out not quite the same

```julia-auto
julia> insert(
         delete(x, oget), 
         oset,
         (f∘oget)(x),
       )
(b = (c = ["/2", "/3/3/"],), d = 5, a = "/4/4")

julia> @replace x.a = dirname(last(x.b.c))
(b = (c = ["/2", "/3/3/", "4"],), d = 5, a = "/4/4")

```

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [March 23, 2025, 8:42pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/16 "2025-03-23T20:42:40Z")

</div>

Everything is even easier:  
`@replace f(x) = g(x)`  
is equivalent to  
`insert(delete(x, g), f, g(x))` 🙂  
No matter if `g = dirname`, `g = @o _.a`, or `g = @o last(_.a.b)`.

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [March 23, 2025, 8:51pm UTC](https://discourse.julialang.org/t/shorter-way-to-rename-property-with-accessors/127256/17 "2025-03-23T20:51:47Z")

</div>

I see, that’s cool.
