# Fixing the Piping/Chaining Issue

**URL:** <https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654>\
**Category:** Internals & Design\
**Tags:** proposal, piping, chaining, partial-evaluation, threading\
**Created:** [November 2, 2022, 11:04am UTC](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654 "2022-11-02T11:04:36Z")\
**Posts on this page:** 1\
**Showing post:** 191

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [November 10, 2022, 3:37am UTC](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654/191 "2022-11-10T03:37:58Z")

</div>

> [@aplavin](#):
>
> But for now I’m skeptical, given a huge amount of methods specifying few to no argument types.

Oops! It appears that calling `methodswith` on a parameterized type doesn’t give the methods of the unparameterized type! My autocomplete was failing to find any methods of `Vector` because it was being parameterized with the type of its contents.

> **See this example.**
>
> ```julia
> 
> julia> struct MyThing{T} end
> 
> julia> foo(::MyThing) = 1
> foo (generic function with 1 method)
> 
> julia> methodswith(MyThing)
> [1] foo(::MyThing) in Main at REPL[157]:1
> 
> julia> methodswith(MyThing{1})
> 
> julia> bar(::MyThing{1}) = 2
> bar (generic function with 1 method)
> 
> julia> methodswith(MyThing)
> [1] foo(::MyThing) in Main at REPL[157]:1
> 
> julia> methodswith(MyThing{1})
> [1] bar(::MyThing{1}) in Main at REPL[160]:1
> 
> ```

As a result, because an object such as `[(a=1,)]` is of type `Vector{NamedTuple{(:a,), Tuple{Int64}}}`, none of the methods of `Vector` appear.

I’ve rewritten it so it’ll ~~detect if there are no methods of the parameterized type, and if so, give methods of the unparameterized type (with special case handling for vectors). I think it’ll have poor behavior in some particular case, but for a quick hack I think it’s not too bad. Might consider doing something more sophisticated later.~~ find methods of the parameterized type, and append methods of the unparameterized type with special case handling for vectors and matrices.

> **Here's the code now.**
>
> ```julia
> 
> function propose_method_autocompletions(obj, func_name_fragment::String=""; 
> type_depth = 1:typemax(Int), only_same_module = false, only_imported_modules = false,
> arg_order_inference = false, github_inference = false, personalized_inference = false)::Vector{Method}
> 
> @assert first(type_depth) ≥ 1 && last(type_depth) ≥ 1
> recs = Vector{Method}[]
> get_type_at_depth(type, depth=1) = depth ≤ 1 ? type : type == Any ? nothing : get_type_at_depth(supertype(type), depth-1)
> 
> for i ∈ type_depth
> stype = get_type_at_depth(typeof(obj), i)
> isnothing(stype) && break
> 
> meths = methodswith(stype)
> if !(stype isa UnionAll) && length(stype.parameters) > 0
> if stype <: AbstractVector # special case handling for vectors
> meths = [meths; methodswith(getfield(parentmodule(stype), nameof(stype)){T,1} where T)]
> elseif stype <: AbstractMatrix
> meths = [meths; methodswith(getfield(parentmodule(stype), nameof(stype)){T,2} where T)]
> end
> meths = [meths; methodswith(getfield(parentmodule(stype), nameof(stype)))]
> end
> 
> meths = filter(meths) do m
> length(func_name_fragment) > length(string(m.name)) && return false
> string(m.name)[1:length(func_name_fragment)] == func_name_fragment || return false
> only_same_module && (parentmodule(typeof(obj)) == m.module || return false)
> # How to detect only modules that have been explicitly imported?
> true
> end
> 
> arg_order_inference || true # do cool sorting stuff, add later
> github_inference || true # do cool sorting stuff, add later
> personalized_inference || true # do cool sorting stuff, add later
> 
> recs = [recs; meths]
> end
> 
> recs
> end
> 
> ```

Calling it on the object of `[(a=1,)]`:

```julia

julia> propose_method_autocompletions([(a=1,)])
[1] CapturedException(ex, bt_raw::Vector) in Base at task.jl:12
[2] \(A::LinearAlgebra.Transpose{<:Complex, <:LinearAlgebra.Hermitian{<:Complex, <:SparseArrays.AbstractSparseMatrixCSC}}, B::Vector) in SparseArrays at C:\Users\unime\AppData\Local\Programs\Julia-1.8.0\share\julia\stdlib\v1.8\SparseArrays\src\linalg.jl:872
[3] \(L::SuiteSparse.CHOLMOD.FactorComponent, b::Vector) in SuiteSparse.CHOLMOD at C:\Users\unime\AppData\Local\Programs\Julia-1.8.0\share\julia\stdlib\v1.8\SuiteSparse\src\cholmod.jl:1521
[4] append!(a::Vector, items::AbstractVector) in Base at array.jl:1105
[5] deleteat!(a::Vector, i::Integer) in Base at array.jl:1485
[6] deleteat!(a::Vector, r::AbstractUnitRange{<:Integer}) in Base at array.jl:1491
[7] deleteat!(a::Vector, inds::AbstractVector{Bool}) in Base at array.jl:1590
[8] deleteat!(a::Vector, inds::AbstractVector) in Base at array.jl:1533
[9] deleteat!(a::Vector, inds) in Base at array.jl:1532
[10] empty!(a::Vector) in Base at array.jl:1738

⋮

[3209] groupview(f, X; restype, kwargs...) in FlexiGroups at C:\Users\unime\.julia\packages\FlexiGroups\1ItB2\src\base.jl:41

```

Beyond that, for _truly_ generic methods that don’t specialize on _anything_, whose behavior can be thought of as really generalizable across _any_ object, they shouldn’t float to the top of such a simple autocomplete anyway; if a method is general enough not to specialize on any type, it’s probably general enough to have memorized.

It’s possible to make them float to the top anyway, using a sorting technique based on statistical inference of a model fitted to a codebase (imagine if you could train your autocomplete to your own codebase!), but I’m not going to make that at the moment.

Without such inference built-in, for methods to gain visibility, they need to be specialized to such types as `AbstractArray`, `AbstractDict`, or etc.

---

_[View the full topic](https://discourse.julialang.org/t/fixing-the-piping-chaining-issue/89654)._
