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

WIP: Staged functions #7474

Merged
merged 11 commits into from Sep 24, 2014

Conversation

Projects
None yet
@Keno
Member

Keno commented Jun 30, 2014

This is my work in progress for staged functions (#7311). It almost works, but there's a few things left to discuss.

  • Syntax: @StefanKarpinski hates stagedfunction foo(); end. @JeffBezanson proposed staged foo(); end, though there's the question if we want to reserve that keyword
  • Caching. E.g. consider the following:
julia> stagedfunction foo(a,b)
       println(a,b)
       :(a+b)
       end

julia> foo(1,2)
Int64Int64
3

julia> foo(1,2)
3

julia> bar() = foo(1,2)
bar (generic function with 1 method)

julia> bar()
Int64Int64
Int64Int64
3

julia> bar()
3

julia> baz() = foo(1,2)
baz (generic function with 1 method)

julia> baz()
Int64Int64
Int64Int64
3

Hopefully calling the staged function that many times can be avoided. In any case, this point isn't critical.

  • Staged functions throwing errors. I'm not handling this yet. In the runtime case this mostly works already, but for type inference we need to intercept and return Any/NF.
  • Documentation

Thanks to @timholy and @jakebolewski for hacking on this with me on Saturday.

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jun 30, 2014

Member

I don't think we should use staged. Not worth taking a dictionary word for this.

Member

JeffBezanson commented Jun 30, 2014

I don't think we should use staged. Not worth taking a dictionary word for this.

Show outdated Hide outdated base/inference.jl
@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jun 30, 2014

Member

Hmm, that is odd behavior. It seems to suggest that the specifically-compiled variants are not getting inserted into the methods table properly. What does methods(foo) say after you call foo(1,2)? What does it say at the end after defining bar and baz?

Member

timholy commented Jun 30, 2014

Hmm, that is odd behavior. It seems to suggest that the specifically-compiled variants are not getting inserted into the methods table properly. What does methods(foo) say after you call foo(1,2)? What does it say at the end after defining bar and baz?

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jun 30, 2014

Member

Also, am I right in guessing that more needs to be done to handle splatted arguments?

Member

timholy commented Jun 30, 2014

Also, am I right in guessing that more needs to be done to handle splatted arguments?

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jun 30, 2014

Member

A rule of thumb is that the system should behave as if the code generator did not exist, and all of its possible outputs have been written manually in a magic infinite source file.

Member

JeffBezanson commented Jun 30, 2014

A rule of thumb is that the system should behave as if the code generator did not exist, and all of its possible outputs have been written manually in a magic infinite source file.

@Keno

This comment has been minimized.

Show comment
Hide comment
@Keno

Keno Jun 30, 2014

Member

I'm not sure about splatted arguments. Haven't tried. About the method cache, I think it is being entered correctly (see the second call to foo). The problem is probably inlining.

@JeffBezanson That analogy doesn't really work though, unless you want to add the generated methods to mt->defs and even then they would only be there after being called.

Member

Keno commented Jun 30, 2014

I'm not sure about splatted arguments. Haven't tried. About the method cache, I think it is being entered correctly (see the second call to foo). The problem is probably inlining.

@JeffBezanson That analogy doesn't really work though, unless you want to add the generated methods to mt->defs and even then they would only be there after being called.

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jun 30, 2014

Member

The rule of thumb should be followed to the extent possible. It's there to resolve design decisions that could go either way.

Member

JeffBezanson commented Jun 30, 2014

The rule of thumb should be followed to the extent possible. It's there to resolve design decisions that could go either way.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jul 1, 2014

Member

Looks like we're super-close, but that splatting seems to be a problem. Check this out (we are so close to having awesome array views!):

A = rand(5,5,3);
B = slice(A, 1:3, 2, 1:3);
stagedfunction mygetindex(S::SubArray, indexes::Real...)
    println(S)
    T, N, A, I = S.parameters
    if N != length(indexes)
        error("Wrong number of indexes supplied")
    end
    NP = length(I)
    indexexprs = Array(Expr, NP)
    j = 1
    for i = 1:NP
        println(i)
        println(j)
        println(I[i])
        if I[i] == Int
            indexexprs[i] = :(S.indexes[$i])
        else
            indexexprs[i] = :(S.indexes[$i][indexes[$j]])
            j += 1
        end
    end
    println(indexexprs)
    ex = :(S[$(indexexprs...)])
    println(ex)
    ex
end

julia> mygetindex(B, 2, 2)
SubArray{Float64,2,Array{Float64,3},(UnitRange{Int64},Int64,UnitRange{Int64})}
1
1
UnitRange{Int64}
2
2
Int64
3
2
UnitRange{Int64}
[:(S.indexes[1][indexes[1]]),:(S.indexes[2]),:(S.indexes[3][indexes[2]])]
S[S.indexes[1][indexes[1]],S.indexes[2],S.indexes[3][indexes[2]]]
ERROR: syntax: "Array{Any, 1}" is not a valid function argument name

Ideally the compiled function should have a signature like this:

mygetindex(S::SubArray{Float64,2,Array{Float64,3},(UnitRange{Int64},Int64,UnitRange{Int64})}, indexes_1::Int, indexes_2::Int)

but I think it's just the naming that's causing problems.

Member

timholy commented Jul 1, 2014

Looks like we're super-close, but that splatting seems to be a problem. Check this out (we are so close to having awesome array views!):

A = rand(5,5,3);
B = slice(A, 1:3, 2, 1:3);
stagedfunction mygetindex(S::SubArray, indexes::Real...)
    println(S)
    T, N, A, I = S.parameters
    if N != length(indexes)
        error("Wrong number of indexes supplied")
    end
    NP = length(I)
    indexexprs = Array(Expr, NP)
    j = 1
    for i = 1:NP
        println(i)
        println(j)
        println(I[i])
        if I[i] == Int
            indexexprs[i] = :(S.indexes[$i])
        else
            indexexprs[i] = :(S.indexes[$i][indexes[$j]])
            j += 1
        end
    end
    println(indexexprs)
    ex = :(S[$(indexexprs...)])
    println(ex)
    ex
end

julia> mygetindex(B, 2, 2)
SubArray{Float64,2,Array{Float64,3},(UnitRange{Int64},Int64,UnitRange{Int64})}
1
1
UnitRange{Int64}
2
2
Int64
3
2
UnitRange{Int64}
[:(S.indexes[1][indexes[1]]),:(S.indexes[2]),:(S.indexes[3][indexes[2]])]
S[S.indexes[1][indexes[1]],S.indexes[2],S.indexes[3][indexes[2]]]
ERROR: syntax: "Array{Any, 1}" is not a valid function argument name

Ideally the compiled function should have a signature like this:

mygetindex(S::SubArray{Float64,2,Array{Float64,3},(UnitRange{Int64},Int64,UnitRange{Int64})}, indexes_1::Int, indexes_2::Int)

but I think it's just the naming that's causing problems.

@porterjamesj

This comment has been minimized.

Show comment
Hide comment
@porterjamesj

porterjamesj Jul 1, 2014

Member

💯

just wanted to register my excitement and say it was very cool to see the initial prototype work on Saturday :)

Member

porterjamesj commented Jul 1, 2014

💯

just wanted to register my excitement and say it was very cool to see the initial prototype work on Saturday :)

@porterjamesj

This comment has been minimized.

Show comment
Hide comment
@porterjamesj

porterjamesj Jul 1, 2014

Member

also is this going to make it into 0.3 or will it be an 0.4-pre thing?

Member

porterjamesj commented Jul 1, 2014

also is this going to make it into 0.3 or will it be an 0.4-pre thing?

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jul 1, 2014

Member

Definitely not 0.3 material.

Member

timholy commented Jul 1, 2014

Definitely not 0.3 material.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Jul 1, 2014

Contributor

While this can legitimately be called a staged function, I feel that the concept of staged functions is much more broad then how they are being applied here. Calling this a stage function would be presumptuous since there could be other functions that fit the definition of what a staged function is.

Since this is a function/macro that operates on types why not have the syntax be

typefunction foo(a,b) #or tfunction foo(a,b)

or

typemacro foo(a,b) #or tmacro foo(a,b)
Contributor

lstagner commented Jul 1, 2014

While this can legitimately be called a staged function, I feel that the concept of staged functions is much more broad then how they are being applied here. Calling this a stage function would be presumptuous since there could be other functions that fit the definition of what a staged function is.

Since this is a function/macro that operates on types why not have the syntax be

typefunction foo(a,b) #or tfunction foo(a,b)

or

typemacro foo(a,b) #or tmacro foo(a,b)
@IainNZ

This comment has been minimized.

Show comment
Hide comment
@IainNZ

IainNZ Jul 1, 2014

Member

typemacro does have some good things going to for it too on top of that, in that its not likely to be wanted in user code, reduces possible confusion with plain old functions, and is short

Member

IainNZ commented Jul 1, 2014

typemacro does have some good things going to for it too on top of that, in that its not likely to be wanted in user code, reduces possible confusion with plain old functions, and is short

@quinnj

This comment has been minimized.

Show comment
Hide comment
@quinnj

quinnj Jul 1, 2014

Member

typemacro has a nice ring to it. What about call site syntax? Do we want to visually distinguish, like macros, that "something funny is going on here"? I think Jeff mentioned @@foo(a,b) syntax is available for something.

Member

quinnj commented Jul 1, 2014

typemacro has a nice ring to it. What about call site syntax? Do we want to visually distinguish, like macros, that "something funny is going on here"? I think Jeff mentioned @@foo(a,b) syntax is available for something.

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jul 1, 2014

Member

I fail to see how it's presumptuous to apply a term to something that fits its definition. What would it mean for another design or implementation to be "more staged" than this?

This can't have different syntax; the whole point is that it's part of the behavior of a generic function. Some methods might be staged, others not, transparently.

Member

JeffBezanson commented Jul 1, 2014

I fail to see how it's presumptuous to apply a term to something that fits its definition. What would it mean for another design or implementation to be "more staged" than this?

This can't have different syntax; the whole point is that it's part of the behavior of a generic function. Some methods might be staged, others not, transparently.

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jul 1, 2014

Member

I would also be ok with a more concrete, less-jargony name possibly evoking "code generator". or "generated method", or something along those lines.

Member

JeffBezanson commented Jul 1, 2014

I would also be ok with a more concrete, less-jargony name possibly evoking "code generator". or "generated method", or something along those lines.

@quinnj

This comment has been minimized.

Show comment
Hide comment
@quinnj

quinnj Jul 1, 2014

Member

Ah, I didn't catch that these will mesh with generic functions. Very cool.

Member

quinnj commented Jul 1, 2014

Ah, I didn't catch that these will mesh with generic functions. Very cool.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Jul 1, 2014

Contributor

@JeffBezanson The presumptuous bit is to allocate a piece of syntax for something that describes a family of functions. I would be a bit like a language defining sin(x) as trigfunction(x) . If the stagedfunction syntax could be applied to all types of staged functions it would be fine.

I think the syntax

typemacro foo(a,b)
    println(a,b)
end

foo(1,2)

would be fine since in your initial mailing list post you say

"These are a lot like macros, except they operate on types instead of
expressions. " -Jeff Bezanson

This may however cause confusion with people trying to call them like macros.(which is why I also suggested typefunction)

Contributor

lstagner commented Jul 1, 2014

@JeffBezanson The presumptuous bit is to allocate a piece of syntax for something that describes a family of functions. I would be a bit like a language defining sin(x) as trigfunction(x) . If the stagedfunction syntax could be applied to all types of staged functions it would be fine.

I think the syntax

typemacro foo(a,b)
    println(a,b)
end

foo(1,2)

would be fine since in your initial mailing list post you say

"These are a lot like macros, except they operate on types instead of
expressions. " -Jeff Bezanson

This may however cause confusion with people trying to call them like macros.(which is why I also suggested typefunction)

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jul 1, 2014

Member

I hope we can find a better name. type function or t function is a term of art used elsewhere in the system to refer to functions that operate within the type domain, used by inference.

Member

JeffBezanson commented Jul 1, 2014

I hope we can find a better name. type function or t function is a term of art used elsewhere in the system to refer to functions that operate within the type domain, used by inference.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Jul 1, 2014

Contributor

Also something to consider would be something like type annotations but for functions. Like

function foo{typed}(a,b) #or foo::typed(a,b)
end

something that describes what aspects of the arguments are passed into the function e.g. in a normal function their values are passed but in a typed function their types are passed.

Contributor

lstagner commented Jul 1, 2014

Also something to consider would be something like type annotations but for functions. Like

function foo{typed}(a,b) #or foo::typed(a,b)
end

something that describes what aspects of the arguments are passed into the function e.g. in a normal function their values are passed but in a typed function their types are passed.

@Keno

This comment has been minimized.

Show comment
Hide comment
@Keno

Keno Jul 1, 2014

Member

Both

function foo{typed}(a,b)

and

foo::typed(a,b)

already have a meaning.

Member

Keno commented Jul 1, 2014

Both

function foo{typed}(a,b)

and

foo::typed(a,b)

already have a meaning.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Jul 1, 2014

Contributor

@Keno then perhaps something like

function{Type} foo(a,b)

I kinda like this idea. Instead of Type where it passes the argument's type it could be Symbol where it just passes the argument's symbol. Default would where it passes the argument's Value

Anyway I've said my piece. I realize this is a bike shed issue so I am going to shut up about it now and let you experts take care of it.

Contributor

lstagner commented Jul 1, 2014

@Keno then perhaps something like

function{Type} foo(a,b)

I kinda like this idea. Instead of Type where it passes the argument's type it could be Symbol where it just passes the argument's symbol. Default would where it passes the argument's Value

Anyway I've said my piece. I realize this is a bike shed issue so I am going to shut up about it now and let you experts take care of it.

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Jul 1, 2014

Member

typemacro or type macro (one less keyword plus more readable) strike me as good.

Member

StefanKarpinski commented Jul 1, 2014

typemacro or type macro (one less keyword plus more readable) strike me as good.

@porterjamesj

This comment has been minimized.

Show comment
Hide comment
@porterjamesj

porterjamesj Jul 1, 2014

Member

typemacro or similar seems like it might be confusing to some in that you don't invoke these like macros; they just generate functions and lodge them in the method table for you.

Member

porterjamesj commented Jul 1, 2014

typemacro or similar seems like it might be confusing to some in that you don't invoke these like macros; they just generate functions and lodge them in the method table for you.

@mlubin

This comment has been minimized.

Show comment
Hide comment
@mlubin

mlubin Jul 1, 2014

Member

typemacro seems confusing on the part of the user, because these functions are called like functions and not with the @ prefix. My vote is for stagedfunction.

Member

mlubin commented Jul 1, 2014

typemacro seems confusing on the part of the user, because these functions are called like functions and not with the @ prefix. My vote is for stagedfunction.

@mlubin

This comment has been minimized.

Show comment
Hide comment
@mlubin
Member

mlubin commented Jul 1, 2014

@yurivish

This comment has been minimized.

Show comment
Hide comment
@yurivish

yurivish Jul 1, 2014

Contributor

What about genfunction or functiongen? These are like stagedfunction, but are a little shorter and capture the idea that what you're defining is a function generator.

Contributor

yurivish commented Jul 1, 2014

What about genfunction or functiongen? These are like stagedfunction, but are a little shorter and capture the idea that what you're defining is a function generator.

@porterjamesj

This comment has been minimized.

Show comment
Hide comment
@porterjamesj
Member

porterjamesj commented Jul 1, 2014

@stevengj

This comment has been minimized.

Show comment
Hide comment
@stevengj

stevengj Jul 1, 2014

Member

@mlubin, since they generate expressions, they are seem more like macros than functions, and hence I like typemacro. Couldn't the patch be changed to call them with @?

Member

stevengj commented Jul 1, 2014

@mlubin, since they generate expressions, they are seem more like macros than functions, and hence I like typemacro. Couldn't the patch be changed to call them with @?

@Keno

This comment has been minimized.

Show comment
Hide comment
@Keno

Keno Jul 1, 2014

Member

That way you couldn't have some methods of getindex that are staged.

Member

Keno commented Jul 1, 2014

That way you couldn't have some methods of getindex that are staged.

@ihnorton

This comment has been minimized.

Show comment
Hide comment
@ihnorton

ihnorton Jul 1, 2014

Member

How about annotating function or the function name: function @foo() function ~foo() @function foo, etc. (I think the last one captures the duality quite well).

Member

ihnorton commented Jul 1, 2014

How about annotating function or the function name: function @foo() function ~foo() @function foo, etc. (I think the last one captures the duality quite well).

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Jul 1, 2014

Member

To me this is quite distinct from macros. I think the best approach is something that straightforwardly describes what the thing is. To that end genfunction is not bad.

Member

JeffBezanson commented Jul 1, 2014

To me this is quite distinct from macros. I think the best approach is something that straightforwardly describes what the thing is. To that end genfunction is not bad.

@mlubin

This comment has been minimized.

Show comment
Hide comment
@mlubin

mlubin Jul 1, 2014

Member

@stevengj, from the user's perspective, whether a function is staged or not is really just an implementation detail. I don't think it deserves the @ syntax which is a warning that anything can happen.

Member

mlubin commented Jul 1, 2014

@stevengj, from the user's perspective, whether a function is staged or not is really just an implementation detail. I don't think it deserves the @ syntax which is a warning that anything can happen.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Jul 2, 2014

Contributor

These suggestions are just for fun

funcro  # FUNction maCRO
maction  #MACro funcTION
tycro  # TYpe maCRO
tytion  #TYpe funcTION
macrope  #MACRO tyPE
funpe  #FUNction tyPE
Contributor

lstagner commented Jul 2, 2014

These suggestions are just for fun

funcro  # FUNction maCRO
maction  #MACro funcTION
tycro  # TYpe maCRO
tytion  #TYpe funcTION
macrope  #MACRO tyPE
funpe  #FUNction tyPE
@tknopp

This comment has been minimized.

Show comment
Hide comment
@tknopp

tknopp Jul 2, 2014

Contributor

I think its pretty obvious that we have to chose funcro :-)
Its such a nice word creation.

Contributor

tknopp commented Jul 2, 2014

I think its pretty obvious that we have to chose funcro :-)
Its such a nice word creation.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jul 2, 2014

Member

Regarding splatting, I see two paths forward. The first is to declare a convention:

stagedfunction myfunc(a, b...)
     blah blah
end

myfunc("Hi", 3, 7)

generates a function with the following signature:

myfunc(a::ASCIIString, b_1::Int, b_2::Int)

The "convention" part is that _i gets tacked on to the name of the ith splatted argument. Naturally, the person implementing the body of this function has to be aware of this convention in order to write the body. (FYI this is the same naming convention that Cartesian uses.)

The second option is to declare that the returned expression needs to contain the full function definition (including signature), not just the body. @Keno, @jakebolewski, and I discussed this and all think it has some potential downsides. But if you don't like the idea of magical naming conventions, this seems to be the only alternative.

Personally I vote for the naming convention approach, but I'm curious what others think.

Member

timholy commented Jul 2, 2014

Regarding splatting, I see two paths forward. The first is to declare a convention:

stagedfunction myfunc(a, b...)
     blah blah
end

myfunc("Hi", 3, 7)

generates a function with the following signature:

myfunc(a::ASCIIString, b_1::Int, b_2::Int)

The "convention" part is that _i gets tacked on to the name of the ith splatted argument. Naturally, the person implementing the body of this function has to be aware of this convention in order to write the body. (FYI this is the same naming convention that Cartesian uses.)

The second option is to declare that the returned expression needs to contain the full function definition (including signature), not just the body. @Keno, @jakebolewski, and I discussed this and all think it has some potential downsides. But if you don't like the idea of magical naming conventions, this seems to be the only alternative.

Personally I vote for the naming convention approach, but I'm curious what others think.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jul 2, 2014

Member

I looked into the inlining thing. code_native indeed shows these are beautifully inlined. However, I still find this a little weird:

julia> stagedfunction foo(a,b)
              println(a,b)
              :(a+b)
              end
foo (generic function with 1 method)

julia> methods(foo)
# 1 method for generic function "foo":
foo(a,b) at none:2

julia> foo(1,2)
Int64Int64
3

julia> methods(foo)
# 1 method for generic function "foo":
foo(a,b) at none:2

I would have expected to see a foo(a::Int, b::Int) method showing up upon the second call to methods. @JeffBezanson?

Member

timholy commented Jul 2, 2014

I looked into the inlining thing. code_native indeed shows these are beautifully inlined. However, I still find this a little weird:

julia> stagedfunction foo(a,b)
              println(a,b)
              :(a+b)
              end
foo (generic function with 1 method)

julia> methods(foo)
# 1 method for generic function "foo":
foo(a,b) at none:2

julia> foo(1,2)
Int64Int64
3

julia> methods(foo)
# 1 method for generic function "foo":
foo(a,b) at none:2

I would have expected to see a foo(a::Int, b::Int) method showing up upon the second call to methods. @JeffBezanson?

@Keno

This comment has been minimized.

Show comment
Hide comment
@Keno

Keno Jul 2, 2014

Member

methods shows method definitions, which we aren't adding. We're adding an entry in the method cache instead. I'm not sure what to do about the varargs thing. We can't really change the signature. Maybe that needs to be resolved in codegen in general?

Member

Keno commented Jul 2, 2014

methods shows method definitions, which we aren't adding. We're adding an entry in the method cache instead. I'm not sure what to do about the varargs thing. We can't really change the signature. Maybe that needs to be resolved in codegen in general?

@mlubin

This comment has been minimized.

Show comment
Hide comment
@mlubin

mlubin Jul 2, 2014

Member

Relating to my request in #7311:

Ideally we'd like to write staged functions where the inputs are typed expression trees, or some transformation thereof. Is this feasible?

Jeff responded:

The macro can generate a call to a staged function, passing the expression trees and, separately, all of its leaves.

How precisely would this work, given this implementation? Staged functions take only types, so we couldn't pass the expression tree as a value. Could you encode the value of the expression tree as a type?

Member

mlubin commented Jul 2, 2014

Relating to my request in #7311:

Ideally we'd like to write staged functions where the inputs are typed expression trees, or some transformation thereof. Is this feasible?

Jeff responded:

The macro can generate a call to a staged function, passing the expression trees and, separately, all of its leaves.

How precisely would this work, given this implementation? Staged functions take only types, so we couldn't pass the expression tree as a value. Could you encode the value of the expression tree as a type?

@amitmurthy

This comment has been minimized.

Show comment
Hide comment
@amitmurthy

amitmurthy Nov 21, 2014

Member

Just generate?

Member

amitmurthy commented Nov 21, 2014

Just generate?

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Nov 21, 2014

Member

I like generated function, i.e., the past-tense. "generate" is imperative, suggesting the compiler should "do it right now," but that's not at all what's happening---each instantiation gets generated when the user needs it. In contrast, generated function implies that this is a declaration of type, and it would be grammatically incorrect to use the present tense for that.

But I'll join the chorus and just say that Jeff & Stefan should talk for 5 minutes and just make a decision.
I think it's fair to say that the rest of us are 95% likely to accept it.

Member

timholy commented Nov 21, 2014

I like generated function, i.e., the past-tense. "generate" is imperative, suggesting the compiler should "do it right now," but that's not at all what's happening---each instantiation gets generated when the user needs it. In contrast, generated function implies that this is a declaration of type, and it would be grammatically incorrect to use the present tense for that.

But I'll join the chorus and just say that Jeff & Stefan should talk for 5 minutes and just make a decision.
I think it's fair to say that the rest of us are 95% likely to accept it.

@johnmyleswhite

This comment has been minimized.

Show comment
Hide comment
@johnmyleswhite

johnmyleswhite Nov 21, 2014

Member

I do really like generated function as well. I'm not that opposed to whitespace keywords.

Agree that Jeff, Stefan and Viral should decide.

Member

johnmyleswhite commented Nov 21, 2014

I do really like generated function as well. I'm not that opposed to whitespace keywords.

Agree that Jeff, Stefan and Viral should decide.

@amitmurthy

This comment has been minimized.

Show comment
Hide comment
@amitmurthy

amitmurthy Nov 21, 2014

Member

Do whitespace keywords mean that generated continues to be a usable identifier on its own? That's a win.

Member

amitmurthy commented Nov 21, 2014

Do whitespace keywords mean that generated continues to be a usable identifier on its own? That's a win.

@tknopp

This comment has been minimized.

Show comment
Hide comment
@tknopp

tknopp Nov 21, 2014

Contributor

It certainly means more whitespace magic in the parser, no? ;-)

Contributor

tknopp commented Nov 21, 2014

It certainly means more whitespace magic in the parser, no? ;-)

@toivoh

This comment has been minimized.

Show comment
Hide comment
@toivoh

toivoh Nov 21, 2014

Member

Or generator function? I like generated function as well, but most of all I
like the functionality :)
On 21 Nov 2014 13:34, "Tobias Knopp" notifications@github.com wrote:

It certainly means more whitespace magic in the parser, no? ;-)


Reply to this email directly or view it on GitHub
#7474 (comment).

Member

toivoh commented Nov 21, 2014

Or generator function? I like generated function as well, but most of all I
like the functionality :)
On 21 Nov 2014 13:34, "Tobias Knopp" notifications@github.com wrote:

It certainly means more whitespace magic in the parser, no? ;-)


Reply to this email directly or view it on GitHub
#7474 (comment).

@toivoh

This comment has been minimized.

Show comment
Hide comment
@toivoh

toivoh Nov 21, 2014

Member

Though generator is a pretty useful variable name otoh.

Member

toivoh commented Nov 21, 2014

Though generator is a pretty useful variable name otoh.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Nov 21, 2014

Member

See above for concerns about generator.

The reason for the whitespace: we'll surely have generated type and generated immutable someday. Using the whitespace means that only one new keyword needs to be added to the parser, not three.

Also, I highlighted Jeff and Stefan above because I thought I remembered that Stefan seems the least happy of anyone with these recent name proposals. But then I just re-read some of the discussion, and Stefan said he'd go for generated function, so it seems there's really quite a lot of agreement on that name. However, since the parser is not my strong suit 😄 it won't be me who makes that change.

Member

timholy commented Nov 21, 2014

See above for concerns about generator.

The reason for the whitespace: we'll surely have generated type and generated immutable someday. Using the whitespace means that only one new keyword needs to be added to the parser, not three.

Also, I highlighted Jeff and Stefan above because I thought I remembered that Stefan seems the least happy of anyone with these recent name proposals. But then I just re-read some of the discussion, and Stefan said he'd go for generated function, so it seems there's really quite a lot of agreement on that name. However, since the parser is not my strong suit 😄 it won't be me who makes that change.

@johnmyleswhite

This comment has been minimized.

Show comment
Hide comment
@johnmyleswhite

johnmyleswhite Nov 21, 2014

Member

Man, DataFrames could be so much better if we had generated type.

Member

johnmyleswhite commented Nov 21, 2014

Man, DataFrames could be so much better if we had generated type.

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Nov 21, 2014

Member

It's bit the prettiest but how about just a @generated macro? No syntax changes required.

On Nov 21, 2014, at 9:01 AM, Tim Holy notifications@github.com wrote:

See above for concerns about generator.

The reason for the whitespace: we'll surely have generated type and generated immutable someday. Using the whitespace means that only one new keyword needs to be added to the parser, not three.

Also, I highlighted Jeff and Stefan above because I thought I remembered that Stefan seems the least happy of anyone with these recent name proposals. But then I just re-read some of the discussion, and Stefan said he'd go for generated function, so it seems there's really quite a lot of agreement on that name. However, since the parser is not my strong suit it won't be me who makes that change.


Reply to this email directly or view it on GitHub.

Member

StefanKarpinski commented Nov 21, 2014

It's bit the prettiest but how about just a @generated macro? No syntax changes required.

On Nov 21, 2014, at 9:01 AM, Tim Holy notifications@github.com wrote:

See above for concerns about generator.

The reason for the whitespace: we'll surely have generated type and generated immutable someday. Using the whitespace means that only one new keyword needs to be added to the parser, not three.

Also, I highlighted Jeff and Stefan above because I thought I remembered that Stefan seems the least happy of anyone with these recent name proposals. But then I just re-read some of the discussion, and Stefan said he'd go for generated function, so it seems there's really quite a lot of agreement on that name. However, since the parser is not my strong suit it won't be me who makes that change.


Reply to this email directly or view it on GitHub.

@MikeInnes

This comment has been minimized.

Show comment
Hide comment
@MikeInnes

MikeInnes Nov 21, 2014

Member

If we're using white space anyway, seems reasonable to just use a macro – @generated function ... or @gen function... (edit: ok, Stefan got there first)

I also quite liked fucro, but that's probably why I'm not making the decisions around here.

Member

MikeInnes commented Nov 21, 2014

If we're using white space anyway, seems reasonable to just use a macro – @generated function ... or @gen function... (edit: ok, Stefan got there first)

I also quite liked fucro, but that's probably why I'm not making the decisions around here.

@toivoh

This comment has been minimized.

Show comment
Hide comment
@toivoh

toivoh Nov 21, 2014

Member

Oh, forgot about python generators :) (which I indeed hope that we will have at some point)

Member

toivoh commented Nov 21, 2014

Oh, forgot about python generators :) (which I indeed hope that we will have at some point)

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Nov 21, 2014

Member

+1 for @generated function, @generated type, etc.

Member

StefanKarpinski commented Nov 21, 2014

+1 for @generated function, @generated type, etc.

@Jutho

This comment has been minimized.

Show comment
Hide comment
@Jutho

Jutho Nov 21, 2014

Contributor

Generated types can be implemented right now using the tricks used in #8432. Not perfect, but still very convenient until we have the full thing. In fact, it shouldn't be to hard to implement a general scheme for this using a macro, which could then be called @generate(d). This could provide a unified approach towards generated functions and types. However, what transformation should @generate(d) apply to :function, i.e. the child still needs a name, unless the generated/staged aspect is indicated using the :meta mechanism.

With respect to name: I would also prefer generated if it is a keyword, but most macros seem to have a name which is a verb in the present tense. Also compare to the original @ngenerate macro in Base.Cartesian. No strong preference from my side.

Contributor

Jutho commented Nov 21, 2014

Generated types can be implemented right now using the tricks used in #8432. Not perfect, but still very convenient until we have the full thing. In fact, it shouldn't be to hard to implement a general scheme for this using a macro, which could then be called @generate(d). This could provide a unified approach towards generated functions and types. However, what transformation should @generate(d) apply to :function, i.e. the child still needs a name, unless the generated/staged aspect is indicated using the :meta mechanism.

With respect to name: I would also prefer generated if it is a keyword, but most macros seem to have a name which is a verb in the present tense. Also compare to the original @ngenerate macro in Base.Cartesian. No strong preference from my side.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Nov 21, 2014

Member

Although @ngenerate is imperative: generate them now, at parsing time.

Member

timholy commented Nov 21, 2014

Although @ngenerate is imperative: generate them now, at parsing time.

@StefanKarpinski

This comment has been minimized.

Show comment
Hide comment
@StefanKarpinski

StefanKarpinski Nov 21, 2014

Member

I agree with the argument that it should be @generated. There are two flavors of macro: imperatives and annotations – this is more of an annotation than an imperative.

Member

StefanKarpinski commented Nov 21, 2014

I agree with the argument that it should be @generated. There are two flavors of macro: imperatives and annotations – this is more of an annotation than an imperative.

@JeffBezanson

This comment has been minimized.

Show comment
Hide comment
@JeffBezanson

JeffBezanson Nov 21, 2014

Member

I like @generated too. It has all the virtues of generated function plus avoids adding a new keyword. Macro names certainly do not need to be verbs in the present tense. This is not past tense either; it's a participle, as in "functions are generated on demand".

Member

JeffBezanson commented Nov 21, 2014

I like @generated too. It has all the virtues of generated function plus avoids adding a new keyword. Macro names certainly do not need to be verbs in the present tense. This is not past tense either; it's a participle, as in "functions are generated on demand".

@Jutho

This comment has been minimized.

Show comment
Hide comment
@Jutho

Jutho Nov 21, 2014

Contributor

On 21 Nov 2014, at 16:18, Tim Holy notifications@github.com wrote:

Although @ngenerate is imperative: generate them now, at parsing time.

Indeed. I agree 100%. +1 for @generated.

Contributor

Jutho commented Nov 21, 2014

On 21 Nov 2014, at 16:18, Tim Holy notifications@github.com wrote:

Although @ngenerate is imperative: generate them now, at parsing time.

Indeed. I agree 100%. +1 for @generated.

@ViralBShah

This comment has been minimized.

Show comment
Hide comment
@ViralBShah

ViralBShah Nov 22, 2014

Member

+1 for @generated. No whitespace in keywords is nice too. Visually, the macro syntax it also alerts you that something will run at an earlier stage.

Member

ViralBShah commented Nov 22, 2014

+1 for @generated. No whitespace in keywords is nice too. Visually, the macro syntax it also alerts you that something will run at an earlier stage.

@johnmyleswhite

This comment has been minimized.

Show comment
Hide comment
@johnmyleswhite

johnmyleswhite Nov 22, 2014

Member

If we make this look like a macro, what will macroexpand produce? I'm not sure I like the idea that this looks like a macro, but doesn't work like other macros.

Member

johnmyleswhite commented Nov 22, 2014

If we make this look like a macro, what will macroexpand produce? I'm not sure I like the idea that this looks like a macro, but doesn't work like other macros.

@amitmurthy

This comment has been minimized.

Show comment
Hide comment
@amitmurthy

amitmurthy Nov 22, 2014

Member

I agree with John. The @ convention is that code is generated when it is used. While defining the generator plain keyword macro is used. +1 for generated function.

Member

amitmurthy commented Nov 22, 2014

I agree with John. The @ convention is that code is generated when it is used. While defining the generator plain keyword macro is used. +1 for generated function.

@tonyhffong

This comment has been minimized.

Show comment
Hide comment
@tonyhffong

tonyhffong Nov 22, 2014

Member

How about using an empty curly?

function f{}( ... )
end

No new reserved word. No need to change editor model. The empty curly suggests that, Instead of parametrizing the function outside, we do that inside...

Edit: ok, f{}{ T<: AbstractArray }( x::T ) ... doesn't look quite right. Never mind me.

Member

tonyhffong commented Nov 22, 2014

How about using an empty curly?

function f{}( ... )
end

No new reserved word. No need to change editor model. The empty curly suggests that, Instead of parametrizing the function outside, we do that inside...

Edit: ok, f{}{ T<: AbstractArray }( x::T ) ... doesn't look quite right. Never mind me.

@MikeInnes

This comment has been minimized.

Show comment
Hide comment
@MikeInnes

MikeInnes Nov 22, 2014

Member

@johnmyleswhite The idea isn't to pretend it's a macro, but for it to actually be a macro. @generated would be a very simple macro that inserts some metadata into the (function/type/whatever) expression for the compiler to pick up on.

We have @inline already doing this, so it's not exactly unprecedented (although admittedly @generated would change the semantics a lot more than @inline).

Member

MikeInnes commented Nov 22, 2014

@johnmyleswhite The idea isn't to pretend it's a macro, but for it to actually be a macro. @generated would be a very simple macro that inserts some metadata into the (function/type/whatever) expression for the compiler to pick up on.

We have @inline already doing this, so it's not exactly unprecedented (although admittedly @generated would change the semantics a lot more than @inline).

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Nov 22, 2014

Member

To follow up on @one-more-minute's point, see http://docs.julialang.org/en/latest/devdocs/meta/

Member

timholy commented Nov 22, 2014

To follow up on @one-more-minute's point, see http://docs.julialang.org/en/latest/devdocs/meta/

@porterjamesj

This comment has been minimized.

Show comment
Hide comment
@porterjamesj

porterjamesj Nov 30, 2014

Member

I think the crucial point is that it's the definition of a generated function that involves a macro rather than the callsite—end users don't have to care. +1 for @generated from me.

Member

porterjamesj commented Nov 30, 2014

I think the crucial point is that it's the definition of a generated function that involves a macro rather than the callsite—end users don't have to care. +1 for @generated from me.

@stevengj

This comment has been minimized.

Show comment
Hide comment
@stevengj

stevengj Dec 29, 2014

Member

Hornéd hat of shame for the lack of documentation on this....

Member

stevengj commented Dec 29, 2014

Hornéd hat of shame for the lack of documentation on this....

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Dec 30, 2014

Member

As I believe you noted elsewhere, it's hard to write documentation for something whose very name is likely to change.

Member

timholy commented Dec 30, 2014

As I believe you noted elsewhere, it's hard to write documentation for something whose very name is likely to change.

@lstagner

This comment has been minimized.

Show comment
Hide comment
@lstagner

lstagner Dec 31, 2014

Contributor

It seems like the consensus that was reached was for calling them generated (functions|types|...) using the @generated (function|type|...) syntax.

Contributor

lstagner commented Dec 31, 2014

It seems like the consensus that was reached was for calling them generated (functions|types|...) using the @generated (function|type|...) syntax.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Dec 31, 2014

Member

I agree, but until the syntax change happens it seems very strange to document it (with either name choice).

Member

timholy commented Dec 31, 2014

I agree, but until the syntax change happens it seems very strange to document it (with either name choice).

@ViralBShah

This comment has been minimized.

Show comment
Hide comment
@ViralBShah

ViralBShah Jan 1, 2015

Member

Why not document it with the current name, and then just update the documentation with the name change? I think a lot of people want to use staged functions and learn about them (on master), but going through the issues is a bit cumbersome for many.

Member

ViralBShah commented Jan 1, 2015

Why not document it with the current name, and then just update the documentation with the name change? I think a lot of people want to use staged functions and learn about them (on master), but going through the issues is a bit cumbersome for many.

@aviks

This comment has been minimized.

Show comment
Hide comment
@aviks

aviks Jan 1, 2015

Member

Why not document it with the current name, and then just update the documentation with the name change

I realise this is more work, and I am in no position to help, but I (and I'm sure many others) would really appreciate something on those lines. Maybe even a gist with some docs and examples?

Member

aviks commented Jan 1, 2015

Why not document it with the current name, and then just update the documentation with the name change

I realise this is more work, and I am in no position to help, but I (and I'm sure many others) would really appreciate something on those lines. Maybe even a gist with some docs and examples?

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jan 1, 2015

Member

I also confess some reluctance before #8504 gets fixed---it's a nasty problem, and it's holding even me back from using stagedfunctions more pervasively.

But, let's go for it and see what happens. If nothing else it might be more incentive to at least get some discussion about my proposed fix.

Member

timholy commented Jan 1, 2015

I also confess some reluctance before #8504 gets fixed---it's a nasty problem, and it's holding even me back from using stagedfunctions more pervasively.

But, let's go for it and see what happens. If nothing else it might be more incentive to at least get some discussion about my proposed fix.

@tonyhffong

This comment has been minimized.

Show comment
Hide comment
@tonyhffong

tonyhffong Jan 8, 2015

Member

I wonder if we should treat function-typed argument differently in a stagedfunction. When testing types, we most likely want to do method_exists or even code_typed to see if the function supports the input/output signature in the staging phase. Having just Function at this stage isn't that helpful.

That said, it should be illegal to actually call the function-value argument at the staging phase.

Member

tonyhffong commented Jan 8, 2015

I wonder if we should treat function-typed argument differently in a stagedfunction. When testing types, we most likely want to do method_exists or even code_typed to see if the function supports the input/output signature in the staging phase. Having just Function at this stage isn't that helpful.

That said, it should be illegal to actually call the function-value argument at the staging phase.

@timholy

This comment has been minimized.

Show comment
Hide comment
@timholy

timholy Jan 9, 2015

Member

It's an interesting idea. Can you expand on your goal, why checking the signature during staging is better than just trying it and seeing what error you get?

But one point is that in principle your suggestion could provide a mechanism for "function-valued argument inlining" (#3440 and perhaps #1864).

Member

timholy commented Jan 9, 2015

It's an interesting idea. Can you expand on your goal, why checking the signature during staging is better than just trying it and seeing what error you get?

But one point is that in principle your suggestion could provide a mechanism for "function-valued argument inlining" (#3440 and perhaps #1864).

@tonyhffong

This comment has been minimized.

Show comment
Hide comment
@tonyhffong

tonyhffong Jan 9, 2015

Member

I'm playing with the idea of Functors and Monads using Traits.jl and notice the ideas are not trivial. (PR# mauro3/Traits.jl#4 (comment)). I was trying to see if I can generate associated types with the package. Let's take Functor. A Functor must support a fmap function. In Haskell it imposes that fmap :: (a->b) -> f a -> f b. So we would write something like this:

using Traits

immutable FuncFullSig{TI, TO}
    f::Function
end

@traitdef Functor{X{Y}} begin
    fmap( FuncFullSig{Y,Z}, X{Y} ) -> X{Z}
end

So when we do

a = Float64[1.0,2.0] # assume we assert Array is a Functor
b = fmap( FuncFullSig{Float64,Float64}( sin ), a ) # b should be provably Array{Float64}

It would do away with many boilerplate codes, as many types are just Functors in disguise (Nullable, Associative{K}, DataArray, etc.) . But writing FuncFullSig is a bit cumbersome. It would be really nice, when we do just b = fmap( sin, c ), the following intermediate steps happen:

  • ask if typeof(c) is a Functor? (already do-able now with Traits.jl)
  • if so, check if the method sin( x::T ) exists? (T is the Functor parameter of typeof(c))
  • (bonus) provide type inference info that b must be a Functor of the result type

Ideally, all these would be better done only once per (Function, ArgTypes...) tuple, or the performance penalty would be massive. Stagedfunction would be an interesting place to put it, but
we are in a strange place right now, when we only know the types of arguments but not the signatures of function arguments, a challenge that is a by-product of julia's multiple-dispatch feature. (Ironically, multiple-dispatch is exactly what makes Traits.jl work.)

Member

tonyhffong commented Jan 9, 2015

I'm playing with the idea of Functors and Monads using Traits.jl and notice the ideas are not trivial. (PR# mauro3/Traits.jl#4 (comment)). I was trying to see if I can generate associated types with the package. Let's take Functor. A Functor must support a fmap function. In Haskell it imposes that fmap :: (a->b) -> f a -> f b. So we would write something like this:

using Traits

immutable FuncFullSig{TI, TO}
    f::Function
end

@traitdef Functor{X{Y}} begin
    fmap( FuncFullSig{Y,Z}, X{Y} ) -> X{Z}
end

So when we do

a = Float64[1.0,2.0] # assume we assert Array is a Functor
b = fmap( FuncFullSig{Float64,Float64}( sin ), a ) # b should be provably Array{Float64}

It would do away with many boilerplate codes, as many types are just Functors in disguise (Nullable, Associative{K}, DataArray, etc.) . But writing FuncFullSig is a bit cumbersome. It would be really nice, when we do just b = fmap( sin, c ), the following intermediate steps happen:

  • ask if typeof(c) is a Functor? (already do-able now with Traits.jl)
  • if so, check if the method sin( x::T ) exists? (T is the Functor parameter of typeof(c))
  • (bonus) provide type inference info that b must be a Functor of the result type

Ideally, all these would be better done only once per (Function, ArgTypes...) tuple, or the performance penalty would be massive. Stagedfunction would be an interesting place to put it, but
we are in a strange place right now, when we only know the types of arguments but not the signatures of function arguments, a challenge that is a by-product of julia's multiple-dispatch feature. (Ironically, multiple-dispatch is exactly what makes Traits.jl work.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment