代码之家  ›  专栏  ›  技术社区  ›  Frames Catherine White

对由“fieldnames”定义的值类型的调度是否完全由该类型的专门化决定?

  •  1
  • Frames Catherine White  · 技术社区  · 6 年前

    例子

    # Rules for how to combine various fields based on there names
    combine(::Val{:foo}, foo1, foo2) = foo1+foo2
    combine(::Val{:bar}, bar1, bar2) = bar2 - bar1
    combine(::Val{:boop}, boop1, boop2) = min(boop1, boop2)
    
    # combining 2 things of the same type
    
    
    function combine(aa::T, bb::T) where T
        T(combine.(
            [Val{fn}() for fn in fieldnames(T)],
            getfield.(Ref(aa), 1:nfields(T)),
            getfield.(Ref(bb), 1:nfields(T))
            )...)
    end
    

    我认为总的模式是有用的 T 有用吗。

    我的问题是,这将完全决定于 专门化(在编译时), 哪一级 combine 正在调用方法?

    演示

    julia> struct Flooper
               foo::Int
               bar::Int
           end
    
    
    julia> combine(Flooper(10,1), Flooper(3, 9))
    Flooper(13, 8)
    

    我正在努力阅读 @code_warntype .

    julia> @code_warntype combine(Flooper(10,1), Flooper(3, 9))
    Body::Any
    5 1 ── %1  = Base.Broadcast.materialize::typeof(Base.Broadcast.materialize)                             │
      │    %2  = new(Main.:(##5#6))::getfield(Main, Symbol("##5#6"))                                        │
      │    %3  = new(getfield(Base, Symbol("##9#10")){DataType}, :($(Expr(:static_parameter, 1))))::getfield(Base, Symbol("##9#10")){DataType}
      └───       goto 2 if not false                                                                        ││╻     fieldcount
      2 ┄─ %5  = π (false, Bool)                                                                            │││
      └───       goto 4 if not %5                                                                           │││
      3 ──       nothing                                                                                    │
      4 ┄─       goto 6 if not false                                                                        │││
      5 ──       nothing                                                                                    │
      6 ┄─ %10 = Base.not_int(true)::Bool                                                                   │││╻     !
      └───       goto 8 if not %10                                                                          │││
      7 ──       nothing                                                                                    │
      8 ┄─ %13 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
      │          Base.getfield(%13, :(:name))                                                               │││╻     getproperty
      │          Base.getfield(NamedTuple{names,T<:Tuple}, :(:name))                                        ││││
      └───       goto 10 if not false                                                                       │││
      9 ──       nothing                                                                                    │
      10 ┄ %18 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
      │    %19 = Base.getfield(%18, :(:abstract))::Bool                                                     │││╻     getproperty
      └───       goto 12 if not %19                                                                         │││
      11 ─       goto 14                                                                                    │││
      12 ─ %22 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
      │          Base.getfield(%22, :(:name))                                                               │││╻     getproperty
      │    %24 = Base.Tuple::Type{Tuple}                                                                    │││
      │          Base.getfield(%24, :(:name))                                                               │││╻     getproperty
      └───       goto 13 if not false                                                                       │││
      13 ┄ %27 = π (false, Bool)                                                                            │││
      14 ┄ %28 = φ (11 => %19, 13 => %27)::Bool                                                             ││
      └───       goto 17 if not %28                                                                         ││╻     fieldcount
      15 ─ %30 = new(Core.ErrorException, "type does not have a definite number of fields")::ErrorException │││╻╷    error
      │          Base.throw(%30)                                                                            ││││
      └───       unreachable                                                                                ││││
      16 ─       unreachable                                                                                │││
      17 ─ %34 = π (:($(Expr(:static_parameter, 1))), Type{Flooper})                                        │││
      │    %35 = Base.getfield(%34, :(:types))::Core.SimpleVector                                           │││╻     getproperty
      │    %36 = $(Expr(:gc_preserve_begin, Core.SSAValue(35)))                                             │││╻     length
      │    %37 = $(Expr(:foreigncall, :(:jl_value_ptr), Ptr{Nothing}, svec(Any), :(:ccall), 1, Core.SSAValue(35)))::Ptr{Nothing}om_objref
      │    %38 = Base.bitcast(Ptr{Int64}, %37)::Ptr{Int64}                                                  ││││╻     convert
      │    %39 = Base.pointerref(%38, 1, 1)::Int64                                                          │││││╻     unsafe_load
      │          $(Expr(:gc_preserve_end, Core.SSAValue(36)))                                               │││╻     length
      └───       goto 18                                                                                    │││
      18 ─ %42 = invoke Base.ntuple(%3::getfield(Base, Symbol("##9#10")){DataType}, %39::Int64)::Tuple      ││
      └───       goto 19                                                                                    ││
      19 ─ %44 = Base.Generator(%2, %42)::Base.Generator{_1,getfield(Main, Symbol("##5#6"))} where _1       │
      │    %45 = Base.collect(%44)::Any                                                                     │
      │    %46 = new(Base.RefValue{Flooper}, %%aa)::Base.RefValue{Flooper}                                  ││╻╷    Type
      │    %47 = Base.ifelse(true, 2, 0)::Int64                                                             ││╻╷    Type
      │    %48 = new(UnitRange{Int64}, 1, %47)::UnitRange{Int64}                                            │││
      │    %49 = Core.tuple(%46, %48)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}}                       │╻     broadcasted
      │    %50 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %49, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
      │    %51 = new(Base.RefValue{Flooper}, %%bb)::Base.RefValue{Flooper}                                  ││╻╷    Type
      │    %52 = Base.ifelse(true, 2, 0)::Int64                                                             ││╻╷    Type
      │    %53 = new(UnitRange{Int64}, 1, %52)::UnitRange{Int64}                                            │││
      │    %54 = Core.tuple(%51, %53)::Tuple{Base.RefValue{Flooper},UnitRange{Int64}}                       │╻     broadcasted
      │    %55 = new(Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}, getfield, %54, nothing)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1},Nothing,typeof(getfield),Tuple{Base.RefValue{Flooper},UnitRange{Int64}}}
      │    %56 = Main.combine::typeof(combine)                                                              │
      │    %57 = Base.Broadcast.broadcastable(%45)::Any                                                     │╻     broadcasted
      │    %58 = Base.Broadcast.combine_styles(%57)::Base.Broadcast.BroadcastStyle                          ││╻     combine_styles
      │    %59 = isa(%58, Base.Broadcast.DefaultArrayStyle{1})::Bool                                        │││
      └───       goto 21 if not %59                                                                         │││
      20 ─       goto 22                                                                                    │││
      21 ─ %62 = Base.Broadcast.result_style(%58, :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))))::Any│
      └───       goto 22                                                                                    │││
      22 ┄ %64 = φ (20 => :($(QuoteNode(Base.Broadcast.DefaultArrayStyle{1}()))), 21 => %62)::Any           │││
      └───       goto 23                                                                                    │││
      23 ─ %66 = Base.Broadcast.broadcasted(%64, %56, %57, %50, %55)::Any                                   ││
      └───       goto 24                                                                                    ││
      24 ─ %68 = %1(%66)::Any                                                                               │
      │    %69 = Core._apply(:($(Expr(:static_parameter, 1))), %68)::Any                                    │
      └───       return %69       
    

    我想另一种选择,如果在专门化过程中调用哪个方法不是完全确定的, @generated function . 但我宁愿不要,我不必。

    我对朱莉娅0.7的答案很感兴趣, (尽管0.6对于上下文来说很有趣,因为我怀疑在不同版本之间它有轻微的变化)

    0 回复  |  直到 6 年前