创建一个行为类似于其他类型的基本类型

时间:2020-10-28 12:54:54

标签: julia

我想创建一个行为类似于primitive type,但命名为Int64的{​​{1}}。这可能吗?

我了解到here我可以做这样的事情

Foo

但是我不明白为什么,即使# Declare the new type. primitive type MyInt8 <: Signed 8 end # A constructor to create values of the type MyInt8. MyInt8(x :: Int8) = reinterpret(MyInt8, x) # A constructor to convert back. Int8(x :: MyInt8) = reinterpret(Int8, x) # This allows the REPL to show values of type MyInt8. Base.show(io :: IO, x :: MyInt8) = print(io, Int8(x)) MyInt8Signed)的子类型,也没有用于该类型的方法:

MyInt8 <: Signed

我认为原始类型作为子类型也会自动“获得”超类型的所有方法。

我在哪里错了?

1 个答案:

答案 0 :(得分:3)

作为Signed的子类型,MyInt8 确实自动“获取”为数字定义的所有方法。实际上有很多:

julia> methodswith(MyInt8, supertypes=true) |> length
1218

julia> methodswith(MyInt8, supertypes=true)[1:10]
[1] poll_fd(s::RawFD, timeout_s::Real; readable, writable) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:649
[2] poll_file(s::AbstractString, interval_seconds::Real) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:784
[3] poll_file(s::AbstractString, interval_seconds::Real, timeout_s::Real) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:784
[4] watch_file(s::AbstractString, timeout_s::Real) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:687
[5] watch_folder(s::String, timeout_s::Real) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:716
[6] watch_folder(s::AbstractString, timeout_s::Real) in FileWatching at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/FileWatching/src/FileWatching.jl:715
[7] randcycle(r::Random.AbstractRNG, n::T) where T<:Integer in Random at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/Random/src/misc.jl:348
[8] randcycle(n::Integer) in Random at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/Random/src/misc.jl:349
[9] randexp(rng::Random.AbstractRNG, ::Type{T}, dim1::Integer, dims::Integer...) where T in Random at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/Random/src/normal.jl:204
[10] randperm(r::Random.AbstractRNG, n::T) where T<:Integer in Random at /home/francois/.local/julia-1.5.2/share/julia/stdlib/v1.5/Random/src/misc.jl:282

其中一些不需要MyInt8符合任何特定的接口,并且可以“开箱即用”地工作:

julia> a = MyInt8(Int8(3))
3

julia> conj(a)
3

但是有些人会提供依赖MyInt8且符合接口的实现:

# Here `imag` does not know how to build a zero of the MyInt8 type
julia> imag(a)
ERROR: MethodError: no method matching MyInt8(::Int64)
Closest candidates are:
  MyInt8(::T) where T<:Number at boot.jl:716
  MyInt8(::Int8) at REPL[7]:2
  MyInt8(::Float16) where T<:Integer at float.jl:71
  ...
Stacktrace:
 [1] convert(::Type{MyInt8}, ::Int64) at ./number.jl:7
 [2] oftype(::MyInt8, ::Int64) at ./essentials.jl:367
 [3] zero(::MyInt8) at ./number.jl:241
 [4] imag(::MyInt8) at ./complex.jl:78
 [5] top-level scope at REPL[37]:1

添加项属于最后一个类别:

# There is indeed a generic implementation that MyInt8 inherits
julia> which(+, (MyInt8, MyInt8))
+(a::Integer, b::Integer) in Base at int.jl:918

# But it relies on promotion features, which are not implemented for MyInt8
julia> a + a
ERROR: promotion of types MyInt8 and MyInt8 failed to change any arguments
Stacktrace:
 [1] error(::String, ::String, ::String) at ./error.jl:42
 [2] sametype_error(::Tuple{MyInt8,MyInt8}) at ./promotion.jl:306
 [3] not_sametype(::Tuple{MyInt8,MyInt8}, ::Tuple{MyInt8,MyInt8}) at ./promotion.jl:300
 [4] +(::MyInt8, ::MyInt8) at ./int.jl:921
 [5] top-level scope at REPL[41]:1

在那种特殊情况下,+的继承实现仅用于处理两个不同类型的操作数的加法;我猜您将不得不为+自己实现MyInt8,与Int8实现自己的附加功能大致相同:

julia> which(+, (Int8, Int8))
+(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:86

我可能会去执行类似以下的实现:

julia> Base.:+(a::MyInt8, b::MyInt8) = MyInt8(Int8(a)+Int8(b))

julia> a + a
6

编辑:

这应该达到与本机Int8类型相同的性能:

# two Int8 vectors
julia> a1 = rand(Int8, 1000); b1 = rand(Int8, 1000);

# same vectors, as MyInt8 values
julia> a2 = MyInt8.(a1);      b2 = MyInt8.(b1);

# check that both ways of doing the calculation produce the same results
julia> @assert a1 .+ b1 == Int8.(a2 .+ b2)

# Benchmark
julia> using BenchmarkTools
julia> @benchmark $a1 .+ $b1
BenchmarkTools.Trial: 
  memory estimate:  1.06 KiB
  allocs estimate:  1
  --------------
  minimum time:     145.274 ns (0.00% GC)
  median time:      176.402 ns (0.00% GC)
  mean time:        200.996 ns (4.20% GC)
  maximum time:     1.349 μs (79.34% GC)
  --------------
  samples:          10000
  evals/sample:     759

julia> @benchmark $a2 .+ $b2
BenchmarkTools.Trial: 
  memory estimate:  1.06 KiB
  allocs estimate:  1
  --------------
  minimum time:     140.316 ns (0.00% GC)
  median time:      172.119 ns (0.00% GC)
  mean time:        195.947 ns (4.54% GC)
  maximum time:     1.148 μs (73.34% GC)
  --------------
  samples:          10000
  evals/sample:     750