Skip to content

Commit 5d2be9e

Browse files
author
Pietro Vertechi
authored
bypass constructor on getindex (#145)
* bypass constructor in getindex * special case tuples and named tuples * only bypass constructor for concrete types * test on internal constructor case * minor reorg * define struct outside testet
1 parent b1f814e commit 5d2be9e

File tree

3 files changed

+32
-2
lines changed

3 files changed

+32
-2
lines changed

src/interface.jl

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ end
99

1010
staticschema(::Type{T}) where {T<:Tup} = T
1111

12-
createinstance(::Type{T}, args...) where {T} = T(args...)
13-
createinstance(::Type{T}, args...) where {T<:Union{Tuple, NamedTuple}} = T(args)
12+
function createinstance(::Type{T}, args...) where {T}
13+
isconcretetype(T) ? bypass_constructor(T, args) : T(args...)
14+
end
15+
16+
createinstance(::Type{T}, args...) where {T<:Tup} = T(args)

src/utils.jl

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,3 +146,16 @@ hasfields(::Type{<:NTuple{N, Any}}) where {N} = true
146146
hasfields(::Type{<:NamedTuple{names}}) where {names} = true
147147
hasfields(::Type{T}) where {T} = !isabstracttype(T)
148148
hasfields(::Union) = false
149+
150+
"""
151+
bypass_constructor(T, args)
152+
153+
Create an instance of type `T` from a tuple of field values `args`, bypassing
154+
possible internal constructors. `T` should be a concrete type.
155+
"""
156+
@generated function bypass_constructor(::Type{T}, args) where {T}
157+
vars = ntuple(_ -> gensym(), fieldcount(T))
158+
assign = [:($var::$(fieldtype(T, i)) = getfield(args, $i)) for (i, var) in enumerate(vars)]
159+
construct = Expr(:new, :T, vars...)
160+
Expr(:block, assign..., construct)
161+
end

test/runtests.jl

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,20 @@ end
238238
@test getproperty(t, 2) == [3.0, 2.0]
239239
end
240240

241+
struct A
242+
x::Int
243+
y::Int
244+
A(x) = new(x, x)
245+
end
246+
247+
@testset "internal constructor" begin
248+
v = A.([1, 2, 3])
249+
s = StructArray(v)
250+
@test s[1] == A(1)
251+
@test s[2] == A(2)
252+
@test s[3] == A(3)
253+
end
254+
241255
@testset "kwargs constructor" begin
242256
a = [1.2]
243257
b = [2.3]

0 commit comments

Comments
 (0)