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, [email protected] <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
> >> <[email protected]<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
> >>>
> >>
> >>
>
> --
>
>