On Fri, 2014-05-16 at 17:18, Toivo wrote:
> Yes, that is exactly the kind of example that I'm referring to. (As is the 
> example that started this thread as well.)

Haha, well sometimes I just take a bit longer to figure things
out... ;-)

> 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.

It looks like the type T is fixed by the first argument in which T
features and for all other arguments of type T it then requires type
equality.

Anyway, I think this is not a big issue.  It only crops up with
composite types with an abstract type parameter, which is usually not
the case.  Otherwise it's pretty intuitive.  If triangular dispatch gets
implemented (I think this is the name it has been referred to), then
Leah's second try will work:

function unshift!{T,I<:T}(l::List{T},item::I)
...
end

Anyway, is there a solution to Leah's problem?  Maybe just leave the
second ::T away and let the Node constructor error on any unsuitable
item?

function Base.unshift!{T}(l::List{T},item)
         new_node = Node{T}(item,l.head)
         l.head = new_node
         return l
end


> 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