Skip to content

Commit

Permalink
syntactic sugar Foo{<:Bar} for Foo{T} where T<:Bar (closes JuliaLang#…
Browse files Browse the repository at this point in the history
  • Loading branch information
stevengj committed Feb 2, 2017
1 parent 3aecb67 commit 9d98937
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 3 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ New language features
`function inv(M::Matrix{T}) where T<:AbstractFloat`.
Anonymous functions can have type parameters via the syntax
`((x::Array{T}) where T<:Real) -> 2x`.
* Implicit type parameters, e.g. `Vector{<:Real}` is equivalent to
`Vector{T} where T<:Real`.
* Much more accurate subtype and type intersection algorithms. Method sorting and
identification of equivalent and ambiguous methods are improved as a result.

Expand Down
8 changes: 6 additions & 2 deletions doc/src/manual/types.md
Original file line number Diff line number Diff line change
Expand Up @@ -603,15 +603,18 @@ function norm(p::Point{Real})
end
```

The correct way to define a method that accepts all arguments of type `Point{T}` where `T` is
A correct way to define a method that accepts all arguments of type `Point{T}` where `T` is
a subtype of `Real` is:

```julia
function norm{T<:Real}(p::Point{T})
function norm(p::Point{<:Real})
sqrt(p.x^2 + p.y^2)
end
```

(Equivalently, one could define `function norm{T<:Real}(p::Point{T})` or
`function norm(p::Point{T} where T<:Real)`; see [UnionAll Types](@ref).)

More examples will be discussed later in [Methods](@ref).

How does one construct a `Point` object? It is possible to define custom constructors for composite
Expand Down Expand Up @@ -990,6 +993,7 @@ Using explicit `where` syntax, any subset of parameters can be fixed. For exampl

Type variables can be restricted with subtype relations.
`Array{T} where T<:Integer` refers to all arrays whose element type is some kind of `Integer`.
The syntax `Array{<:Integer}` is a convenient shorthand for `Array{T} where T<:Integer`.
Type variables can have both lower and upper bounds.
`Array{T} where Int<:T<:Number` refers to all arrays of `Number`s that are able to contain `Int`s
(since `T` must be at least as big as `Int`).
Expand Down
22 changes: 21 additions & 1 deletion src/julia-syntax.scm
Original file line number Diff line number Diff line change
Expand Up @@ -1763,6 +1763,20 @@
body
(expand-where (expand-wheres body (cdr vars)) (car vars))))

; given e = (curly T params...), return (newparams . whereparams) where any <:X expression
; in params is converted to T and T<:X is added to whereparams. (This implements
; the syntactic sugar Foo{<:Bar} --> Foo{T} where T<:Bar.)
(define (extract-implicit-whereparams e)
(define (extract params newparams whereparams)
(if (null? params)
(cons (reverse newparams) (reverse whereparams))
(let ((p (car params)))
(if (and (list? p) (= (length p) 3) (eq? (car p) 'call) (eq? (cadr p) '|<:|))
(let ((T (gensy)))
(extract (cdr params) (cons T newparams) (cons (list '|<:| T (caddr p)) whereparams)))
(extract (cdr params) (cons p newparams) whereparams)))))
(extract (cddr e) '() '()))

;; table mapping expression head to a function expanding that form
(define expand-table
(table
Expand Down Expand Up @@ -1980,7 +1994,13 @@
(expand-forms (partially-expand-ref e)))))

'curly
(lambda (e) (expand-forms `(call (core apply_type) ,@(cdr e))))
(lambda (e)
(let* ((p (extract-implicit-whereparams e))
(curlyparams (car p))
(whereparams (cdr p)))
(if (null? whereparams)
(expand-forms `(call (core apply_type) ,@(cdr e)))
(expand-forms `(where (curly ,(cadr e) ,@curlyparams) ,@whereparams)))))

'call
(lambda (e)
Expand Down
15 changes: 15 additions & 0 deletions test/subtype.jl
Original file line number Diff line number Diff line change
Expand Up @@ -861,3 +861,18 @@ f18348{T<:Any}(::Type{T}, x::T) = 2
# Issue #12721
f12721{T<:Type{Int}}(::T) = true
@test_throws MethodError f12721(Float64)

# implicit type parameters:
type TwoParams{S,T}; x::S; y::T; end
@test TwoParams{<:Real,<:Number} == (TwoParams{S,T} where S<:Real where T<:Number) ==
(TwoParams{S,<:Number} where S<:Real) == (TwoParams{<:Real,T} where T<:Number)
@test TwoParams(3,0im) isa TwoParams{<:Real,<:Number}
@test TwoParams(3,"foo") isa TwoParams{<:Real}
@test !(TwoParams(3im,0im) isa TwoParams{<:Real,<:Number})
@test !(TwoParams(3,"foo") isa TwoParams{<:Real,<:Number})
ftwoparams(::TwoParams) = 1
ftwoparams(::TwoParams{<:Real}) = 2
ftwoparams(::TwoParams{<:Real,<:Real}) = 3
@test ftwoparams(TwoParams('x',3)) == 1
@test ftwoparams(TwoParams(3,'x')) == 2
@test ftwoparams(TwoParams(3,4)) == 3

0 comments on commit 9d98937

Please sign in to comment.