Skip to content

Commit

Permalink
deprecate convert-to-construct fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
JeffBezanson committed Dec 13, 2017
1 parent f965a87 commit 002fb2f
Show file tree
Hide file tree
Showing 48 changed files with 414 additions and 405 deletions.
6 changes: 5 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Language changes
* The syntax for parametric methods, `function f{T}(x::T)`, has been
changed to `function f(x::T) where {T}` ([#11310]).

* The fallback constructor that calls `convert` is deprecated. Instead, new types should
prefer to define constructors, and add `convert` methods that call those constructors
only as necessary ([#15120]).

* The syntax `1.+2` is deprecated, since it is ambiguous: it could mean either
`1 .+ 2` (the current meaning) or `1. + 2` ([#19089]).

Expand Down Expand Up @@ -1721,4 +1725,4 @@ Command-line option changes
[#24413]: https://github.com/JuliaLang/julia/issues/24413
[#24653]: https://github.com/JuliaLang/julia/issues/24653
[#24869]: https://github.com/JuliaLang/julia/issues/24869
[#25021]: https://github.com/JuliaLang/julia/issues/25021
[#25021]: https://github.com/JuliaLang/julia/issues/25021
19 changes: 11 additions & 8 deletions base/abstractarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@ Supertype for `N`-dimensional arrays (or array-like types) with elements of type
"""
AbstractArray

convert(::Type{T}, a::T) where {T<:AbstractArray} = a
convert(::Type{T}, a::AbstractArray) where {T<:AbstractArray} = T(a)

if module_name(@__MODULE__) === :Base # avoid method overwrite
# catch undefined constructors before the deprecation kicks in
# TODO: remove when deprecation is removed
function (::Type{T})(arg) where {T<:AbstractArray}
throw(MethodError(T, (arg,)))
end
end

"""
size(A::AbstractArray, [dim...])
Expand Down Expand Up @@ -856,14 +867,6 @@ isempty(a::AbstractArray) = (_length(a) == 0)
# keys with an IndexStyle
keys(s::IndexStyle, A::AbstractArray, B::AbstractArray...) = eachindex(s, A, B...)

## Conversions ##

convert(::Type{AbstractArray{T,N}}, A::AbstractArray{T,N}) where {T,N } = A
convert(::Type{AbstractArray{T,N}}, A::AbstractArray{S,N}) where {T,S,N} = copy!(similar(A,T), A)
convert(::Type{AbstractArray{T}}, A::AbstractArray{S,N}) where {T,S,N} = convert(AbstractArray{T,N}, A)

convert(::Type{Array}, A::AbstractArray{T,N}) where {T,N} = convert(Array{T,N}, A)

"""
of_indices(x, y)
Expand Down
41 changes: 23 additions & 18 deletions base/array.jl
Original file line number Diff line number Diff line change
Expand Up @@ -396,21 +396,14 @@ oneunit(x::AbstractMatrix{T}) where {T} = _one(oneunit(T), x)
# arises in similar(dest, Pair{Union{},Union{}}) where dest::Dict:
convert(::Type{Vector{Union{}}}, a::Vector{Union{}}) = a

convert(::Type{Vector}, x::AbstractVector{T}) where {T} = convert(Vector{T}, x)
convert(::Type{Matrix}, x::AbstractMatrix{T}) where {T} = convert(Matrix{T}, x)

convert(::Type{Array{T}}, x::Array{T,n}) where {T,n} = x
convert(::Type{Array{T,n}}, x::Array{T,n}) where {T,n} = x

convert(::Type{Array{T}}, x::AbstractArray{S,n}) where {T,n,S} = convert(Array{T,n}, x)
convert(::Type{Array{T,n}}, x::AbstractArray{S,n}) where {T,n,S} = copy!(Array{T,n}(uninitialized, size(x)), x)

promote_rule(a::Type{Array{T,n}}, b::Type{Array{S,n}}) where {T,n,S} = el_same(promote_type(T,S), a, b)

# constructors should make copies
## Constructors ##

if module_name(@__MODULE__) === :Base # avoid method overwrite
(::Type{T})(x::T) where {T<:Array} = copy(x)
# constructors should make copies
Array{T,N}(x::AbstractArray{S,N}) where {T,N,S} = copy!(Array{T,N}(uninitialized, size(x)), x)
AbstractArray{T,N}(A::AbstractArray{S,N}) where {T,N,S} = copy!(similar(A,T), A)
end

## copying iterators to containers
Expand Down Expand Up @@ -498,14 +491,26 @@ end
# gets a chance to see it, so that recursive calls to the caller
# don't trigger the inference limiter
if isdefined(Core, :Inference)
macro default_eltype(itrt)
macro default_eltype(itr)
I = esc(itr)
return quote
Core.Inference.return_type(first, Tuple{$(esc(itrt))})
if $I isa Generator && ($I).f isa Type
($I).f
else
Core.Inference.return_type(first, Tuple{typeof($I)})
end
end
end
else
macro default_eltype(itrt)
return :(Any)
macro default_eltype(itr)
I = esc(itr)
return quote
if $I isa Generator && ($I).f isa Type
($I).f
else
Any
end
end
end
end

Expand All @@ -514,7 +519,7 @@ _array_for(::Type{T}, itr, ::HasShape) where {T} = similar(Array{T}, indices(itr

function collect(itr::Generator)
isz = iteratorsize(itr.iter)
et = @default_eltype(typeof(itr))
et = @default_eltype(itr)
if isa(isz, SizeUnknown)
return grow_to!(Vector{et}(), itr)
else
Expand All @@ -528,12 +533,12 @@ function collect(itr::Generator)
end

_collect(c, itr, ::EltypeUnknown, isz::SizeUnknown) =
grow_to!(_similar_for(c, @default_eltype(typeof(itr)), itr, isz), itr)
grow_to!(_similar_for(c, @default_eltype(itr), itr, isz), itr)

function _collect(c, itr, ::EltypeUnknown, isz::Union{HasLength,HasShape})
st = start(itr)
if done(itr,st)
return _similar_for(c, @default_eltype(typeof(itr)), itr, isz)
return _similar_for(c, @default_eltype(itr), itr, isz)
end
v1, st = next(itr, st)
collect_to_with_first!(_similar_for(c, typeof(v1), itr, isz), v1, itr, st)
Expand Down
21 changes: 6 additions & 15 deletions base/bitarray.jl
Original file line number Diff line number Diff line change
Expand Up @@ -463,21 +463,19 @@ function _bitreshape(B::BitArray, dims::NTuple{N,Int}) where N
return Br
end

## Conversions ##
## Constructors ##

convert(::Type{Array{T}}, B::BitArray{N}) where {T,N} = convert(Array{T,N}, B)
convert(::Type{Array{T,N}}, B::BitArray{N}) where {T,N} = _convert(Array{T,N}, B) # see #15801
function _convert(::Type{Array{T,N}}, B::BitArray{N}) where {T,N}
A = Array{T}(uninitialized, size(B))
function Array{T,N}(B::BitArray{N}) where {T,N}
A = Array{T,N}(uninitialized, size(B))
Bc = B.chunks
@inbounds for i = 1:length(A)
A[i] = unsafe_bitgetindex(Bc, i)
end
return A
end

convert(::Type{BitArray}, A::AbstractArray{T,N}) where {T,N} = convert(BitArray{N}, A)
function convert(::Type{BitArray{N}}, A::AbstractArray{T,N}) where N where T
BitArray(A::AbstractArray{<:Any,N}) where {N} = BitArray{N}(A)
function BitArray{N}(A::AbstractArray{T,N}) where N where T
B = BitArray(uninitialized, size(A))
Bc = B.chunks
l = length(B)
Expand All @@ -502,7 +500,7 @@ function convert(::Type{BitArray{N}}, A::AbstractArray{T,N}) where N where T
return B
end

function convert(::Type{BitArray{N}}, A::Array{Bool,N}) where N
function BitArray{N}(A::Array{Bool,N}) where N
B = BitArray(uninitialized, size(A))
Bc = B.chunks
l = length(B)
Expand All @@ -511,16 +509,9 @@ function convert(::Type{BitArray{N}}, A::Array{Bool,N}) where N
return B
end

convert(::Type{BitArray{N}}, B::BitArray{N}) where {N} = B
convert(::Type{AbstractArray{T,N}}, B::BitArray{N}) where {T,N} = convert(Array{T,N}, B)

reinterpret(::Type{Bool}, B::BitArray, dims::NTuple{N,Int}) where {N} = reinterpret(B, dims)
reinterpret(B::BitArray, dims::NTuple{N,Int}) where {N} = reshape(B, dims)

## Constructors from generic iterables ##

BitArray(A::AbstractArray{<:Any,N}) where {N} = convert(BitArray{N}, A)

if module_name(@__MODULE__) === :Base # avoid method overwrite
(::Type{T})(x::T) where {T<:BitArray} = copy(x)
end
Expand Down
8 changes: 8 additions & 0 deletions base/boot.jl
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,13 @@ Array{T}(::Uninitialized, d::NTuple{N,Int}) where {T,N} = Array{T,N}(uninitializ
Array{T,1}() where {T} = Array{T,1}(uninitialized, 0)


(::Type{Array{T,N} where T})(x::AbstractArray{S,N}) where {S,N} = Array{S,N}(x)

Array(A::AbstractArray{T,N}) where {T,N} = Array{T,N}(A)
Array{T}(A::AbstractArray{S,N}) where {T,N,S} = Array{T,N}(A)

AbstractArray{T}(A::AbstractArray{S,N}) where {T,S,N} = AbstractArray{T,N}(A)

# primitive Symbol constructors
function Symbol(s::String)
return ccall(:jl_symbol_n, Ref{Symbol}, (Ptr{UInt8}, Int),
Expand Down Expand Up @@ -667,6 +674,7 @@ UInt128(x::BuiltinInts) = toUInt128(x)::UInt128
UInt32(x::Char) = bitcast(UInt32, x)
Char(x::UInt32) = bitcast(Char, x)
Char(x::Number) = Char(UInt32(x))
Char(x::Char) = x
(::Type{T})(x::Char) where {T<:Number} = T(UInt32(x))

(::Type{T})(x::T) where {T<:Number} = x
Expand Down
16 changes: 16 additions & 0 deletions base/deprecated.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1520,6 +1520,22 @@ export hex2num

@deprecate convert(dt::Type{<:Integer}, ip::IPAddr) dt(ip)

function (::Type{T})(arg) where {T}
if applicable(convert, T, arg)
sig = which(convert, (Type{T}, typeof(arg))).sig
if sig == (Tuple{typeof(convert),Type{S},Number} where S<:Number) ||
sig == (Tuple{typeof(convert),Type{S},AbstractArray} where S<:AbstractArray)
# matches a catch-all converter; will stack overflow
throw(MethodError(T, (arg,)))
end
# if `convert` call would not work, just let the method error happen
depwarn("Constructors no longer fall back to `convert`. A constructor `$T(::$(typeof(arg)))` should be defined instead.", :Type)
end
convert(T, arg)::T
end
# related items to remove in: abstractarray.jl, dates/periods.jl, inference.jl
# also remove all uses of is_default_method

# Issue #19923
@deprecate ror circshift
@deprecate ror! circshift!
Expand Down
4 changes: 2 additions & 2 deletions base/dict.jl
Original file line number Diff line number Diff line change
Expand Up @@ -157,9 +157,9 @@ associative_with_eltype(DT_apply, kv, ::TP{K,V}) where {K,V} = DT_apply(K, V)(kv
associative_with_eltype(DT_apply, kv::Generator, ::TP{K,V}) where {K,V} = DT_apply(K, V)(kv)
associative_with_eltype(DT_apply, ::Type{Pair{K,V}}) where {K,V} = DT_apply(K, V)()
associative_with_eltype(DT_apply, ::Type) = DT_apply(Any, Any)()
associative_with_eltype(DT_apply::F, kv, t) where {F} = grow_to!(associative_with_eltype(DT_apply, @default_eltype(typeof(kv))), kv)
associative_with_eltype(DT_apply::F, kv, t) where {F} = grow_to!(associative_with_eltype(DT_apply, @default_eltype(kv)), kv)
function associative_with_eltype(DT_apply::F, kv::Generator, t) where F
T = @default_eltype(typeof(kv))
T = @default_eltype(kv)
if T <: Union{Pair, Tuple{Any, Any}} && _isleaftype(T)
return associative_with_eltype(DT_apply, kv, T)
end
Expand Down
10 changes: 8 additions & 2 deletions base/inference.jl
Original file line number Diff line number Diff line change
Expand Up @@ -1912,7 +1912,7 @@ function abstract_call_gf_by_type(@nospecialize(f), argtypes::Vector{Any}, @nosp
end
# many types have many matching constructors; try harder to infer simple type ctors
if !has_free_typevars(tname)
max_methods = max(max_methods, 15)
#max_methods = max(max_methods, 15)
end
end
min_valid = UInt[typemin(UInt)]
Expand Down Expand Up @@ -2088,7 +2088,13 @@ function abstract_call_method_with_const_args(argtypes::Vector{Any}, match::Simp
return result
end

const deprecated_sym = Symbol("deprecated.jl")

function abstract_call_method(method::Method, @nospecialize(sig), sparams::SimpleVector, sv::InferenceState)
# TODO: remove with 0.7 deprecations
if method.file === deprecated_sym && method.sig == (Tuple{Type{T},Any} where T)
return Any, false
end
topmost = nothing
# Limit argument type tuple growth of functions:
# look through the parents list to see if there's a call to the same method
Expand Down Expand Up @@ -2183,7 +2189,7 @@ function abstract_call_method(method::Method, @nospecialize(sig), sparams::Simpl
recomputed = ccall(:jl_type_intersection_with_env, Any, (Any, Any), sig, method.sig)::SimpleVector
sig = recomputed[1]
if !isa(unwrap_unionall(sig), DataType) # probably Union{}
return Any
return Any, false
end
sparams = recomputed[2]::SimpleVector
end
Expand Down
1 change: 1 addition & 0 deletions base/libgit2/types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct GitHash <: AbstractGitHash
GitHash(val::NTuple{OID_RAWSZ, UInt8}) = new(val)
end
GitHash() = GitHash(ntuple(i->zero(UInt8), OID_RAWSZ))
GitHash(h::GitHash) = h

"""
GitShortHash(hash::GitHash, len::Integer)
Expand Down
17 changes: 9 additions & 8 deletions base/linalg/bidiag.jl
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ function Bidiagonal(A::AbstractMatrix, uplo::Symbol)
Bidiagonal(diag(A, 0), diag(A, uplo == :U ? 1 : -1), uplo)
end

Bidiagonal(A::Bidiagonal) = A

function getindex(A::Bidiagonal{T}, i::Integer, j::Integer) where T
if !((1 <= i <= size(A,2)) && (1 <= j <= size(A,2)))
throw(BoundsError(A,(i,j)))
Expand Down Expand Up @@ -131,7 +133,7 @@ function Base.replace_in_print_matrix(A::Bidiagonal,i::Integer,j::Integer,s::Abs
end

#Converting from Bidiagonal to dense Matrix
function convert(::Type{Matrix{T}}, A::Bidiagonal) where T
function Matrix{T}(A::Bidiagonal) where T
n = size(A, 1)
B = zeros(T, n, n)
for i = 1:n - 1
Expand All @@ -145,15 +147,14 @@ function convert(::Type{Matrix{T}}, A::Bidiagonal) where T
B[n,n] = A.dv[n]
return B
end
convert(::Type{Matrix}, A::Bidiagonal{T}) where {T} = convert(Matrix{T}, A)
convert(::Type{Array}, A::Bidiagonal) = convert(Matrix, A)
Matrix(A::Bidiagonal{T}) where {T} = Matrix{T}(A)
Array(A::Bidiagonal) = Matrix(A)
promote_rule(::Type{Matrix{T}}, ::Type{<:Bidiagonal{S}}) where {T,S} =
@isdefined(T) && @isdefined(S) ? Matrix{promote_type(T,S)} : Matrix
promote_rule(::Type{Matrix}, ::Type{<:Bidiagonal}) = Matrix

#Converting from Bidiagonal to Tridiagonal
Tridiagonal(M::Bidiagonal{T}) where {T} = convert(Tridiagonal{T}, M)
function convert(::Type{Tridiagonal{T}}, A::Bidiagonal) where T
function Tridiagonal{T}(A::Bidiagonal) where T
dv = convert(AbstractVector{T}, A.dv)
ev = convert(AbstractVector{T}, A.ev)
z = fill!(similar(ev), zero(T))
Expand All @@ -164,12 +165,12 @@ promote_rule(::Type{<:Tridiagonal{T}}, ::Type{<:Bidiagonal{S}}) where {T,S} =
promote_rule(::Type{<:Tridiagonal}, ::Type{<:Bidiagonal}) = Tridiagonal

# No-op for trivial conversion Bidiagonal{T} -> Bidiagonal{T}
convert(::Type{Bidiagonal{T}}, A::Bidiagonal{T}) where {T} = A
Bidiagonal{T}(A::Bidiagonal{T}) where {T} = A
# Convert Bidiagonal to Bidiagonal{T} by constructing a new instance with converted elements
convert(::Type{Bidiagonal{T}}, A::Bidiagonal) where {T} =
Bidiagonal{T}(A::Bidiagonal) where {T} =
Bidiagonal(convert(AbstractVector{T}, A.dv), convert(AbstractVector{T}, A.ev), A.uplo)
# When asked to convert Bidiagonal to AbstractMatrix{T}, preserve structure by converting to Bidiagonal{T} <: AbstractMatrix{T}
convert(::Type{AbstractMatrix{T}}, A::Bidiagonal) where {T} = convert(Bidiagonal{T}, A)
AbstractMatrix{T}(A::Bidiagonal) where {T} = convert(Bidiagonal{T}, A)

broadcast(::typeof(big), B::Bidiagonal) = Bidiagonal(big.(B.dv), big.(B.ev), B.uplo)

Expand Down
30 changes: 15 additions & 15 deletions base/linalg/cholesky.jl
Original file line number Diff line number Diff line change
Expand Up @@ -349,30 +349,30 @@ function cholfact(x::Number, uplo::Symbol=:U)
end


function convert(::Type{Cholesky{T}}, C::Cholesky) where T
function Cholesky{T}(C::Cholesky) where T
Cnew = convert(AbstractMatrix{T}, C.factors)
Cholesky{T, typeof(Cnew)}(Cnew, C.uplo, C.info)
end
convert(::Type{Factorization{T}}, C::Cholesky{T}) where {T} = C
convert(::Type{Factorization{T}}, C::Cholesky) where {T} = convert(Cholesky{T}, C)
convert(::Type{CholeskyPivoted{T}},C::CholeskyPivoted{T}) where {T} = C
convert(::Type{CholeskyPivoted{T}},C::CholeskyPivoted) where {T} =
Factorization{T}(C::Cholesky{T}) where {T} = C
Factorization{T}(C::Cholesky) where {T} = Cholesky{T}(C)
CholeskyPivoted{T}(C::CholeskyPivoted{T}) where {T} = C
CholeskyPivoted{T}(C::CholeskyPivoted) where {T} =
CholeskyPivoted(AbstractMatrix{T}(C.factors),C.uplo,C.piv,C.rank,C.tol,C.info)
convert(::Type{Factorization{T}}, C::CholeskyPivoted{T}) where {T} = C
convert(::Type{Factorization{T}}, C::CholeskyPivoted) where {T} = convert(CholeskyPivoted{T}, C)
Factorization{T}(C::CholeskyPivoted{T}) where {T} = C
Factorization{T}(C::CholeskyPivoted) where {T} = CholeskyPivoted{T}(C)

convert(::Type{AbstractMatrix}, C::Cholesky) = C.uplo == 'U' ? C[:U]'C[:U] : C[:L]*C[:L]'
convert(::Type{AbstractArray}, C::Cholesky) = convert(AbstractMatrix, C)
convert(::Type{Matrix}, C::Cholesky) = convert(Array, convert(AbstractArray, C))
convert(::Type{Array}, C::Cholesky) = convert(Matrix, C)
AbstractMatrix(C::Cholesky) = C.uplo == 'U' ? C[:U]'C[:U] : C[:L]*C[:L]'
AbstractArray(C::Cholesky) = AbstractMatrix(C)
Matrix(C::Cholesky) = Array(AbstractArray(C))
Array(C::Cholesky) = Matrix(C)

function convert(::Type{AbstractMatrix}, F::CholeskyPivoted)
function AbstractMatrix(F::CholeskyPivoted)
ip = invperm(F[:p])
(F[:L] * F[:U])[ip,ip]
end
convert(::Type{AbstractArray}, F::CholeskyPivoted) = convert(AbstractMatrix, F)
convert(::Type{Matrix}, F::CholeskyPivoted) = convert(Array, convert(AbstractArray, F))
convert(::Type{Array}, F::CholeskyPivoted) = convert(Matrix, F)
AbstractArray(F::CholeskyPivoted) = AbstractMatrix(F)
Matrix(F::CholeskyPivoted) = Array(AbstractArray(F))
Array(F::CholeskyPivoted) = Matrix(F)

copy(C::Cholesky) = Cholesky(copy(C.factors), C.uplo, C.info)
copy(C::CholeskyPivoted) = CholeskyPivoted(copy(C.factors), C.uplo, C.piv, C.rank, C.tol, C.info)
Expand Down
10 changes: 5 additions & 5 deletions base/linalg/diagonal.jl
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ Diagonal(V::AbstractVector{T}) where {T} = Diagonal{T,typeof(V)}(V)
Diagonal{T}(V::AbstractVector{T}) where {T} = Diagonal{T,typeof(V)}(V)
Diagonal{T}(V::AbstractVector) where {T} = Diagonal{T}(convert(AbstractVector{T}, V))

convert(::Type{Diagonal{T}}, D::Diagonal{T}) where {T} = D
convert(::Type{Diagonal{T}}, D::Diagonal) where {T} = Diagonal{T}(convert(AbstractVector{T}, D.diag))
convert(::Type{AbstractMatrix{T}}, D::Diagonal) where {T} = convert(Diagonal{T}, D)
convert(::Type{Matrix}, D::Diagonal) = diagm(0 => D.diag)
convert(::Type{Array}, D::Diagonal) = convert(Matrix, D)
Diagonal{T}(D::Diagonal{T}) where {T} = D
Diagonal{T}(D::Diagonal) where {T} = Diagonal{T}(convert(AbstractVector{T}, D.diag))
AbstractMatrix{T}(D::Diagonal) where {T} = Diagonal{T}(D)
Matrix(D::Diagonal) = diagm(0 => D.diag)
Array(D::Diagonal) = Matrix(D)

# For D<:Diagonal, similar(D[, neweltype]) should yield a Diagonal matrix.
# On the other hand, similar(D, [neweltype,] shape...) should yield a sparse matrix.
Expand Down
Loading

0 comments on commit 002fb2f

Please sign in to comment.