The rule of thumb is this:
Using abstract types to describe *behaviors* is fine, using them for
*locations* is bad.
A field is a location, the element type of an array is a set of locations.
If you want these to be fast, they should be concretely typed. The types in
a method signature describes a behavior, not a location, so it's fine for
the types to be abstract.
On Thu, Jun 11, 2015 at 9:26 AM, andrew cooke <[email protected]> wrote:
>
> i don't know of any docs that justify this, but i would assume that Union
> and Number would have very similar performance.
>
> also, this isn't as bad as you may think. it depends a lot on what you
> are doing. if you're array crunching, yes, it's a big deal, because you
> have to look at type tags all the time. but i you're just storing data at
> a high level and then passing it to other routines, those routines may
> still be specialised.
>
> for example:
>
> julia> foo(a::Int) = (println("int"); a)
> foo (generic function with 1 method)
>
> julia> foo(a::Number) = (println("number"); a)
> foo (generic function with 2 methods)
>
> julia> map(foo, Number[1,1.0])
> int
> number
> 2-element Array{Real,1}:
> 1
> 1.0
>
> you can see that the specialised, efficient, foo() is called. and if that
> is where most of your work is done, you are fine.
>
> so "never" is a bit strong. sometimes abstract types can be very useful.
>
> andrew
>
>
> On Thursday, 11 June 2015 01:21:01 UTC-3, Lyndon White wrote:
>>
>> Containers of abstract types are not performant,
>> This is documented in the performance notes section of the manual.
>>
>> However containers of concrete types are not generic.
>> For example, I am currently redoing a large section of code from using
>> Float64s to using Numbers, so that I can use DualNumbers to check
>> derivatives.
>>
>> The reason Number (and other abstract types) are slow, is because are
>> full of pointers.
>> Since each element of a Matix{Number} could potentially be of a different
>> type, eg some could be Int8s and some could be Float64s.
>> But in practice the varse majority of the time, every element is of the
>> same type.
>>
>> The 3 signitures:
>>
>> Matix{Number}
>> Matrix{Union(Number, Float64, Float32, Float16, Int...) }
>> Matrix{T<:Number}
>>
>>
>> All can contain the same information, as they will all contain a
>> Matrix{Number}, and none of them will contain a Matrix{NotNumber},
>> (Though to fit a concrete typed matrix into a matrix of abstract type
>> you need to run a convert),
>>
>> But they have very different performance.
>> As I can show with the following Notebook:
>> http://nbviewer.ipython.org/gist/oxinabox/a00d3b1eb5584467e6b7
>> Which also compares with Any just for the sake of seeing if contrete
>> types help (they don't)
>>
>> What can be seen t Matrix{Union(Number, Float64) }, Matrix{T<:Number}
>> and Any perform about the same
>> and that Matrix{Number} is 3 orders of magnitude slower (not unexpected).
>>
>> Ergo, because the former can contain anything that can be contained in
>> the Matrix{Number}, there is AFAICT, no reason not to use them.
>> Worse case senario, the contents really is a Matrix of mixed numeric
>> types and the performance falls back to the Matrix{Number} case.
>>
>> Syntactically perhaps it is less nice.
>> I have a type alias for Matrix{Union(Number, Float64,...)} which solves
>> that, to an extent.
>> Argument could be made that Matrix{T<:Number} is even better, but it is
>> annoying to refactor code to use that as it is not a simple find and
>> replace as a type parameter needs to be added to all functions.
>>
>>
>> ----
>>
>> Thoughts, comments,
>> Reasons why Matrix{Number} might be users over either of the other cases?
>>
>>
>>