Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function arguments are inferred to be of type Any despite annotation (v0.3.0-prerelease) #6813

Closed
yurivish opened this issue May 12, 2014 · 19 comments

Comments

@yurivish
Copy link
Contributor

In the definition of getindex() below, which is taken from a Treap implementation discussed in this julia-users thread, inspecting variable types using code_typed reveals that both t and index are inferred to be of type Any despite being annotated with specific types in the function declaration.

Here's a minimal piece of code that will reproduce the issue (load the Treap code first):

t = MinTreap{Int}()
add!(t, 50)
@code_typed t.root[1]

For convenience, here's the definition of getindex() that is being invoked above:

function Base.getindex{K}(t::TreapNode{K}, index::Int)
    @assert 1 <= index <= t.size "Invalid treap index: $index."
    while t.left.size != index - 1
        if index <= t.left.size
            t = t.left
        else
            index = index - t.left.size - 1
            t = t.right
        end
    end
    t.key
end
@yurivish yurivish changed the title Function arguments are type-inferred to be of type Any despite annotation Function arguments are inferred to be of type Any despite annotation May 12, 2014
@yurivish yurivish changed the title Function arguments are inferred to be of type Any despite annotation Function arguments are inferred to be of type Any despite annotation [0.3] May 12, 2014
@yurivish yurivish changed the title Function arguments are inferred to be of type Any despite annotation [0.3] Function arguments are inferred to be of type Any despite annotation [Julia v0.3.0-prerelease] May 12, 2014
@yurivish yurivish changed the title Function arguments are inferred to be of type Any despite annotation [Julia v0.3.0-prerelease] Function arguments are inferred to be of type Any despite annotation (v0.3.0-prerelease) May 12, 2014
@JeffBezanson
Copy link
Member

The types in the function signature only serve as a dispatch spec; they don't "declare" the variables to be of those types in a case like this where the arguments are assigned to. It has to be this way, to make dispatch and declaration orthogonal.

I was able to fix it by adding these declarations at the beginning of the function:

    t::TreapNode{K}
    index::Int

One could argue that this orthogonality is not so important, and you just have to expect arguments with types to have fixed types. But the current behavior is intentional and we'll probably keep it that way for now.

@yurivish
Copy link
Contributor Author

Understood – thanks for the diagnosis. I had thought that type annotations in the signature had the effect as those in the two lines you added.

For my understanding, could you give an example of a case where the current behavior is beneficial?

@IainNZ
Copy link
Member

IainNZ commented May 12, 2014

So @JeffBezanson is then a failure in some sense of the type inference, and is thus fixable?

@JeffBezanson
Copy link
Member

Sometimes people write code like

function foo(x::Int)
    x = float(x)
    ...
end

and expect the type of x to change. It would be a bit confusing if x were type-const by default.

@mlubin
Copy link
Member

mlubin commented May 12, 2014

But that doesn't seem to be the case here?

@JeffBezanson
Copy link
Member

In the new version of the code, the abstract Treap type has been removed, so the type of t.left is always known exactly. With that change, the extra declarations are not necessary.

@IainNZ
Copy link
Member

IainNZ commented May 12, 2014

Oh, yes, indeed. 👍

@yurivish
Copy link
Contributor Author

For what it's worth, I think that the code was prettier and more expressive when empty and nonempty nodes had different types. The change in the new version was made for performance reasons alone (and does improve the speed of treap operations significantly).

I wonder if there's any way to use the type system to encode the distinction while maintaining performance?

@JeffBezanson
Copy link
Member

It would be nice to have a way to "seal" an abstract type so that its set of subtypes is fixed. Then you would get more of the benefits of tagged unions as in many functional languages.

@StefanKarpinski
Copy link
Member

Isn't a sealed abstract type just a type union? The only difference is that an abstract type is declared before its constituent types, whereas a type union must be defined after. However, if we allowed referring to not-yet-declared types that are defined later in the same closed module (i.e. not Main), then we would get both for free and solve the mutually recursive types problem.

@JeffBezanson
Copy link
Member

I'm not sure they're equivalent when parameters are involved. For example

abstract A{P}

type Sub1{T} <: A{T}
end

type Sub2 <: A{Int8}
end

@StefanKarpinski
Copy link
Member

Can't you get around that with a typealias? Close abstract types seem kind of featurey.

@JeffBezanson
Copy link
Member

I agree it feels featurey, but I don't see how to express my example with typealias.

@StefanKarpinski
Copy link
Member

typealias Sub{T} Union(Sub1{T},Sub2)

@JeffBezanson
Copy link
Member

In my example Sub2 is only a subtype of A{Int8}, not any other A{T}.

@StefanKarpinski
Copy link
Member

What is the abstract type that you want to close here? A?

@JeffBezanson
Copy link
Member

Yes, that's the only abstract type in the example.

@StefanKarpinski
Copy link
Member

There are an unbounded number of abstract types in the example: Sub1, A, A{Int8}, A{Symbol}, A{A}, etc. I don't get how Sub2 being only a subtype of A{Int8} is relevant – Sub2 <: A{Int8} <: A. The concrete types that are subtypes of A at the end of your code snippet are Sub1{T} for any T and Sub2. Those are precisely the concrete types that are subtypes of the Sub typealias.

@JeffBezanson
Copy link
Member

With the typealias, Sub2 is a subtype of A{Float64}, and in my example it's not. The behavior is not identical.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants