From 6e6dca316687abba31eff3c7aaa705317bd0c900 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Mon, 6 Jan 2025 18:15:59 +0000 Subject: [PATCH 1/4] Fix docstring formatting --- src/fwds_rvs_data.jl | 12 +-- src/test_utils.jl | 136 ++++++++++++------------ src/tools_for_rules.jl | 232 ++++++++++++++++++++--------------------- 3 files changed, 190 insertions(+), 190 deletions(-) diff --git a/src/fwds_rvs_data.jl b/src/fwds_rvs_data.jl index 02b69ca6c..de70b5467 100644 --- a/src/fwds_rvs_data.jl +++ b/src/fwds_rvs_data.jl @@ -396,15 +396,15 @@ fields_type(::Type{RData{T}}) where {T<:NamedTuple} = T return RData(increment_field!!(x.data, new_val, Val(f))) end -@doc """ - rdata_type(T) +""" + rdata_type(T) - Returns the type of the reverse data of a tangent of type T. +Returns the type of the reverse data of a tangent of type T. - # Extended help +# Extended help - See extended help in [`fdata_type`](@ref) docstring. - """ +See extended help in [`fdata_type`](@ref) docstring. +""" rdata_type(T) rdata_type(x) = throw(error("$x is not a type. Perhaps you meant typeof(x)?")) diff --git a/src/test_utils.jl b/src/test_utils.jl index 579795f5c..58a48463d 100644 --- a/src/test_utils.jl +++ b/src/test_utils.jl @@ -565,65 +565,65 @@ end __get_primals(xs) = map(x -> x isa CoDual ? primal(x) : x, xs) -@doc """ - test_rule( - rng, x...; - interface_only=false, - is_primitive::Bool=true, - perf_flag::Symbol=:none, - interp::Mooncake.MooncakeInterpreter=Mooncake.get_interpreter(), - debug_mode::Bool=false, - unsafe_perturb::Bool=false, - ) - - Run standardised tests on the `rule` for `x`. - The first element of `x` should be the primal function to test, and each other element a - positional argument. - In most cases, elements of `x` can just be the primal values, and `randn_tangent` can be - relied upon to generate an appropriate tangent to test. Some notable exceptions exist - though, in partcular `Ptr`s. In this case, the argument for which `randn_tangent` cannot be - readily defined should be a `CoDual` containing the primal, and a _manually_ constructed - tangent field. - - This function uses [`Mooncake.build_rrule`](@ref) to construct a rule. This will use an - `rrule!!` if one exists, and derive a rule otherwise. - - # Arguments - - `rng::AbstractRNG`: a random number generator - - `x...`: the function (first element) and its arguments (the remainder) - - # Keyword Arguments - - `interface_only::Bool=false`: test only that the interface is satisfied, without testing - correctness. This should generally be set to `false` (the default value), and only - enabled if the testing infrastructure is unable to test correctness for some reason - e.g. the returned value of the function is a `Ptr`, and appropriate tangents cannot, - therefore, be generated for it automatically. - - `is_primitive::Bool=true`: check whether the thing that you are testing has a hand-written - `rrule!!`. This option is helpful if you are testing a new `rrule!!`, as it enables you - to verify that your method of `is_primitive` has returned the correct value, and that - you are actually testing a method of the `rrule!!` function -- a common mistake when - authoring a new `rrule!!` is to implement `is_primitive` incorrectly and to accidentally - wind up testing a rule which Mooncake has derived, as opposed to the one that you have - written. If you are testing something for which you have not - hand-written an `rrule!!`, or which you do not care whether it has a hand-written - `rrule!!` or not, you should set it to `false`. - - `perf_flag::Symbol=:none`: the value of this symbol determines what kind of performance - tests should be performed. By default, none are performed. If you believe that a rule - should be allocation-free (iff the primal is allocation free), set this to `:allocs`. If - you hand-write an `rrule!!` and believe that your test case should be type stable, set - this to `:stability` (at present we cannot verify whether a derived rule is type stable - for technical reasons). If you believe that a hand-written rule should be _both_ - allocation-free and type-stable, set this to `:stability_and_allocs`. - - `interp::Mooncake.MooncakeInterpreter=Mooncake.get_interpreter()`: the abstract - interpreter to be used when testing this rule. The default should generally be used. - - `debug_mode::Bool=false`: whether or not the rule should be tested in debug mode. - Typically this should be left at its default `false` value, but if you are finding that - the tests are failing for a given rule, you may wish to temporarily set it to `true` in - order to get access to additional information and automated testing. - - `unsafe_perturb::Bool=false`: value passed as the third argument to `_add_to_primal`. - Should usually be left `false` -- consult the docstring for `_add_to_primal` for more - info on when you might wish to set it to `true`. - """ +""" + test_rule( + rng, x...; + interface_only=false, + is_primitive::Bool=true, + perf_flag::Symbol=:none, + interp::Mooncake.MooncakeInterpreter=Mooncake.get_interpreter(), + debug_mode::Bool=false, + unsafe_perturb::Bool=false, + ) + +Run standardised tests on the `rule` for `x`. +The first element of `x` should be the primal function to test, and each other element a +positional argument. +In most cases, elements of `x` can just be the primal values, and `randn_tangent` can be +relied upon to generate an appropriate tangent to test. Some notable exceptions exist +though, in partcular `Ptr`s. In this case, the argument for which `randn_tangent` cannot be +readily defined should be a `CoDual` containing the primal, and a _manually_ constructed +tangent field. + +This function uses [`Mooncake.build_rrule`](@ref) to construct a rule. This will use an +`rrule!!` if one exists, and derive a rule otherwise. + +# Arguments +- `rng::AbstractRNG`: a random number generator +- `x...`: the function (first element) and its arguments (the remainder) + +# Keyword Arguments +- `interface_only::Bool=false`: test only that the interface is satisfied, without testing + correctness. This should generally be set to `false` (the default value), and only + enabled if the testing infrastructure is unable to test correctness for some reason + e.g. the returned value of the function is a `Ptr`, and appropriate tangents cannot, + therefore, be generated for it automatically. +- `is_primitive::Bool=true`: check whether the thing that you are testing has a hand-written + `rrule!!`. This option is helpful if you are testing a new `rrule!!`, as it enables you + to verify that your method of `is_primitive` has returned the correct value, and that + you are actually testing a method of the `rrule!!` function -- a common mistake when + authoring a new `rrule!!` is to implement `is_primitive` incorrectly and to accidentally + wind up testing a rule which Mooncake has derived, as opposed to the one that you have + written. If you are testing something for which you have not + hand-written an `rrule!!`, or which you do not care whether it has a hand-written + `rrule!!` or not, you should set it to `false`. +- `perf_flag::Symbol=:none`: the value of this symbol determines what kind of performance + tests should be performed. By default, none are performed. If you believe that a rule + should be allocation-free (iff the primal is allocation free), set this to `:allocs`. If + you hand-write an `rrule!!` and believe that your test case should be type stable, set + this to `:stability` (at present we cannot verify whether a derived rule is type stable + for technical reasons). If you believe that a hand-written rule should be _both_ + allocation-free and type-stable, set this to `:stability_and_allocs`. +- `interp::Mooncake.MooncakeInterpreter=Mooncake.get_interpreter()`: the abstract + interpreter to be used when testing this rule. The default should generally be used. +- `debug_mode::Bool=false`: whether or not the rule should be tested in debug mode. + Typically this should be left at its default `false` value, but if you are finding that + the tests are failing for a given rule, you may wish to temporarily set it to `true` in + order to get access to additional information and automated testing. +- `unsafe_perturb::Bool=false`: value passed as the third argument to `_add_to_primal`. + Should usually be left `false` -- consult the docstring for `_add_to_primal` for more + info on when you might wish to set it to `true`. +""" function test_rule( rng::AbstractRNG, x...; @@ -1077,18 +1077,18 @@ function __is_completely_stable_type(::Type{P}) where {P} return all(__is_completely_stable_type, fieldtypes(P)) end -@doc """ - test_tangent(rng::AbstractRNG, p::P, x::T, y::T, z_target::T) where {P, T} +""" + test_tangent(rng::AbstractRNG, p::P, x::T, y::T, z_target::T) where {P, T} - Verify that primal `p` with tangents `z_target`, `x`, and `y`, satisfies the tangent - interface. If these tests pass, then it should be possible to write rules for primals - of type `P`, and to test them using [`test_rule`](@ref). +Verify that primal `p` with tangents `z_target`, `x`, and `y`, satisfies the tangent +interface. If these tests pass, then it should be possible to write rules for primals +of type `P`, and to test them using [`test_rule`](@ref). - It should be the case that `z_target` == `increment!!(x, y)`. +It should be the case that `z_target` == `increment!!(x, y)`. - As always, there are limits to the errors that these tests can identify -- they form - necessary but not sufficient conditions for the correctness of your code. - """ +As always, there are limits to the errors that these tests can identify -- they form +necessary but not sufficient conditions for the correctness of your code. +""" function test_tangent( rng::AbstractRNG, p::P, x::T, y::T, z_target::T; interface_only, perf=true ) where {P,T} diff --git a/src/tools_for_rules.jl b/src/tools_for_rules.jl index 65ee34368..186df35e0 100644 --- a/src/tools_for_rules.jl +++ b/src/tools_for_rules.jl @@ -254,30 +254,30 @@ function increment_and_get_rdata!(f, r, t::CRC.Thunk) return increment_and_get_rdata!(f, r, CRC.unthunk(t)) end -@doc """ - rrule_wrapper(f::CoDual, args::CoDual...) - - Used to implement `rrule!!`s via `ChainRulesCore.rrule`. - - Given a function `foo`, argument types `arg_types`, and a method of `ChainRulesCore.rrule` - which applies to these, you can make use of this function as follows: - ```julia - Mooncake.@is_primitive DefaultCtx Tuple{typeof(foo), arg_types...} - function Mooncake.rrule!!(f::CoDual{typeof(foo)}, args::CoDual...) - return rrule_wrapper(f, args...) - end - ``` - Assumes that methods of `to_cr_tangent` and `to_mooncake_tangent` are defined such that you - can convert between the different representations of tangents that Mooncake and - ChainRulesCore expect. - - Furthermore, it is _essential_ that - 1. `f(args)` does not mutate `f` or `args`, and - 2. the result of `f(args)` does not alias any data stored in `f` or `args`. - - Subject to some constraints, you can use the [`@from_rrule`](@ref) macro to reduce the - amount of boilerplate code that you are required to write even further. - """ +""" + rrule_wrapper(f::CoDual, args::CoDual...) + +Used to implement `rrule!!`s via `ChainRulesCore.rrule`. + +Given a function `foo`, argument types `arg_types`, and a method of `ChainRulesCore.rrule` +which applies to these, you can make use of this function as follows: +```julia +Mooncake.@is_primitive DefaultCtx Tuple{typeof(foo), arg_types...} +function Mooncake.rrule!!(f::CoDual{typeof(foo)}, args::CoDual...) + return rrule_wrapper(f, args...) +end +``` +Assumes that methods of `to_cr_tangent` and `to_mooncake_tangent` are defined such that you +can convert between the different representations of tangents that Mooncake and +ChainRulesCore expect. + +Furthermore, it is _essential_ that +1. `f(args)` does not mutate `f` or `args`, and +2. the result of `f(args)` does not alias any data stored in `f` or `args`. + +Subject to some constraints, you can use the [`@from_rrule`](@ref) macro to reduce the +amount of boilerplate code that you are required to write even further. +""" function rrule_wrapper(fargs::Vararg{CoDual,N}) where {N} # Run forwards-pass. @@ -333,119 +333,119 @@ function construct_rrule_wrapper_def(arg_names, arg_types, where_params) return construct_def(arg_names, arg_types, where_params, body) end -@doc """ - @from_rrule ctx sig [has_kwargs=false] +""" + @from_rrule ctx sig [has_kwargs=false] - Convenience functionality to assist in using `ChainRulesCore.rrule`s to write `rrule!!`s. +Convenience functionality to assist in using `ChainRulesCore.rrule`s to write `rrule!!`s. - # Arguments +# Arguments - - `ctx`: A Mooncake context type - - `sig`: the signature which you wish to assert should be a primitive in `Mooncake.jl`, and - use an existing `ChainRulesCore.rrule` to implement this functionality. - - `has_kwargs`: a `Bool` state whether or not the function has keyword arguments. This - feature has the same limitations as `ChainRulesCore.rrule` -- the derivative w.r.t. all - kwargs must be zero. +- `ctx`: A Mooncake context type +- `sig`: the signature which you wish to assert should be a primitive in `Mooncake.jl`, and + use an existing `ChainRulesCore.rrule` to implement this functionality. +- `has_kwargs`: a `Bool` state whether or not the function has keyword arguments. This + feature has the same limitations as `ChainRulesCore.rrule` -- the derivative w.r.t. all + kwargs must be zero. - # Example Usage +# Example Usage - ## A Basic Example +## A Basic Example - ```jldoctest - julia> using Mooncake: @from_rrule, DefaultCtx, rrule!!, zero_fcodual, TestUtils +```jldoctest +julia> using Mooncake: @from_rrule, DefaultCtx, rrule!!, zero_fcodual, TestUtils - julia> using ChainRulesCore +julia> using ChainRulesCore - julia> foo(x::Real) = 5x; +julia> foo(x::Real) = 5x; - julia> function ChainRulesCore.rrule(::typeof(foo), x::Real) - foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), 5Ω - return foo(x), foo_pb - end; +julia> function ChainRulesCore.rrule(::typeof(foo), x::Real) + foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), 5Ω + return foo(x), foo_pb + end; - julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} +julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} - julia> rrule!!(zero_fcodual(foo), zero_fcodual(5.0))[2](1.0) - (NoRData(), 5.0) +julia> rrule!!(zero_fcodual(foo), zero_fcodual(5.0))[2](1.0) +(NoRData(), 5.0) - julia> # Check that the rule works as intended. - TestUtils.test_rule(Xoshiro(123), foo, 5.0; is_primitive=true) - Test Passed - ``` +julia> # Check that the rule works as intended. + TestUtils.test_rule(Xoshiro(123), foo, 5.0; is_primitive=true) +Test Passed +``` - ## An Example with Keyword Arguments +## An Example with Keyword Arguments - ```jldoctest - julia> using Mooncake: @from_rrule, DefaultCtx, rrule!!, zero_fcodual, TestUtils +```jldoctest +julia> using Mooncake: @from_rrule, DefaultCtx, rrule!!, zero_fcodual, TestUtils - julia> using ChainRulesCore +julia> using ChainRulesCore - julia> foo(x::Real; cond::Bool) = cond ? 5x : 4x; +julia> foo(x::Real; cond::Bool) = cond ? 5x : 4x; - julia> function ChainRulesCore.rrule(::typeof(foo), x::Real; cond::Bool) - foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), cond ? 5Ω : 4Ω - return foo(x; cond), foo_pb - end; +julia> function ChainRulesCore.rrule(::typeof(foo), x::Real; cond::Bool) + foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), cond ? 5Ω : 4Ω + return foo(x; cond), foo_pb + end; - julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} true +julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} true - julia> _, pb = rrule!!( - zero_fcodual(Core.kwcall), - zero_fcodual((cond=false, )), - zero_fcodual(foo), - zero_fcodual(5.0), - ); +julia> _, pb = rrule!!( + zero_fcodual(Core.kwcall), + zero_fcodual((cond=false, )), + zero_fcodual(foo), + zero_fcodual(5.0), + ); - julia> pb(3.0) - (NoRData(), NoRData(), NoRData(), 12.0) +julia> pb(3.0) +(NoRData(), NoRData(), NoRData(), 12.0) - julia> # Check that the rule works as intended. - TestUtils.test_rule( - Xoshiro(123), Core.kwcall, (cond=false, ), foo, 5.0; is_primitive=true - ) - Test Passed - ``` - Notice that, in order to access the kwarg method we must call the method of `Core.kwcall`, - as Mooncake's `rrule!!` does not itself permit the use of kwargs. - - # Limitations - - It is your responsibility to ensure that - 1. calls with signature `sig` do not mutate their arguments, - 2. the output of calls with signature `sig` does not alias any of the inputs. - - As with all hand-written rules, you should definitely make use of - [`TestUtils.test_rule`](@ref) to verify correctness on some test cases. - - # Argument Type Constraints - - Many methods of `ChainRuleCore.rrule` are implemented with very loose type constraints. - For example, it would not be surprising to see a method of rrule with the signature - ```julia - Tuple{typeof(rrule), typeof(foo), Real, AbstractVector{<:Real}} - ``` - There are a variety of reasons for this way of doing things, and whether it is a good idea - to write rules for such generic objects has been debated at length. - - Suffice it to say, you should not write rules for _this_ package which are so generically - typed. - Rather, you should create rules for the subset of types for which you believe that the - `ChainRulesCore.rrule` will work correctly, and leave this package to derive rules for the - rest. - For example, it is quite common to be confident that a given rule will work correctly for - any `Base.IEEEFloat` argument, i.e. `Union{Float16, Float32, Float64}`, but it is usually - not possible to know that the rule is correct for all possible subtypes of `Real` that - someone might define. - - # Conversions Between Different Tangent Type Systems - - Under the hood, this functionality relies on two functions: `Mooncake.to_cr_tangent`, and - `Mooncake.increment_and_get_rdata!`. These two functions handle conversion to / from - `Mooncake` tangent types and `ChainRulesCore` tangent types. This functionality is known to - work well for simple types, but has not been tested to a great extent on complicated - composite types. If `@from_rrule` does not work in your case because the required method of - either of these functions does not exist, please open an issue. - """ +julia> # Check that the rule works as intended. + TestUtils.test_rule( + Xoshiro(123), Core.kwcall, (cond=false, ), foo, 5.0; is_primitive=true + ) +Test Passed +``` +Notice that, in order to access the kwarg method we must call the method of `Core.kwcall`, +as Mooncake's `rrule!!` does not itself permit the use of kwargs. + +# Limitations + +It is your responsibility to ensure that +1. calls with signature `sig` do not mutate their arguments, +2. the output of calls with signature `sig` does not alias any of the inputs. + +As with all hand-written rules, you should definitely make use of +[`TestUtils.test_rule`](@ref) to verify correctness on some test cases. + +# Argument Type Constraints + +Many methods of `ChainRuleCore.rrule` are implemented with very loose type constraints. +For example, it would not be surprising to see a method of rrule with the signature +```julia +Tuple{typeof(rrule), typeof(foo), Real, AbstractVector{<:Real}} +``` +There are a variety of reasons for this way of doing things, and whether it is a good idea +to write rules for such generic objects has been debated at length. + +Suffice it to say, you should not write rules for _this_ package which are so generically +typed. +Rather, you should create rules for the subset of types for which you believe that the +`ChainRulesCore.rrule` will work correctly, and leave this package to derive rules for the +rest. +For example, it is quite common to be confident that a given rule will work correctly for +any `Base.IEEEFloat` argument, i.e. `Union{Float16, Float32, Float64}`, but it is usually +not possible to know that the rule is correct for all possible subtypes of `Real` that +someone might define. + +# Conversions Between Different Tangent Type Systems + +Under the hood, this functionality relies on two functions: `Mooncake.to_cr_tangent`, and +`Mooncake.increment_and_get_rdata!`. These two functions handle conversion to / from +`Mooncake` tangent types and `ChainRulesCore` tangent types. This functionality is known to +work well for simple types, but has not been tested to a great extent on complicated +composite types. If `@from_rrule` does not work in your case because the required method of +either of these functions does not exist, please open an issue. +""" macro from_rrule(ctx, sig::Expr, has_kwargs::Bool=false) arg_type_syms, where_params = parse_signature_expr(sig) arg_names = map(n -> Symbol("x_$n"), eachindex(arg_type_syms)) From 3d22a1bef2f70538526c214c24dca3e199d053d6 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Mon, 6 Jan 2025 18:16:27 +0000 Subject: [PATCH 2/4] Bump patch --- Project.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Project.toml b/Project.toml index a1f1a2ec9..fc43c7bb3 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "Mooncake" uuid = "da2b9cff-9c12-43a0-ae48-6db2b0edb7d6" authors = ["Will Tebbutt, Hong Ge, and contributors"] -version = "0.4.70" +version = "0.4.71" [deps] ADTypes = "47edcb42-4c32-4615-8424-f2b9edc5f35b" From 74a13c542f0cf679348712acc7ea5a8b23c705cc Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Mon, 6 Jan 2025 19:05:17 +0000 Subject: [PATCH 3/4] Fix doctest formatting --- src/tools_for_rules.jl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/tools_for_rules.jl b/src/tools_for_rules.jl index 186df35e0..2a64d5512 100644 --- a/src/tools_for_rules.jl +++ b/src/tools_for_rules.jl @@ -359,9 +359,9 @@ julia> using ChainRulesCore julia> foo(x::Real) = 5x; julia> function ChainRulesCore.rrule(::typeof(foo), x::Real) - foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), 5Ω - return foo(x), foo_pb - end; + foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), 5Ω + return foo(x), foo_pb + end; julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} @@ -383,9 +383,9 @@ julia> using ChainRulesCore julia> foo(x::Real; cond::Bool) = cond ? 5x : 4x; julia> function ChainRulesCore.rrule(::typeof(foo), x::Real; cond::Bool) - foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), cond ? 5Ω : 4Ω - return foo(x; cond), foo_pb - end; + foo_pb(Ω::Real) = ChainRulesCore.NoTangent(), cond ? 5Ω : 4Ω + return foo(x; cond), foo_pb + end; julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} true From 9370f202c71c46d627da2eefb2b0f2c45f0b7739 Mon Sep 17 00:00:00 2001 From: Will Tebbutt Date: Mon, 6 Jan 2025 19:55:26 +0000 Subject: [PATCH 4/4] More fixes --- src/tools_for_rules.jl | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/tools_for_rules.jl b/src/tools_for_rules.jl index 2a64d5512..8561735ee 100644 --- a/src/tools_for_rules.jl +++ b/src/tools_for_rules.jl @@ -369,7 +369,7 @@ julia> rrule!!(zero_fcodual(foo), zero_fcodual(5.0))[2](1.0) (NoRData(), 5.0) julia> # Check that the rule works as intended. - TestUtils.test_rule(Xoshiro(123), foo, 5.0; is_primitive=true) + TestUtils.test_rule(Xoshiro(123), foo, 5.0; is_primitive=true) Test Passed ``` @@ -390,19 +390,19 @@ julia> function ChainRulesCore.rrule(::typeof(foo), x::Real; cond::Bool) julia> @from_rrule DefaultCtx Tuple{typeof(foo), Base.IEEEFloat} true julia> _, pb = rrule!!( - zero_fcodual(Core.kwcall), - zero_fcodual((cond=false, )), - zero_fcodual(foo), - zero_fcodual(5.0), - ); + zero_fcodual(Core.kwcall), + zero_fcodual((cond=false, )), + zero_fcodual(foo), + zero_fcodual(5.0), + ); julia> pb(3.0) (NoRData(), NoRData(), NoRData(), 12.0) julia> # Check that the rule works as intended. - TestUtils.test_rule( - Xoshiro(123), Core.kwcall, (cond=false, ), foo, 5.0; is_primitive=true - ) + TestUtils.test_rule( + Xoshiro(123), Core.kwcall, (cond=false, ), foo, 5.0; is_primitive=true + ) Test Passed ``` Notice that, in order to access the kwarg method we must call the method of `Core.kwcall`,