# Any way to skip a constructor for Accessors.jl-like syntax?

**URL:** <https://discourse.julialang.org/t/any-way-to-skip-a-constructor-for-accessors-jl-like-syntax/122678>\
**Category:** General Usage\
**Tags:** constructors, accessors\
**Created:** [November 15, 2024, 12:13pm UTC](https://discourse.julialang.org/t/any-way-to-skip-a-constructor-for-accessors-jl-like-syntax/122678 "2024-11-15T12:13:13Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 15, 2024, 1:03pm UTC](https://discourse.julialang.org/t/any-way-to-skip-a-constructor-for-accessors-jl-like-syntax/122678/3 "2024-11-15T13:03:44Z")

</div>

> [@Mason](#):
>
> That said, there are of course times where you want to be able to bypass this, so it’s good that there is a way (though I would like if there was a clean way to do this on a per-call basis, rather than globally overriding the behaviour for all instances of `EvenInt`).

Looks like this is actually not so hard to do by just defining a custom lens:

```julia
using Accessors: IndexLens, PropertyLens, ComposedOptic, setmacro, opticmacro, modifymacro

struct FieldLens{L}
    inner::L
end

(l::FieldLens)(o) = l.inner(o)
function Accessors.set(o, l::FieldLens{<:ComposedOptic}, val)
    o_inner = l.inner.inner(o)
    set(o_inner, FieldLens(l.inner.outer), val)
end
function Accessors.set(o, l::FieldLens{PropertyLens{prop}}, val) where {prop}
    setfield(o, val, Val(prop))
end

@generated function setfield(obj::T, val, ::Val{name}) where {T, name}
    fields = fieldnames(T)
    name ∈ fields || error("$(repr(name)) is not a field of $T, expected one of ", fields)
    Expr(:new, T, (name == field ? :val : :(getfield(obj, $(QuoteNode(field)))) for field ∈ fields)...)
end

macro setfield(ex)
    setmacro(FieldLens, ex, overwrite=false)
end
macro resetfield(ex)
    setmacro(FieldLens, ex, overwrite=true)
end

```

then define our type:

```julia
struct EvenInt
    x::Int
    function EvenInt(x::Int)
        iseven(x) || throw(ArgumentError("Must be even."))
        sleep(1) # pretend this is useful processing
        new(x)
    end
end

```

Regular `@reset` is still safe and slow:

```julia
julia> @time y = EvenInt(2)
  1.002596 seconds (4 allocations: 112 bytes)
EvenInt(2)

julia> @reset y.x = 5
ERROR: ArgumentError: Must be even.

julia> @time @reset y.x = 4
  1.002588 seconds (5 allocations: 128 bytes)
EvenInt(4)

```

But we now also have `@resetfield` which is unsafe and fast:

```julia
julia> @resetfield y.x = 5
EvenInt(5)

julia> @time @resetfield y.x = 4
  0.000005 seconds (1 allocation: 16 bytes)
EvenInt(4)

```

---

_[View the full topic](https://discourse.julialang.org/t/any-way-to-skip-a-constructor-for-accessors-jl-like-syntax/122678)._
