This is well documented behavior, and has been the same since “forever” 
(it’s a fundamental design decision in Julia’s type system). The manual 
section on parametric types 
<http://docs.julialang.org/en/release-0.4/manual/types/#man-parametric-types> 
talks quite a lot about this, including this specific quote:

*Even though Float64 <: Real we DO NOT have Point{Float64} <: Point{Real}*

The theoretical concept is called “type invariance”, and if you search the 
list for “invariance” you’ll find a host of threads with more-or-less 
exactly the same examples as yours, and with more detailed explanations on 
why they don’t work, and why that’s a good thing.

The “Julian way” of writing that method, would be number 4 - the code will 
be just as efficient (thanks to Julia’s smart JIT compilation) but much 
more usable to other users, who might have defined other types that fulfill 
the contracts you require in your method.

// T

On Thursday, October 8, 2015 at 10:24:05 AM UTC+2, le…@neilson-levin.org 
wrote:

Here is a simple function to evaluate a polynomial. Different potential 
> function signatures are shown in the commented lines:
>
>
> # 1 function p{T<:Real, Y<:Real}(x::T, coeff::Array{Y,1}) # this works
> # 2 function p(x::Real, coeff::Array{Real,1}) # DOES NOT WORK
> # 3 function p(x::Any, coeff::Array{Any,1}) # DOES NOT WORK
>
> function p(x, coeff) # works but you better use it right
>     px = 0
>     for (i,v) in enumerate(coeff)
>         px += v * x^(i-1)
>     end
>     return px
> end
>
>
>
>
> Here are the results I observed:
> 1. The parametric type used for the parameter types works. Both the input 
> value x and the array of coeffs must be real AND they can be different 
> sub-types of real.
>
> 2. This seems like it SHOULD work but it does not. Example of output: 
>
> *julia> **include("polyeval.jl")*
>
> *p (generic function with 1 method)*
>
>
> *julia> **methods(p)*
>
> *# 1 method for generic function "p":*
>
> *p(x::Real, coeff::Array{Real,1}) at 
> /Users/lewislevinmbr/Dropbox/julia-code/just-learning/polyeval.jl:5*
>
>
> *julia> **p(2.1,[1,1.0])*
>
> *ERROR: MethodError: `p` has no method matching p(::Float64, 
> ::Array{Float64,1})*
>
> Closest candidates are:
>
>   p(::Real, *::Array{Real,1}*)
>
>  
> The problem appears to be that the concrete types of the arguments are not 
> being mapped to the abstract types of the function parameters. All examples 
> I see in documentation suggest this should work. Am I doing something wrong 
> here? 
>
> 3. This looks like it should work. It should match the last, uncommented 
> function signature allowing any argument types. I say work in the sense it 
> should have no compile time exception and should accept any argument types. 
> It is likely to generate runtime errors for lots of inputs. But, it 
> produces a MethodError always. 
>
> 4. This function signature doesn't type the parameters. It should 
> operationally be the same as 3. Naturally, it runs with the same caveat 
> about runtime errors. 
>
> What's going on here?
>
​

Reply via email to