Yes, that is exactly the kind of example that I'm referring to. (As is the 
example that started this thread as well.)
In all other cases, x::T is covariant in the sense that it allows typeof(x) 
<: T. But in an argument list when T is a type parameter to the same 
method, x::T is instead invariant in the sense that it only allows 
typeof(x) === T.

To me, this is a much bigger (and completely different kind of) difference 
than between using :: as a type declaration and type assertion.
Now that I know this, I'm starting to doubt what I thought that I knew 
about type parameters in other cases. How about

    f{T}(x::AbstractArray{T}) = T

Does this accept subtypes of AbstractArray{T}? It turns out that it does. 
But how do I know?

I suspect that the pragmatic rule that Julia follows is that each type 
declaration that involves a type parameter T must in itself determine a 
unique possible value for T based on the type of the method arguments.

Jeff or Stefan: Care to comment?

On Friday, 16 May 2014 11:48:29 UTC+2, Mauro wrote:
>
> Here is an example of the difference Toivo refers to (I think): 
>
>
> julia> foo{T<:Real}(a::Array{T},b::T) = T 
> foo (generic function with 1 method) 
>
> julia> bar(a::Array{Real},b::Real) = Real                                 
>                                                                             
>                     
> bar (generic function with 1 method) 
>
> julia> aR = Real[1,2]; aI = Int[1,2];                                     
>                                                                             
>                     
>
> julia> foo(aR, 5) 
> ERROR: no method foo(Array{Real,1}, Int64) 
>
> julia> foo(aI, 5)                                                         
>                                                                             
>                     
> Int64 
>
> julia> bar(aR, 5)                                                         
>                                                                             
>                     
> Real 
>
>
> When calling foo(aR, 5), then T is set to Real.  Now in case of 
> parameterized functions this means that typeof(b)===T, i.e. typeof(b) 
> must be Real.  (which in this case is never possible as Real is an 
> abstract type).  This contrasts to bar where only the weaker constraint 
> typeof(b)<:Real is needed, i.e. a isa relation. 
>
> Thus, Toivo's complaint is that in function definitions :: usually means 
> `isa` whereas for parameterized functions it means type equality `===`. 
> However, I think this realisation does not make the :: situation worse 
> than it already is.  :: has different meanings depending on context: 
> ditto when in function declarations, then in function bodies it can also 
> be a sub-type-assert, or a type declaration of a variable in the sense 
> of check-and-convert (if check fails).  So, three meanings of :: are 
> possible. 
>
> As an aside, in the issue about "function return type declarations" 
> https://github.com/JuliaLang/julia/issues/1090 it is suggested to add 
> syntax like f(a)::Int = 5 to declare that f returns an Int.  The 
> discussion there suggests that there :: will have the check-and-convert 
> semantics.  Thus a line like this could contain all three meanings of :: 
>
> f{T<:Real}((a::Array{T},b::T,c::Integer)::Complex = ... 
>
> ! 
>
> On Fri, 2014-05-16 at 08:15, tomas....@gmail.com <javascript:> wrote: 
> >> But do you agree that the usage of x::T as a formal parameter is quite 
> > different when T is a type parameter compared to when it is a plain 
> type? 
> > 
> > I'm not 100% sure I grok what you're getting at, but *if *what you're 
> > asking is whether I see a difference between foo(x::Real) and 
> > foo{T<:Real}(x::Array{T}), then really no - I don't. 
> > 
> > I just the latter as shorthand for defining a function with a whole 
> bunch 
> > of methods - foo(x::Array{Int64}), foo(x::Array{Float64}), etc etc - 
> with 
> > the same Julia implementation. They will still, just as the former for 
> > foo(x::Int64) and foo(x::Float64), be compiled to different versions, 
> > strongly typed to the runtime type of the argument, and I could get 
> exactly 
> > the same behavior without parametric methods by copy-pasting the 
> > implementation and using different specific type signatures. I'd need 
> one 
> > for every subtype of Real, so of course this isn't feasible in practice, 
> > but the way I look at it the difference is really mainly syntactic 
> sugar. 
> > 
> > The possibility to do diagonal dispatch with the help of type parameters 
> is 
> > also syntactic sugar - I could just as easily define bar(x::Int64, 
> > y::Int64) etc for all real types, but with no methods for bar that take 
> > arguments of different kinds, as define bar{T<:Real}(x::T, y::T). Again, 
> > this would mean an insane amount of code duplication, so I'm really glad 
> I 
> > don't *have* to code this way, but I certainly could if I for some 
> wicked 
> > reason wanted to. 
> > 
> > There is of course one thing that differs profoundly: if you define 
> > foo{T<:Real}(x::Array{T}) and then someone else comes, later on, and 
> > defines a new subtype to Real, your definition just works. Had you done 
> it 
> > without type parameters, it of course wouldn't have worked without also 
> > adding a specific implementation for foo(x::Array{MyNewRealType}). 
> > 
> > // Tomas 
> > 
> > On Thursday, May 15, 2014 10:03:12 PM UTC+2, Kevin Squire wrote: 
> >> 
> >> FWIW, I really appreciate you pointing out the different uses of :: 
> Toivo. 
> >>  Along with the different meanings of parameterizations in types and 
> >> functions, this is another area I haven't been clear about (and I 
> wasn't 
> >> even aware of it until you pointed it out). 
> >> 
> >> Cheers! 
> >>    Kevin 
> >> 
> >> 
> >> On Thu, May 15, 2014 at 11:49 AM, Toivo Henningsson 
> >> <toiv...@gmail.com<javascript:> 
>
> >> > wrote: 
> >> 
> >>> 
> >>> 
> >>> On Thursday, 15 May 2014 10:59:07 UTC+2, Tomas Lycken wrote: 
> >>>> 
> >>>> it silently uses :: in a different sense than anywhere else in the 
> >>>>> language 
> >>>> 
> >>>> 
> >>>> I started writing a reply here, but realized it would be more 
> >>>> instructive to have it as an IJulia notebook, where we can actually 
> inspect 
> >>>> the values of various statements along the way - take a look here 
> instead: 
> >>>> 
> http://nbviewer.ipython.org/github/tlycken/IJulia-Notebooks/blob/master/ 
> >>>> A%20more%20thorough%20look%20at%20Julia's%20%22double% 
> >>>> 20colon%22%20syntax.ipynb 
> >>>> 
> >>>> I hope it makes things a little clearer. I tried to base it on the 
> >>>> relevant section on `::` in the manual (http://docs.julialang.org/en/ 
> >>>> latest/manual/types/#type-declarations) and expand it with more 
> >>>> examples etc, so I hope it's possible to see the connections. 
> >>>> 
> >>> 
> >>>  / Toivo 
> >>> 
> >> 
> >> 
>
> -- 
>
>

Reply via email to