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

RFC: Provide a way to get the inferred return type of a function #6692

Closed
wants to merge 3 commits into from

Conversation

simonster
Copy link
Member

This PR implements Base.return_type(function, types) to get the inferred return type of a function for a given set of input types. Type inference knows about Base.return_type, and when the function and types are known at compile time, the call can be eliminated entirely.

This would make it possible to provide type inference for memoized functions, and it is the proper way to provide the right typeassert for the FFT inverse in #6193. It could also be used to determine the element type of the returned array for map and broadcast (see also #210, #670, #2938, #4883, #6548, and others), although for map the overhead might be undesirable, and there is some debate over whether making the concrete output types of functions depend on type inference is a good idea.

I am not entirely confident in the correctness of this code, so if this functionality is useful enough to include it, please take a close look.

Implements Base.return_type(function, types) to get the inferred return
type of a function for a given set of input types. Type inference knows
about Base.return_type, and when the function and types are known at
compile time, the call can be eliminated entirely.
@simonster simonster changed the title Provide a way to get the inferred return type of a function RFC: Provide a way to get the inferred return type of a function Apr 29, 2014
@quinnj
Copy link
Member

quinnj commented Apr 29, 2014

If we have this, it'd be great to have the corresponding @return_type macro similar to the @code_llvm family. See #5832

@timholy
Copy link
Member

timholy commented Apr 30, 2014

Looks like this might have been developed outside of Base, and has some module scoping which is not necessary?

But this seems pretty intriguing.

@porterjamesj
Copy link
Contributor

This would also be cool to have for tooling like TypeCheck.jl and similar projects that might pop up in the future.

@ivarne
Copy link
Member

ivarne commented Apr 30, 2014

Is this the same functionality as @JeffBezanson's suggested @typeof macro in #6114 (comment)? He also explained it somewhere else, but I can't find it.

@simonster
Copy link
Member Author

If I understand correctly, @typeof is @vtjnash's @static_typeof macro from #5588. This is certainly related but a bit different. The output of return_type only depends only on the function and types it's passed, and not on type inference for the rest of the calling function's body. This may make it behave a little more predictably than @typeof, although it still depends on type inference for the passed function, so it's still dangerous. While for many uses @typeof and return_type are exchangeable, the overlap in functionality is not complete: return_type works even when the function or types are not known at compile time (e.g. map), although in that case type inference does not know what type it will return, but it does not allow access to type inference for the calling function body (e.g. @vtjnash's case 1 in #5588).

This is stricter than necessary but should work.
@vtjnash
Copy link
Member

vtjnash commented Apr 30, 2014

What happens in the pathological case?

F() = return_type(F, ())

@simonster
Copy link
Member Author

It looks like type inference runs four times and then spits out Any.

@vtjnash
Copy link
Member

vtjnash commented May 1, 2014

How about other similarly foolish options then:

type Z{T} end
f{T}(::Type{Z{T}}) = return_type(f, (Z{T-1},)) + return_type(f, (Z{T-2},))
f(::Type{Z{1}}) = Z{1}
f(::Type{Z{2}}) = Z{1}
+{A,B}(::Type{Z{A}}, ::Type{Z{B}}) = Z{A+B}

@simonster
Copy link
Member Author

Maybe the last three lines should actually construct the types? In any case, maybe I am missing something, but I'm not sure why this is problematic since we don't do constant folding in inference. The first definition is inferred as Any (although I think I could probably bound this as Type or more specific) and we throw a MethodError for f(Z{T}) if T is not in {1,2,3}.

@vtjnash
Copy link
Member

vtjnash commented May 1, 2014

If you construct the types, then you should be able to get rid of the uses of Type{}. I don't see why f(Z{3}) would throw a MethodError, but I might have typo's. The goal here is to make sure your proposal won't potentially incur the halting problem or other unexpected behaviors.

@stevengj
Copy link
Member

stevengj commented Jun 6, 2014

As @simonster mentioned, something like this will help with broadcast (to avoid problems like those raised in #6547 and #4883); I want it because it will allow us to finally replace vectorize_2arg with broadcast (#4363).

@simonster
Copy link
Member Author

It seems that we are moving away from allowing type inference to affect return types, so this PR is probably not the right solution to many of the issues it was designed to solve. I'm going to close it, but I'll leave the branch around for a bit just in case we want to revisit it.

@simonster simonster closed this Aug 11, 2014
@simonster simonster mentioned this pull request Aug 18, 2014
@stevengj
Copy link
Member

Yet another reason I'd like to have something like this: testing that type-inference is working correctly is currently a pain. (See e.g. #9772.) Nevermind, the @inferred macro handles this.

@KristofferC KristofferC deleted the sjk/return_type branch June 4, 2018 08:31
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

Successfully merging this pull request may close these issues.

7 participants