After some iterations, I'm pretty happy with this form, which doesn't need any magic:
https://gist.github.com/nbecker/58f79e449400159e4762f6c8eedd9f65 The type var is parameterized by 2 parameters, and the constructors take care of the type computations, similar to Dan's suggestion. The invariant checking you suggest could be added (but in my case would be a bit more complicated) Jeffrey Sarnoff wrote: > Hi Neal, > > It is not good practice to leave out parts of the template that Dan > offers. > While it may work with some test data, it is very likely to fail in > general use (particularly by/with use from other packages) and it may > become incompatible in some specific manner with future releases. > > If I get your drift, something like this may serve > > underlyingtype{T}(::Type{Complex{T}}) = T > > type ComplexOf{S,T} > sum::S > sumsqr::T > function ComplexOf{S,T}(s::S,ss::T) > realtype = underlyingtype(S) > if typeof(ss) != realtype > throw( > TypeError( :ComplexOf, "ComplexOf($s,$ss)\n\t\t", realtype, > T > )) > end > new(s,ss) > end > end > > ComplexOf{S,T}(x::S, y::T) = ComplexOf{S,T}(x,y) > > ComplexOf(1.5+2.0im, 1.0) > > ComplexOf(5+2im, 3) > > # force a type error by mixing the kinds of underlying types > ComplexOf(5.0+1.5im, 2.0f0) > > # presumably, you want to add > function ComplexOf{T}(x::Vector{Complex{T}}) > s = sum(x) > ss = abs2(s) > return ComplexOf(s,ss) > end > > > test = ComplexOf([3.0+1.0im, 2.0-1.0im]); > test.sum, test.sumsqr > > > > If you have questions about why something is present, do ask. > Also, in this case, you can use `immutable ComplexOf` rather than `type > ComplexOf`, which helps if there are very many of them. > > On Thursday, September 15, 2016 at 8:44:28 AM UTC-4, Neal Becker wrote: >> >> OK, I think I got it: >> >> decomplexify{T}(::Type{Complex{T}}) = T >> >> type var2{T,S} >> sum::S >> sumsqr::T >> nobjs::Int64 >> var2() = new(0,0,0) >> end >> >> (::Type{var2{T}}){T}() = var2{T,decomplexify((T))}() << magic? >> var2() = var2{Complex{Float64},Float64}() << default >> >> This seems to work >> Problem is I have no idea what this line marked "magic" means. >> >> Isaiah Norton wrote: >> >> > See >> https://github.com/JuliaLang/julia/issues/18466#issuecomment-246713799 >> > >> > On Wed, Sep 14, 2016 at 6:13 PM, Dan >> > <[email protected] <javascript:>> wrote: >> > >> >> Maybe the following is the form you are looking for: >> >> >> >> julia> decomplexify{T}(::Type{Complex{T}}) = T >> >> decomplexify (generic function with 1 method) >> >> >> >> >> >> julia> type bar{S,T} >> >> sum::S >> >> sumsqr::T >> >> function bar(s,ss) >> >> if typeof(ss) != decomplexify(typeof(s)) >> >> error("Yaiks") >> >> end >> >> new(s,ss) >> >> end >> >> end >> >> >> >> >> >> julia> bar{Complex{Float64},Float64}(1.5+2.0im,1.0) >> >> bar{Complex{Float64},Float64}(1.5 + 2.0im,1.0) >> >> >> >> >> >> julia> bar{S,T}(x::S,y::T) = bar{S,T}(x,y) >> >> bar{S,T} >> >> >> >> >> >> julia> bar(1.5+2.0im,1.0) >> >> bar{Complex{Float64},Float64}(1.5 + 2.0im,1.0) >> >> >> >> >> >> The outer constructor is necessary to get the last line working. The >> >> inner constructor basically maintains the constraint between S and T >> of: >> >> T == Complex{S}. >> >> >> >> On Wednesday, September 14, 2016 at 3:38:53 PM UTC-4, Neal Becker >> wrote: >> >>> >> >>> Evan Fields wrote: >> >>> >> >>> > How about something like the following? >> >>> > >> >>> > type CT{T} >> >>> > ctsum::Complex{T} >> >>> > ctsumsq::T >> >>> > end >> >>> > >> >>> >> >>> I'm aware that it's easier to make the type parameter the scalar >> >>> type, allowing writing as you show, but as a learning exercise I'd >> >>> like to know how Julia would go the other way. >> >>> >> >>> In c++ this would be done with template metaprogramming, but as Julia >> >>> claims >> >>> to have types as 1st class objects, I thought there should be some >> >>> elegant >> >>> way to do this. >> >>> >> >>> That is, given T is Complex{U}, I need the type U so I can write >> >>> ctsumsq::U >> >>> >> >>> >> >> >>
