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

Allow user-defined functors to be passed to more methods in Base #12035

Closed
wants to merge 1 commit into from

Conversation

malmaud
Copy link
Contributor

@malmaud malmaud commented Jul 6, 2015

Closes #12012

@yuyichao
Copy link
Contributor

yuyichao commented Jul 6, 2015

What are the places left that uses Callable and do we still need it?

@malmaud
Copy link
Contributor Author

malmaud commented Jul 6, 2015

Only in get and get!. I was getting ambiguity warnings with get!(o::ObjectIdDict, key, default) = (o[key] = get(o, key, default)) in dict.jl; haven't looked into it further.

@@ -189,7 +189,7 @@ copy(x::Union{Symbol,Number,AbstractString,Function,Tuple,LambdaStaticData,
TopNode,QuoteNode,DataType,Union}) = x

# function pipelining
|>(x, f::Callable) = f(x)
|>(x, f) = f(x)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Won't this conflict with the deprecated piping of Cmd objects via |> ? I don't think we can make this change until after that deprecation gets removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, since Cmd piping will still invoke the more specific |>(src::Base.AbstractCmd, dest::Base.AbstractCmd).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm okay, well if no ambiguities then I guess we can see what happens

@yuyichao
Copy link
Contributor

yuyichao commented Jul 6, 2015

Only in get and get!. I was getting ambiguity warnings with get!(o::ObjectIdDict, key, default) = (o[key] = get(o, key, default)) in dict.jl; haven't looked into it further.

I guess the get interface needs to distinguish between callable and non-callable object and keeping it only limited to function and types would probably be the simplest solusion.

@malmaud
Copy link
Contributor Author

malmaud commented Jul 7, 2015

Maybe it's best to just change the get interface to not be ambiguous wrt ObjectIdDict, and then Callable can be removed completely. I don't have a good sense of how often that interface is used in packages and therefore how breaking it would be.

@toivoh
Copy link
Contributor

toivoh commented Jul 8, 2015

Agreed, now that everything is potentially callable, we should get rid of Callable entirely and rework those apis that relied on it. Otherwise we will leave some nasty surprises for people who use objects with call overloading.

@malmaud
Copy link
Contributor Author

malmaud commented Jul 10, 2015

What should we do about the ambiguity that will exist between get{K,V}(default::Callable, h::Dict{K,V}, key) and get{K,V}(h::Dict{K,V}, key, default)?

@kmsquire
Copy link
Member

Perhaps change the name of the first?

On Thursday, July 9, 2015, Jonathan Malmaud notifications@github.com
wrote:

What should we do about the ambiguity that will exist between get{K,V}(default::Callable,
h::Dict{K,V}, key) and get{K,V}(h::Dict{K,V}, key, default)?


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

@nalimilan
Copy link
Member

OTOH, restricting these methods to Callable limits ambiguities (as can be seen above) and means that you'll get a no method error pretty early when a call doesn't make sense, which is always good. Shouldn't objects that implement call inherit from Callable instead?

@timholy
Copy link
Sponsor Member

timholy commented Jul 10, 2015

Given that we don't have multiple inheritance, that would be a rather extreme constraint on type hierarchies. Much better to ditch Callable altogether.

@ScottPJones
Copy link
Contributor

Would this be a case where "Holy" Traits could come to the rescue?

@nalimilan
Copy link
Member

Yeah, actually I had in mind a kind of a trait (which the name Callable evokes).

@yuyichao
Copy link
Contributor

I strongly disagree that using a trait here is a good API.
It'll easily break if someone decided to make a object callable.

@ScottPJones
Copy link
Contributor

@yuyichao Could you elaborate please?

@malmaud
Copy link
Contributor Author

malmaud commented Jul 10, 2015

It seems get(default::Callable, h::Dict{K,V}, key) and friends will have to be eliminated, since without Callable it will be ambiguous with any method of the form get(::T, key, default). But that will be a breaking change that eliminates using do syntax with get. Maybe for the time being it's best to not touch those methods, and then this PR will be non-breaking.

@timholy
Copy link
Sponsor Member

timholy commented Jul 10, 2015

What about inserting a deprecation now and having it call a function of a new name? Otherwise you're stuck with it through 0.5, too.

@StefanKarpinski
Copy link
Sponsor Member

Long ago I proposed a d[k] ?= v syntax for this operation. Maybe it's time to have that.

@toivoh
Copy link
Contributor

toivoh commented Jul 12, 2015 via email

@kmsquire
Copy link
Member

I think that syntax is fine, but I don't see how it solves the Callable issue...

@malmaud
Copy link
Contributor Author

malmaud commented Jul 14, 2015

@timholy You're proposing introducing a new function that implements the behavior that get(::Callable,...) currently has? That does seem to be the only solution, short of changing how do functions work to allow them to still be used with get while avoiding defining get(::Callable

@timholy
Copy link
Sponsor Member

timholy commented Jul 14, 2015

Yeah. It's basically the same thing that @kmsquire was saying, I think.

@JeffBezanson
Copy link
Sponsor Member

I envision making Function an abstract type, for objects that are primarily functions. That doesn't directly solve this problem, but what you can do is annotate arguments with ::Function or ::Callable when needed to avoid ambiguities. Then at worst the caller needs to wrap the intended argument in an anonymous function, which presumably will be fast at some point :)

@malmaud
Copy link
Contributor Author

malmaud commented Jul 19, 2015

Seems like it could be a bit janky: I have a callable object f that can't derive from Function because of the lack of multiple inheritance. I then have to pass it to a higher-order function as (args...)->f(args...) to get it to dispatch properly. I guess we could have something like asfunction(f) which automatically does that to allay the pain.

@yuyichao
Copy link
Contributor

Feels like #5571 (a little bit).

In any case, should we merge the non-ambigious part of this PR?

@@ -186,7 +186,7 @@ sum_pairwise_blocksize(::Abs2Fun) = 4096
mapreduce_impl(f, op::AddFun, A::AbstractArray, ifirst::Int, ilast::Int) =
mapreduce_pairwise_impl(f, op, A, ifirst, ilast, sum_pairwise_blocksize(f))

sum(f::Union{Callable,Func{1}}, a) = mapreduce(f, AddFun(), a)
sum(f, a) = mapreduce(f, AddFun(), a)
Copy link
Sponsor Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems weird to me, given the existence of sum(array, dims). I think ideally this definition would not exist at all.
count is ok, since its first argument is always a function.

@JeffBezanson
Copy link
Sponsor Member

Fixed on master.

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.

10 participants