# \[ANN\] Announcing MethodForwarding.jl

**URL:** <https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599>\
**Category:** Package Announcements\
**Created:** [April 1, 2025, 3:22pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599 "2025-04-01T15:22:02Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 1, 2025, 3:22pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/1 "2025-04-01T15:22:02Z")

</div>

Hello,

I’m announcing ~~AutoForward.jl~~ [MethodForwarding.jl](https://github.com/ghyatzo/MethodForwarding.jl)~~(still in the registering 3-day waiting period)~~, which should make composing objects much more hasslefree. It’s a bit what I’ve always wanted `@forward` from Lazy.jl to be.

The package exports a single `@forward` macro. The behaviour is probably best explained with an example (for details check the README in the repo):

```julia
struct A
    x::Int
end
value(a::A) = a.x
doubleA(a::A) = 2 * value(a)

@forward A struct NamedA
    a::A
    name::String
end
name(na::NamedA) = na.name

a = A(10)
named_A = NamedA(a, "name")
@assert value(named_A) == 10
@assert doubleA(named_A) == 20

```

We can also make a wrapper type splat into function arguments:

```julia
function1(a::Int, b::Int) = a + b
function2(a::Int, b::Int, c::Int) = a + b + c

@forward {Int, Int},
struct Point2
    x::Int
    y::Int
end

p = Point2(1,1)
@assert function1(p) == 2
@assert function2(p, 1) == function2(1, p) == 3

```

By default only the functions defined in the current module are forwarded, but it is possible to specify a list of modules and/or functions for which to forward their methods:

```julia
module MainModule

module InnerModule
  export innerfunc
  innerfunc(a::Int, b::Int) = a + b + 100
  anotherfunc(a::Int, b::Int) = a + b + 200
end
using .InnerModule

function1(a::Int, b::Int) = a + b
function2(a::Int, b::Int, c::Int) = a + b + c

@forward {Int, Int},
struct Point2
	x::Int
	y::Int
end function1
# Generates: 
# function1(p)

@forward {Int, Int},
struct Point2
	x::Int
	y::Int
end InnerModule # forwards only the public/exported methods of InnerModule
# Generates: 
# innerfunc(p)

@forward {Int, Int},
struct Point2
	x::Int
	y::Int
end InnerModule.anotherfunc # forwards a specific method of a specific module
# Generates: 
# anotherfunc(p)

@forward {Int, Int},
struct Point2
	x::Int
	y::Int
end (InnerModule, function2) # exports all public functions of InnerModule, and function2
# Generates: 
# function2(a, p)
# function2(p, c)
# innerfunc(p)

end # module

```

This package has not been used in the wild very much and it’s still highly experimental, so don’t expect flawless outputs.

~~I am also not married to the name, if the name `@forward` or `AutoForward` `MethodForwarding` rubs you the wrong way i’m open to suggestions (while still in the package registry waiting period if possible)!~~

---

<div class="post-metadata">

**Author:** ![gdalle](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gdalle/32/27854_2.png) [@gdalle](https://discourse.julialang.org/u/gdalle)\
**Post date:** [April 1, 2025, 8:44pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/2 "2025-04-01T20:44:44Z")

</div>

Hi, congrats on the package!  
I have no opinions on the content, just want to point out that the name AutoForward could suggest that it has to do with automatic differentiation. It sounds a lot like a backend name from ADTypes.jl (like `AutoForwardDiff`). I’m not opposing the registration on these grounds but if you have alternative name ideas (AutoCompose?) it might be less confusing.

---

<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:** [April 1, 2025, 9:00pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/3 "2025-04-01T21:00:11Z")

</div>

I guessed correctly from the name what the package does when I saw the announcement…but had to second-guess when I saw @gdalle’s face in the thread 🙂

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 1, 2025, 9:48pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/4 "2025-04-01T21:48:37Z")

</div>

That is definitely a valid concern. I’ll workshop another name for the package.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [April 1, 2025, 10:57pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/5 "2025-04-01T22:57:41Z")

</div>

Would something like `MethodForwarding.jl` be more descriptive? At least something that describes what is being forwarded?

---

<div class="post-metadata">

**Author:** ![JADekker](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jadekker/32/210281_2.png) [@JADekker](https://discourse.julialang.org/u/JADekker)\
**Post date:** [April 2, 2025, 6:08am UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/6 "2025-04-02T06:08:54Z")

</div>

Perhaps something with ‘Extends’, as it basically extends an existing struct with more fields, while keeping the original methods?

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 2, 2025, 6:29am UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/7 "2025-04-02T06:29:37Z")

</div>

Yes! That’s the name I’ve landed on as well.  
Today I’ll make the switch. Thanks for all the suggestions!

---

<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:** [April 2, 2025, 6:45am UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/8 "2025-04-02T06:45:36Z")

</div>

I can’t decide whether it’s a good thing or a bad thing that this name sounds so similar to [ForwardMethods.jl](https://github.com/curtd/ForwardMethods.jl) by @curtd.

The two packages some similar functionality, so it would make sense that their names are similar, but I can also see myself never being able to remember which one has the specific features I want in a particular case, and constantly getting confused between the two.

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 2, 2025, 10:28pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/9 "2025-04-02T22:28:32Z")

</div>

I see the potential headache, but given the extremely narrow focus of this package, a precise and descriptive name like `MethodForwarding.jl` I think would be better than anything more abstract. I’ve toyed with the idea of borrowing Rust `derive` terminology, given the neighbouring concepts, so something like `DeriveMethods.jl` with the macro called `@derive` instead. But I am not completely convinced, given that the term `derive` is very generic.

Maybe in a future the headache could be solved by merging the packages!

---

<div class="post-metadata">

**Author:** ![BdeKoning](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bdekoning/32/214557_2.png) [@BdeKoning](https://discourse.julialang.org/u/BdeKoning)\
**Post date:** [April 3, 2025, 10:41am UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/10 "2025-04-03T10:41:05Z")

</div>

Is this package suitable for something like this PR:

[Use `similar` methods from `ArrayPartion` for `NamedArrayPartition` by SouthEndMusic · Pull Request #431 · SciML/RecursiveArrayTools.jl](https://github.com/SciML/RecursiveArrayTools.jl/pull/431)

where I basically apply a method on a field of a wrapper and then reapply the wrapper.

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 3, 2025, 12:13pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/11 "2025-04-03T12:13:52Z")

</div>

No, not at the current state. Something like

```julia
@forward ArrayPartition,
struct NamedArrayPartition
    arr::ArrayPartition
    name::String
end

```

would result in

```julia
similar(A::NamedArrayPartition) = similar(A.arr)

```

This raises a good point though. I’ve already excluded constructors from the automatic forwarding for exactly this reason, that usually constructing objects needs more customized behaviour. But I didn’t think about constructor-like methods such as similar.

One could add some customized generators for special cases like this, something like  
`similar(w::Wrapper) = Wrapper( W.field1, ..., similar(forwarded field), W.fieldn, ...)`  
could work, but I think that culd be a slippery slope.

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [April 6, 2025, 7:58pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/12 "2025-04-06T19:58:38Z")

</div>

The package has been merged into the registry and updated to `0.2.0`. It should be availble for use.

The new version added support for:

- parametric forwarding:

```julia
# we only forward wrappers of arrays of integers.
@forward Array{T,N} where {T<:Integer,N},
struct MyArray{T,N}
    a::Array{T,N}
    some_attr::Int
    MyArray(T, dims::NTuple{N,Int}) where {N} = new{T,N}(zeros(T, dims...), 1)
end, (Base.size,)

afloat = MyArray(Float64, (2, 2, 2))
aint = MyArray(Int, (2, 2, 2))

@assert size(aint) == (2,2,2)
size(afloat) # results in a method error.

```

- keyword arguments passthrough
- anonymous arguments

happy forwarding!

---

<div class="post-metadata">

**Author:** ![marco\_menarini](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marco_menarini/32/46117_2.png) [@marco\_menarini](https://discourse.julialang.org/u/marco_menarini)\
**Post date:** [April 16, 2025, 3:29pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/13 "2025-04-16T15:29:18Z")

</div>

ooooh this would have been useful a couple of days ago. Good job 😃

---

<div class="post-metadata">

**Author:** ![cshen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cshen/32/217287_2.png) [@cshen](https://discourse.julialang.org/u/cshen)\
**Post date:** [May 5, 2025, 2:29pm UTC](https://discourse.julialang.org/t/ann-announcing-methodforwarding-jl/127599/14 "2025-05-05T14:29:56Z")

</div>

## Version 0.3.0

New breaking version which decouples the macro from the struct definition.  
What was before

```julia-auto
@forward Array{T,N} where {T<:Integer,N},
struct MyArray{T,N}
    a::Array{T,N}
    some_attr::Int
    MyArray(T, dims::NTuple{N,Int}) where {N} = new{T,N}(zeros(T, dims...), 1)
end, (Base.size,)

```

is now

```julia-auto
struct MyArray{T,N}
    a::Array{T,N}
    some_attr::Int
    MyArray(T, dims::NTuple{N,Int}) where {N} = new{T,N}(zeros(T, dims...), 1)
end

@forward MyArray => {
    Array{T, N} where {T<:Integer, N}
} [Base.size]

```

This is mainly to make the macro more flexible, and allow some future features.  
This way the same wrapper could be forwarded over different fields for a separate set of functions. And reduces the clutter around the struct definition.

Some primitive and naive type piracy check was introduces to retain some of the safety of the previous version. The macro will error if both the type and the functions are not defined within the same module the macro is used in.

The plan is also to allow for detection of manual ovverrides defined before the macro and to add some sort of re-wrapping behaviour although the API for that is not yet very clear.

The struct wrapping version might be reintroduced in the future, but for simplicity for now it only support the new API.

Cheers.
