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
>> >>> 
>> >>> 
>>
>>
>>


Reply via email to