I'd like to point out that the fact that Array{Float64,1} is not a subtype 
of Array{Any,1} makes it easier to reason about Julia program correctness 
and therefore avoid errors.  Consider:

function f(a::Array{Any,1})
    push!(a, "hello")
end

Is this function correct?  Assuming I didn't make any typos, we could say 
with a high degree of confidence that it is correct in Julia 0.3, 0.4, 0.5, 
...  But suppose that the language were changed so that Array{Float64,1} 
were a subtype of Array{Any,1}.  Then what would the above function do if 
invoked like this:  f([4.0,5.0])?  Either it would give an error (which is 
undesirable, since we'd like to say once and for all that f is correct), or 
else it would have to silently change the type of its argument from an 
array of Float64's to an array of Any, which would make it very difficult 
to reason about program correctness.

This example says that covariance for a container would undermine our 
ability to reason about program correctness unless the container is 
immutable.  But in fact, Julia allows tuples (which are immutable) to be 
covariant in version 0.4+, so we are still safe.

-- Steve Vavasis




On Thursday, October 8, 2015 at 6:02:21 AM UTC-4, [email protected] 
wrote:
>
> Yup.  Thanks Kristoffer.  I did a few more little things in julia and 
> figured it out before I saw your post:
>
> function(x::Real, y::Real)
>     return 2x - y
> end
>
> function(x::Real, y::Array{Real, 1})
>     return 2x - y[1]
> end
>
> First one works; second one does not.
>
> It is the use of Array, a compound object.  I guess that means types 
> aren't covariant (is that the right term?).  It's unfortunate.  ML and some 
> of the lisps would probably handle it.  It's not a big deal.  It is 
> documented but you sort of have to put a few concepts together.  It's sort 
> of cool that the parametric type function signature DOES work.  Less 
> familiar concept to code, but the user of the method doesn't see it.
>
> On Thursday, October 8, 2015 at 2:43:08 AM UTC-7, Kristoffer Carlsson 
> wrote:
>>
>> There is a difference between an abstract type like Number and a type 
>> parameterized by an abstract types like Vector{Number}.
>>
>> While it is true that for example Float64 is a subtype of Number it is 
>> not true that Vector{Float64} is a subtype of Vector{Number}.
>>
>>
>>
>> On Thursday, October 8, 2015 at 11:35:05 AM UTC+2, 
>> [email protected] wrote:
>>>
>>> Thanks Tomas, but what you are saying seems to violate the manual.
>>>
>>> Here is the verbatim example:
>>>
>>> (from Chapter 12, "Methods", page 104)
>>>
>>> As you can see, the arguments must be precisely of type Float64. Other 
>>> numeric types, such as integers or 32- bit floating-point values, are not 
>>> automatically converted to 64-bit floating-point, nor are strings parsed as 
>>> numbers. Because Float64 is a concrete type and concrete types cannot 
>>> be subclassed in Julia, such a definition can only be applied to arguments 
>>> that are exactly of type Float64. It may often be useful, however, to 
>>> write more general methods where the declared parameter types are abstract: 
>>>
>>>
>>> julia> f(x::Number, y::Number) = 2x - y;
>>>
>>> julia> f(2.0, 3)1.0
>>>
>>>
>>> This method definition applies to any pair of arguments that are 
>>> instances of Number. They need not be of the same type, so long as they 
>>> are each numeric values. The problem of handling disparate numeric types is 
>>> delegated to the arithmetic operations in the expression2x - y. 
>>>
>>>
>>> Can't see how that is different than my use of the abstract type Real. 
>>>  In fact, the above example from the manual naturally works with Real.
>>>
>>>
>>> Is there something special about one-line function definitions?
>>>
>>> I think my objection stands unless there are more rules or I missed 
>>> something and defined the function incorrectly or did the type restriction 
>>> incorrectly.
>>>
>>> Still confused.
>>>
>>

Reply via email to