Description
Currently, a generic function can only be created by making a method. However, it may be useful to declare generic functions without having to provide an implementation. For instance Common Lisp provides this functionality with its defgeneric
macro. Examples where this could be useful:
- When writing libraries it is fairly common that the user must implement some methods for her concrete application. Currently, the library-writer can create a generic function by declaring a method which throws an error which must then be overwritten by the user. This was discussed here (and what prompted me to open this issue): https://groups.google.com/forum/#!topic/julia-users/KE7q3yq3eiA . Here is an example of this pattern in
Base
: https://github.com/JuliaLang/julia/blob/master/base/graphics.jl - In
Base
the implied meaning of generic functions is fairly set, and their signature is consistent. Examples aresize
,copy
,isequal
, etc. However, there is no place where the generic function is defined. Thus there is no place in the code to specify & document what its meaning is and what conventions/rules its call signature should follow. - To get consistent implementations of generic functions across different packages. For instance, a generic
plot
function could be defined somewhere, inBase
or in some umbrella-plotting package (quite a few github topical groups have sprung up recently, probably they could profit from such definitions). See issue Common pool for methods as a way to solve common names in different packages #2327 or thread: https://groups.google.com/d/msg/julia-users/zyVU-tty-qk/lg1IW2qPSGEJ - Also relevant with function/method-return type declarations: return type declarations #1090
- If interfaces become part of Julia they will probably need generic function specifications Interfaces for Abstract Types #6975.
This issue touches on: documentation (e.g. #3988), function types (e.g. #1090), interface-oriented programming (e.g. #6975), and method ambiguity warnings (#6190 (comment)). In particular, @StefanKarpinski's comment on how to potentially specify (interfaces)[https://github.com//issues/6975#issuecomment-44502467] also has syntax to define generic functions within an interface specification.
Declaring a generic function should:
- not break any existing code
- make a generic function if none exists already
- associate the given documentation with the generic function
- generate an appropriate error message if there is no matching method when calling the generic function
- maybe impose restrictions on the associated methods signatures, or if methods are already defined, check that they all comply.
Implementations:
The most straight forward implementation would just create the generic function and allow documentation to be associated with it:
doc"""
Returns the size of a container.
"""
generic size
More complicated would be to allow to constrain the call signature. Inspired by Common Lisp, the syntax could look like:
doc"""
A function taking arguments:
- a: one input of type T
- b: another input
...
"""
generic afun{T<:Integer, S<:String}(a::T, [b::S]; y::Int=7, ...)-->T
The names of the arguments would be dummy-names useful for documentation and consistency in method implementations. a
would be a required argument, b
would be optional, likewise for keyword arguments, and ...
would allow any number of other optional arguments (the []
and ...
couldn't be allowed at the same time).
Example size
:
doc"""
Returns a tuple containing the dimensions of A. If specified, along a particular
dimension of a multidimensional collection.
"""
generic size(obj::Any, [dim::Integer])
size(a::Array) = arraysize(a)
size(a::Array, d) = arraysize(a, d)
Thus, the generic declarations could follow largely what is defined in the standard library documentation https://github.com/JuliaLang/julia/tree/master/doc/stdlib in a more formal way.
To think about:
- should/could restrictions on method-signature be part of the generic definition?
- should method-signature be a recommendation or be enforced?
- what to do when there are several definitions of a generic function?
- within the same module it should be an error.
- otherwise warn: this would probably mean that two packages export the same generic function.
- how would this fit with a future interface specification Interfaces for Abstract Types #6975? Is it needed as well, is it redundant or even inconsistent? If all generic functions are only part of a single interface, then this feature is probably not needed. But I suspect that some functions will not belong to any interface, whereas others may belong to several interfaces.