Free parameters in function definitions

function foo(x) where {T} =  x

is valid in julia (v0.7) – but I’m not fully grokking this. foo is parameterized by T, but the signature of this method is ‘free’ of T – so how does julia interpret this? Is the T tag maintained somewhere in the metadata for this method? Is there some sort of use case where this is helpful?

I was scanning thru the Readme of Cassette.jl and saw something similar to this, though there were macros involved so I’m not sure if the syntax is being rewritten into something entirely different

thanks!

It doesn’t enable much that’s wasn’t possible before but it makes the dispatch rule much simpler. Julia doesn’t need to interpret it since it does not affect dispatch anymore.

For the user, T is just an unassigned variable and it could be useful in some uncommon cases to express dispatch rules. This happen mainly with unions when part of the union may not participate in a successful match (e.g. Union{Int,Vector{T}})

The biggest downside of the change, like any other change that remove restrictions, is that there will be more user bugs. Fortunately, the check is still possible to do by a linter and it’s normally just a code cleaness issue rather than a behavior issue…

5 Likes

Is there some sort of syntax for binding T at the call site? I tried:

julia> foo(x) where {T} = isbitstype(T)
foo (generic function with 1 method)

julia> foo{Int}(3)
ERROR: TypeError: in Type{...} expression, expected UnionAll, got typeof(foo)

I was expecting something like what happens in c++

template <typename T>
bool foo(int x) {
    return std::is_pod<T>();  //or whatever 
}

bool b = foo<int>(42);

Also I’m not sure I understand why this leads to only one method definition:

julia> foo(x) where {T} = isbitstype(T)
foo (generic function with 1 method)

julia> foo(x) = isbitstype(Int)
foo (generic function with 1 method)

Thanks for indulging my curiosity – cheers

No. Such feature will be very hard to add since type parameter is a property of the method, not the function. It’ll not be very clear from the syntax which method you are talking about when there isn’t just one. If you have only one method though, you can use a singleton type to achieve the same if you really want this syntax.

As for difference from c++.

  1. C++ have some really complicated rules related to function overload and template. I don’t remember all those and have been bite by it multiple times. I’m pretty sure this is a related issue.
  2. Types are NOT first class object in C++ and the constness of value is semantically significant in the language. Julia doesn’t have those problems so you don’t have to use a static parameter to pass in anything explicitly to a function. Your foo should just be defined as foo(x) = isbitstype(x) or foo(::Type{T}) where T = isbitstype(T) (or just foo = isbitstype…).

As I said,

Dispatch only depends on the types the method signature can match and it doesn’t care if you expressed it with a hundred insignificant type parameters or not. Your two definitions have exactly the same dispatch behavior so one have to overwrite the other.

1 Like