Idea for potentially easier to parse/read syntax for type constraints in #18457

Reading the discussion of #18457 (which I have been looking forward to since JuliaCon 2015!), I saw the following comment: https://github.com/JuliaLang/julia/pull/18457#issuecomment-268716047
and wondered if maybe an alternate syntax might make things cleaner for types:

instead of Array{T,N} where T <: Int, where N
what about:
Array{T,N ; where T <: Int, where N}

I think that would eliminate the parsing issues that Jeff had brought up in reply to Andy, wouldn’t require extra parenthesis as in Andy’s example, and I think is easier to understand, in that the where clauses don’t potentially end up far from where the type variables first appear.

The problem with that is that the where needs to be able to qualify any expression that yields a type. There needs to be a form that wraps an arbitrary expression. For function signatures, we need a syntax for type variables over all arguments.

Right, I’m not saying that this would replace the syntax for constraints on type variables over all arguments, just that it might be a good alternative syntax for a single type.
Just like there are two different syntaxes for defining a function, I think this might be a nice form that’s easier to read, when you don’t need to have a constraint over multiple arguments.

I think it starts to get confusing as soon as there is more than one type application, for example Array{Array{T}; where T}. Inserting a semicolon does the same thing as moving where outside the braces? The where isn’t any more associated with the outer Array type than the inner one, so it seems odd to make it part of that expression.

I was thinking that would be: Array{Array{T; where T}}.
What I’d like to see avoided is the following, where you have many arguments, where there is no constraint that any typevar be the same for different types, you don’t have to bounce around when reading from the argument list to the potentially large where clauses. (Note: if you have the ; to separate the parameters from the constraints, I don’t think you even need the where for this syntax, it would be as simple as Array{Array{T;T}}, and that would make it clear that it is different from Array{Array{Int}}.

For example, currently, there is:

function round{T<:AbstractFloat, MR, MI}(z::Complex{T}, ::RoundingMode{MR}, ::RoundingMode{MI})
    Complex(round(real(z), RoundingMode{MR}()),
            round(imag(z), RoundingMode{MI}()))
end

which would need to be rewritten with #18457 as:

function round(z::Complex{T}, ::RoundingMode{MR}, ::RoundingMode{MI}) where T<:AbstractFloat, where MR, where MI

but instead, it could be simply:

function round(z::Complex{T; T<:AbstractFloat}, ::RoundingMode{MR;MR}, ::RoundingMode{MI;MI})

But the position of where is significant; Array{Array{T}} where T is not the same type as Array{Array{T} where T}.

3 Likes

OK, I hadn’t expected that, and there was no mention in the section added to NEWS.md for the #18457 branch. Thanks for the info!
That still doesn’t mean that a short form, keeping the constraint closer to the use of the typevar might not be useful to make things easier to read for mere mortals :wink:
I think a useful short form might simply mean that S{T;T<:U} would be equivalent to S{T} where T<:U.
Array{Array{T} where T} would be equivalent to Array{Array{T;T}}, and Array{Array{T}} where T would be equivalent to Array{Array{T} ; T}.
Are there any parsing or semantic issues with that approach?

Anyway, no matter what the syntax, I’m very much looking forward to this in v0.6! Thanks very much for this big advance!