Skip to content

Update methods.rst #10769

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

Merged
merged 4 commits into from
Apr 26, 2015
Merged

Update methods.rst #10769

merged 4 commits into from
Apr 26, 2015

Conversation

daanhb
Copy link
Contributor

@daanhb daanhb commented Apr 8, 2015

The change mentions a possible side-effect of the implementation of optional arguments that was discussed on julia-users:
https://groups.google.com/forum/#!topic/julia-users/gNMILY7s95c

The change mentions a possible side-effect of the implementation of optional arguments that was discussed on julia-users:
https://groups.google.com/forum/#!topic/julia-users/gNMILY7s95c
@toivoh
Copy link
Contributor

toivoh commented Apr 8, 2015

It's good to mention this in the manual, but I think the underlying issue should be fixed. @JeffBezanson, @StefanKarpinski?

@elextr
Copy link

elextr commented Apr 9, 2015

Pending contradiction from Jeff or Stefan I don't think there is a problem. Julia is a multiple dispatch language, the type of the parameters decides the method to use. Optional parameters (note Julia does not call them "default values") are implemented as multiple methods, ie

f(d=a)=d

is

f() = f(a)
f(d) = d

Clearly the type of a will affect the method of f dispatched.

For programmers from other languages thinking in non-Julian terms, it perhaps could be expressed as "the default values are calculated each call (like C++ not like Python) and so they impact method dispatch".

It is documented that this is how optional parameters work, but maybe it needs to be better highlighted in the "Optional Arguments" section of functions, rather than being relegated to an easily overlooked (see Methods) at the very end.

@daanhb
Copy link
Contributor Author

daanhb commented Apr 9, 2015

Right, "default values" is not the proper terminology here, thanks for pointing that out. I'll change that. In any case I'm not sure whether I've done the pull request correctly, as one of the builds seems to have failed.

If documentation is the answer, I do believe the section on Methods is more appropriate, if only because the notions of methods and dispatch are not discussed yet in the section on Functions. It is difficult to briefly explain the issue without those concepts beyond what is already written.

Strictly speaking, the behaviour is actually clear from what is said in
http://julia.readthedocs.org/en/latest/manual/functions/#optional-arguments
There is a forward reference in that part of the manual which perhaps could be made more specific to http://julia.readthedocs.org/en/latest/manual/methods/#note-on-optional-and-keyword-arguments.

@pao
Copy link
Member

pao commented Apr 9, 2015

In any case I'm not sure whether I've done the pull request correctly, as one of the builds seems to have failed.

It failed the whitespace check. Copying from the build log:

$ make check-whitespace || exit 1
doc/manual/methods.rst:544:usual, and so they may also call different methods of ``f``. For example, if 
doc/manual/methods.rst:548: 
Error: trailing whitespace found in source file(s)
This can often be fixed with:
    git rebase --whitespace=fix HEAD~1
or
    git rebase --whitespace=fix master
and then a forced push of the correct branch

You may also want to amend your commit message to include the string [av skip], which will save us some compute time by skipping the Windows tests entirely; it's helpful for these documentation-only commits. Thanks!

@elextr
Copy link

elextr commented Apr 9, 2015

Strictly speaking, the behaviour is actually clear from what is said in
http://julia.readthedocs.org/en/latest/manual/functions/#optional-arguments
There is a forward reference in that part of the manual which perhaps could be made more specific to http://julia.readthedocs.org/en/latest/manual/methods/#note-on-optional-and-keyword-arguments.

Yes, thats what I was suggesting should also be more prominent.

@sbromberger
Copy link
Contributor

Could someone tell me why this behaves the way it does?

julia> a = 5
5

julia> function f(d=a) info("in f1"); d; end
f (generic function with 2 methods)

julia> function f(a::Float64) info("in f2"); round(Int,a); end
f (generic function with 3 methods)

julia> f()
INFO: in f1
5

julia> a = 6.6
6.6

julia> f()
INFO: in f2
7

julia> methods(f)
# 3 methods for generic function "f":
f() at none:1
f(a::Float64) at none:1
f(d) at none:1

I've read through the documentation proposed here and still don't get it. The docs say that the default values merely create additional methods with variable numbers of arguments, and I see them with methods, but I don't understand the dispatch to the "f2" method given the call to f().

@elextr
Copy link

elextr commented Apr 16, 2015

See my comment above, f() is a call to f(a) and in the first of your f() calls a is an Int, so it doesn't dispatch to f(::float64) but in the second call f() a is float64 and so it dispatches to f(::float64).

@ViralBShah ViralBShah added the docs This change adds or pertains to documentation label Apr 16, 2015
@daanhb
Copy link
Contributor Author

daanhb commented Apr 16, 2015

Sorry for the lack of response here on my behalf - I have only intermittent and poor internet access this week (holiday), but I still intend to take the comments above into account, fix the pull request and update the documentation.

@daanhb
Copy link
Contributor Author

daanhb commented Apr 16, 2015

I did the original change on the website only, which in hindsight was not the best idea as apparently that makes it more difficult to amend the commit message (to include [av skip]).

@elextr
Copy link

elextr commented Apr 16, 2015

Although travis is currently usefully telling you that you have a whitespace error :)

@daanhb
Copy link
Contributor Author

daanhb commented Apr 16, 2015

Yes, good point :-)

@sbromberger
Copy link
Contributor

@elextr thanks very much for the explanation. I understand it, though I'm not quite sure I agree with the behavior. It seems to me that this way of handling optional parameters can have some very ugly side effects (though I confess to being too tired to provide a documented example right now, I'm thinking of a case where you're relying on some external [non-julian] process to provide data to a function, and that process is itself not type-stable).

@toivoh
Copy link
Contributor

toivoh commented Apr 16, 2015

As I said above, I think this should be changed. The current behavior is a leaky abstraction: it looks like all you are doing is defining som default arguments for your method, but in practice you have to be aware of and consider how multiple dispatch works and which other methods have been defined for the same function. If we leave this kind of trap in, I'm not quite sure we should provide the mechanism of default arguments at all.

@sbromberger
Copy link
Contributor

at a minimum, I think this should throw a warning:

julia> f() = 100
f (generic function with 1 method)

julia> a = 6
6

julia> f(d=a) = d
f (generic function with 2 methods) # this overwrites an existing method f() and adds a new one f(d)

julia> f(a::Float64) = -a
f (generic function with 3 methods)

julia> methods(f)
# 3 methods for generic function "f":
f() at none:1
f(a::Float64) at none:1
f(d) at none:1

julia> f()
6

@StefanKarpinski
Copy link
Member

@toivoh, do you have a proposal for how you'd want to see this fixed?

@StefanKarpinski
Copy link
Member

I guess one option would be that the additional methods implied by default arguments use invoke to call the specific method that the defaults are provided for. I have a nagging suspicion that this might cause other equally bad or worse problems though...

@mbauman
Copy link
Member

mbauman commented Apr 16, 2015

The "underlying issue" is #9938 and #7357. invoke was discussed there, too, which triggered my memory.

@toivoh
Copy link
Contributor

toivoh commented Apr 16, 2015

Well, my thought was that the solution would have to stay partially outside the dispatch machinery. We would still create a method for each possible number of arguments, but then we would also create a hidden function containing the actual method body, which these would call directly.

@elextr
Copy link

elextr commented Apr 16, 2015

@toivoh the only way I can see is to compute the default values at compile time so f() = f(value_of_default_expression). Computing the value only once is the same as Python, but it restricts the default values to something that can be computed at compile time.

Its also going to be hard to make that change without breaking any code that inadvertently relies on the current behaviour since it would be hard to deprecate.

@toivoh
Copy link
Contributor

toivoh commented Apr 17, 2015

I don't see why you would have to evaluate the defaults at definition time; my suggestion only changes what the created methods call after they have evaluated their default arguments.

Deprecation is more of an issue, but given that this is an accidental feature that has not been advertised and has just been discovered, I'm hoping that it's not relied on a lot and that a public announcement would be enough.

@elextr
Copy link

elextr commented Apr 17, 2015

@toivoh can you explain your suggestion more completely, I don't understand what you actually propose.

As I pointed out above it is documented, just split across two places (for good reason) so its not crystal clear.

@daanhb
Copy link
Contributor Author

daanhb commented Apr 21, 2015

I guess this issue is still a bit controversial. In the meantime I updated the pull request with some of the comments made above. I kept the changes to the manual rather minimal, because a thorough discussion of this design and its implications, with some of the examples given above, would make the manual rather complicated. Is it reasonable?

@toivoh
Copy link
Contributor

toivoh commented Apr 21, 2015 via email

@daanhb
Copy link
Contributor Author

daanhb commented Apr 21, 2015

Hey, no problem, discussions tend to be distributed here I gather. It is very handy to have these links to other issues for a complete picture (thanks @mbauman).

@pao
Copy link
Member

pao commented Apr 21, 2015

Test failures are not whitespace, so that failure should not hold this up.

@jiahao jiahao merged commit 9351cc0 into JuliaLang:master Apr 26, 2015
@daanhb
Copy link
Contributor Author

daanhb commented Apr 27, 2015

Cool, thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docs This change adds or pertains to documentation
Projects
None yet
Development

Successfully merging this pull request may close these issues.

9 participants