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 types #210

Closed
StefanKarpinski opened this issue Oct 12, 2011 · 24 comments
Closed

function types #210

StefanKarpinski opened this issue Oct 12, 2011 · 24 comments
Assignees

Comments

@StefanKarpinski
Copy link
Member

Then just settle for map returning a type of the map function as the output array type.

@ghost ghost assigned JeffBezanson Oct 12, 2011
@6e441f9c
Copy link

6e441f9c commented Apr 8, 2012

As stated, issue looks like a theoretical problem. An example where it matters:
map(join, ["z", "я"])

map decides that the type is simply ASCIIString after the first element. Backtrace is also suboptimal:

invalid ASCII sequence
in check_ascii at string.jl:528
in assign at array.jl:239
in map_to2 at array.jl:1138
in map at array.jl:1147

@StefanKarpinski
Copy link
Member Author

Thanks. This is very much not a theoretical problem; see #670.

@6e441f9c
Copy link

6e441f9c commented Nov 5, 2012

I am currently rewriting some Julia code and got biten by this again. Fix is easy, but understanding what goes on...

Is it a good idea to have verbose messages for such cases? It could explicitly say that map chose wrong type for the list based on the first element and that explicit type-cast is needed.

This would reduce cost for user from "Wait What Why?!" to "Oh, a minor glitch, nevermind", as far as I understand.

@mlubin
Copy link
Member

mlubin commented Nov 9, 2012

I also have a use case where it would be very helpful to be able to access type inference of an expression programmatically.

@WestleyArgentum
Copy link
Member

Bump

@filmackay
Copy link

Is this the kind of syntax that would be Julian?

function map{S,R}(f::S->R, arr::Array{S,1})::Array{R,1} # return type just for fun
# or:
function map{S,R}(f::((S)::R), arr::Array{S,1})::Array{R,1}

@filmackay
Copy link

It seems to me this is the most important that is holding back Julia. Everywhere I turn this seems to surface - is there anyone actively working on function types?

Of course there has to be a "no. 1" item with anything. Not to denigrate Julia at all (I love multiple dispatch).. but onwards and upwards and all that :)

ps. my no. 2 & 3 would be triangular dispatch and return types!

@MikeInnes
Copy link
Member

I think that the ability to query types at runtime would be extremely useful, e.g.

return_type(*, Int, Int) == Int
return_type(*, Int, Float64) == Float64
return_type(my_func, Int) == Union(ASCIIString, Nothing)

As far as I know, Julia has this information already – exposing it would solve the map problem without adding the complexity of a real function type.

Also, it might be helpful if functions like map and broadcast took an optional explicit return element type. I know there's map! but it's a bit less convenient – if you like the idea I can work on a PR.

@toivoh
Copy link
Contributor

toivoh commented Apr 16, 2014

There used to be an unexported function broadcast_T for precisely this purpose (it seems to have gone missing in the latest master, though). There was some discussion on how to best expose this functionality in https://groups.google.com/forum/#!searchin/julia-users/broadcast_T%7Csort:relevance%7Cspell:false/julia-users/ZgxIa7vUe74/ebZhHMyFuVUJ, but no conclusion. I would definitely support an optional result type argument to map and broadcast.

The problem with querying return type information from type inference is that it's too volatile. Changes in type inference may change which type you get. Changes in one place in the code may cause cascading changes in types inferred elsewhere. Comprehensions currently exploit type inference to pick a return type, but as I understand it the desire is to move away from this, not to do it in more places.

See also Stefan's comments in #670.

@MikeInnes
Copy link
Member

How about querying return_type and using it if it's a concrete type like Int, but otherwise falling back to Any? That way you'd have performant, C-compatible arrays when possible, but at the same time avoid volatile Union types (which AFAIK don't have much of a performance benefit over Any).

If you need a particular return type (e.g. for dispatch), it makes sense to specify it explicitly: map(f, Union(String, Int), xs, ys).

There could still be edge-case problems, but I imagine they'd be rare – especially as type inference matures.

@jey
Copy link
Contributor

jey commented Aug 15, 2014

Out of curiosity, what's the core team's stance on this? I see that other issues are being deduped to this, but I'm wondering whether this is undecided, is accepted and literally targeted to 1.0, or more abstractly targeted to sometime in the indefinite future.

@JeffBezanson
Copy link
Member

Well, we don't know what this issue means exactly. The milestone is not real yet.
We know certain things are good:

  1. A better result type from map (already done)
  2. Better performance

There are a couple ways to get (2), and function types don't necessarily have to be part of it. Function types and generic functions are like oil and water. There are certainly a few ways we could use them, but none are an obvious fit for multiple dispatch.

@toivoh
Copy link
Contributor

toivoh commented Aug 15, 2014

It would also be good to get a better result type from broadcast, and anything else that someone wants to cook up that stores multiple return values from a user supplied function.

@JeffBezanson
Copy link
Member

Latest discussion in #10269

@vtjnash
Copy link
Member

vtjnash commented Mar 8, 2016

@JeffBezanson i think you get the honor of closing this one now

@StefanKarpinski
Copy link
Member Author

@vtjnash – I think you may be misunderstanding the intended meaning of this issue. Yes, functions are types now in the Julia sense, but not in the sense that static languages generally mean it. I think the conclusion is that we cannot do this and this issue is superseded by a combination of #1090 and #7258 and map behaving in the same inference-independent manner as comprehensions.

@sighoya
Copy link

sighoya commented Oct 1, 2017

I'am a little bit confused about:
210
10269
1090

What is the current state of typed functions?
If we had two functions

f(x::Int64)::Int64

g(x::T)::S where {S,T}
do we get by typeof(f), and (g) only the type "Function" or a more specific result like

typeof(f) == Function{(Int64,),Int64}
typeof(g) == Function{(T,),S}

The latter would be better as we can filter out functions that we do not want.
What is the problem with the map function, do we want it to be typesafe?
A possible solution with extended syntax would be

map(f::Function{Tuple{S..},R},x::Tuple{T...}..)::Tuple{R...} where {R,S<:DataType, T}=...
I will explain it:
x::T... means vararg x with the same parametric type T
x::T.. means vararg x with different parametric types ( x1::T1, x2::T2,x3::T3,...)
x::Tuple{T...}.. means each Tuple xi has elements of one type, but the type from tuple to tuple in the vararg list can vary ( x1::Tuple{T1...},x2::Tuple{T2...},...)
x::Tuple{S..} means x is tuple of heterogenous type (x=Tuple{T1,T2,T3,T4,...})
S<:DataType ensures that S is a higher order generic at least of rank 2, why?
Because a function f::Function{(Int64,Float64,...),R} may be applied to vararg list of tuples where the second tuple may not include elems of Type Float64. Therefore, it is better only to take polymorphic functions into the map function.
The Tuple type could of course be exchanged by a more general collection type.
My assumption of a typed map function is that each xi in x contains only members of the same type, but the type from the elems in xi-1 to xi can vary.
If also the type in each xi can vary, then the use of the standard map in Base would be more appropriate.

@yuyichao
Copy link
Contributor

yuyichao commented Oct 1, 2017

do we get by typeof(f), and (g) only the type "Function" or a more specific result like

Neither, they have their own type but they don't and can't (as it doesn't make any sense) to give you argument and return types.

@sighoya
Copy link

sighoya commented Oct 1, 2017

Does it have to do something with methods versus function, where a method has only one argument type tuple and one return type and functions multiple argument type tuples and return types?

@JeffBezanson
Copy link
Member

That's part of the issue, yes, but it's mostly that the language is dynamically typed so functions do not have meaningful return types (other than the types of values they actually return at run time).

@sighoya
Copy link

sighoya commented Oct 2, 2017

Disregarding the multiple method problem, mabye, a special function type could be created for functions in which the types are hardcoded by the user? For instance, something like StaticFunction{Tuple{Int64,Float64},Int64}

@KristofferC
Copy link
Member

StefanKarpinski pushed a commit that referenced this issue Feb 8, 2018
KristofferC added a commit that referenced this issue Mar 16, 2018
(cherry picked from commit ef37aa7d4f68e47f74346da40daa671528385755)
KristofferC added a commit that referenced this issue Mar 17, 2018
(cherry picked from commit ef37aa7d4f68e47f74346da40daa671528385755)
@JeffBezanson JeffBezanson removed this from the 2.0+ milestone Nov 4, 2018
cmcaine pushed a commit to cmcaine/julia that referenced this issue Sep 24, 2020
@oscardssmith
Copy link
Member

Is this still a thing? It seems closable as moot.

@oscardssmith
Copy link
Member

Closing since we aren't going to change this.

Keno pushed a commit that referenced this issue Oct 9, 2023
This happens when the call is module-scoped.
Fixes JuliaDebug/Debugger.jl#141
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