In the "Inner Constructors" section of the manual, it says:
The default constructor is equivalent to writing your own inner constructor method that takes all of the object鈥檚 fields as parameters (constrained to be of the correct type, if the corresponding field has a type), and passes them to new, returning the resulting object
Which I would read to mean that:
type T1
x::Int64
end
would be equivalent to:
type T1
x::Int64
T1(x::Int64) = new(x)
end
But right below it gives the above equivalent example as:
type T1
x::Int64
T1(x) = new(x)
end
Which seems to me to imply that new
calls convert
on the fields, because non-Int64
arguments are convert
ed to Int64
.
In the "Types" section of the manual it says:
Two constructors are generated automatically (these are called default constructors). One accepts any arguments and calls convert() to convert them to the types of the fields, and the other accepts arguments that match the field types exactly.
Which I would read to mean that:
type T1
x::Int64
end
would be equivalent to:
type T1
x::Int64
T1(x::Int64) = new(x)
end
T1(x) = T1(convert(Int64, x))
It seems that these two descriptions of the default constructors (either converting in the outer constructor or converting in new
) would behave identically, but it's confusing that it's described both ways in the manual. Is one of them more correct?
It actually generates both:
julia> expand(quote
type T1
x::Int64
end
end)
type T1
x::Int64
T1(x::Int64) = new(convert(Int64, x))
T1(x) = new(convert(Int64, x))
end
It sounds like parts of the manual may be out-of-date?
It seems like from the user's perspective it the T1(x::Int64)
definition doesn't matter, right?
Also, if you define:
type T1
x::Int64
T1(x) = new(x)
end
Then T1(1.0)
still works, so it seems that in that case it's still convert
ing. Looking at new-call in the parser it looks like a convert
is automatically inserted even if the user overrides the inner constructor .
So maybe the equivalence in the Constructors section is the best one:
type T1
x::Int64
T1(x) = new(x)
end
But removing the comment about restricting argument types, and adding a note that new
converts all the field types.
If that seems correct I can edit the docs.
The T1(x::Int64)
constructor is sometimes important. Otherwise e.g. T1(x::Real) = T1(round(Int64, x))
would cause stack overflow.
Ah, good point. Thanks!
That trick with expand is very neat!
If anyone's feeling extra ambitious, it'd be great to clarify how to use type parameters w/ new
in inner constructors. Even as someone who has used julia for years, I have trouble knowing how exactly to express something like:
# type w/ type parameter tag
type A{T}
val::Int
A{T}(val) = new(convert(Int, val)) # ?
A(val) = new{T}(convert(Int, val)) # ?
end
Most helpful comment
If anyone's feeling extra ambitious, it'd be great to clarify how to use type parameters w/
new
in inner constructors. Even as someone who has used julia for years, I have trouble knowing how exactly to express something like: