From a8fec91b779bf023e9225d98bbfc9b241f713a0a Mon Sep 17 00:00:00 2001
From: Mike Nolta <mike@nolta.net>
Date: Tue, 7 Jan 2014 21:55:53 -0500
Subject: [PATCH] deprecate concatenating [a,b,...] and T[a,b,...]

closes #2488, closes #3737
---
 base/abstractarray.jl | 68 ++++++++++++++++++++++++++++++++++++++-----
 base/array.jl         |  4 +++
 base/show.jl          |  2 +-
 src/julia-parser.scm  | 26 +++++++----------
 src/julia-syntax.scm  | 56 ++++++++++++-----------------------
 test/arrayops.jl      | 12 ++++++++
 6 files changed, 107 insertions(+), 61 deletions(-)

diff --git a/base/abstractarray.jl b/base/abstractarray.jl
index 2ebca13ee67ce..c319fe223d9a0 100644
--- a/base/abstractarray.jl
+++ b/base/abstractarray.jl
@@ -6,6 +6,45 @@ typealias AbstractVecOrMat{T} Union(AbstractVector{T}, AbstractMatrix{T})
 
 ## Basic functions ##
 
+vect() = Array(None, 0)
+vect{T}(X::T...) = T[ X[i] for i=1:length(X) ]
+
+const _oldstyle_array_vcat_ = true
+
+if _oldstyle_array_vcat_
+    function oldstyle_vcat_warning(n::Int)
+        if n == 1
+            before = "a"
+            after  = "a;"
+        elseif n == 2
+            before = "a,b"
+            after  = "a;b"
+        else
+            before = "a,b,..."
+            after  = "a;b;..."
+        end
+        warn_once("[$before] concatenation is deprecated; use [$after] instead")
+    end
+    function vect(A::AbstractArray...)
+        oldstyle_vcat_warning(length(A))
+        vcat(A...)
+    end
+    function vect(X...)
+        for a in X
+            if typeof(a) <: AbstractArray
+                oldstyle_vcat_warning(length(X))
+                break
+            end
+        end
+        vcat(X...)
+    end
+else
+    function vect(X...)
+        T = promote_type(map(typeof, X)...)
+        T[ X[i] for i=1:length(X) ]
+    end
+end
+
 size{T,n}(t::AbstractArray{T,n}, d) = (d>n ? 1 : size(t)[d])
 eltype(x) = Any
 eltype{T,n}(::AbstractArray{T,n}) = T
@@ -602,6 +641,11 @@ end
 ## cat: general case
 
 function cat(catdim::Integer, X...)
+    T = promote_type(map(x->isa(x,AbstractArray) ? eltype(x) : typeof(x), X)...)
+    cat_t(catdim, T, X...)
+end
+
+function cat_t(catdim::Integer, typeC::Type, X...)
     nargs = length(X)
     dimsX = map((a->isa(a,AbstractArray) ? size(a) : (1,)), X)
     ndimsX = map((a->isa(a,AbstractArray) ? ndims(a) : 1), X)
@@ -645,7 +689,6 @@ function cat(catdim::Integer, X...)
 
     ndimsC = max(catdim, d_max)
     dimsC = ntuple(ndimsC, compute_dims)::(Int...)
-    typeC = promote_type(map(x->isa(x,AbstractArray) ? eltype(x) : typeof(x), X)...)
     C = similar(isa(X[1],AbstractArray) ? full(X[1]) : [X[1]], typeC, dimsC)
 
     range = 1
@@ -661,12 +704,15 @@ end
 vcat(X...) = cat(1, X...)
 hcat(X...) = cat(2, X...)
 
+typed_vcat(T::Type, X...) = cat_t(1, T, X...)
+typed_hcat(T::Type, X...) = cat_t(2, T, X...)
+
 cat{T}(catdim::Integer, A::AbstractArray{T}...) = cat_t(catdim, T, A...)
 
 cat(catdim::Integer, A::AbstractArray...) =
     cat_t(catdim, promote_eltype(A...), A...)
 
-function cat_t(catdim::Integer, typeC, A::AbstractArray...)
+function cat_t(catdim::Integer, typeC::Type, A::AbstractArray...)
     # ndims of all input arrays should be in [d-1, d]
 
     nargs = length(A)
@@ -727,6 +773,9 @@ end
 vcat(A::AbstractArray...) = cat(1, A...)
 hcat(A::AbstractArray...) = cat(2, A...)
 
+typed_vcat(T::Type, A::AbstractArray...) = cat_t(1, T, A...)
+typed_hcat(T::Type, A::AbstractArray...) = cat_t(2, T, A...)
+
 # 2d horizontal and vertical concatenation
 
 function hvcat(nbc::Integer, as...)
@@ -817,25 +866,28 @@ function hvcat_fill(a, xs)
     a
 end
 
-function hvcat(rows::(Int...), xs::Number...)
+function typed_hvcat(T::Type, rows::(Int...), xs...)
     nr = length(rows)
     nc = rows[1]
-    #error check
     for i = 2:nr
         if nc != rows[i]
             error("row ", i, " has mismatched number of columns")
         end
     end
-    T = typeof(xs[1])
-    for i=2:length(xs)
-        T = promote_type(T,typeof(xs[i]))
-    end
     if nr*nc != length(xs)
         error("argument count does not match specified shape")
     end
     hvcat_fill(Array(T, nr, nc), xs)
 end
 
+function hvcat(rows::(Int...), xs::Number...)
+    T = typeof(xs[1])
+    for i = 2:length(xs)
+        T = promote_type(T,typeof(xs[i]))
+    end
+    typed_hvcat(T, rows, xs...)
+end
+
 ## Reductions and scans ##
 
 function isequal(A::AbstractArray, B::AbstractArray)
diff --git a/base/array.jl b/base/array.jl
index fcaa3009a2c9e..b614c2f108d4c 100644
--- a/base/array.jl
+++ b/base/array.jl
@@ -125,12 +125,15 @@ end
 
 getindex(T::(Type...)) = Array(T,0)
 
+if _oldstyle_array_vcat_
 # T[a:b] and T[a:s:b] also contruct typed ranges
 function getindex{T<:Number}(::Type{T}, r::Range)
+    warn_once("T[a:b] concatenation is deprecated; use T[a:b;] instead")
     copy!(Array(T,length(r)), r)
 end
 
 function getindex{T<:Number}(::Type{T}, r1::Range, rs::Range...)
+    warn_once("T[a:b,...] concatenation is deprecated; use T[a:b;...] instead")
     a = Array(T,length(r1)+sum(length,rs))
     o = 1
     copy!(a, o, r1)
@@ -141,6 +144,7 @@ function getindex{T<:Number}(::Type{T}, r1::Range, rs::Range...)
     end
     return a
 end
+end
 
 function fill!{T<:Union(Int8,Uint8)}(a::Array{T}, x::Integer)
     ccall(:memset, Ptr{Void}, (Ptr{Void}, Int32, Csize_t), a, x, length(a))
diff --git a/base/show.jl b/base/show.jl
index a17265f99a6d0..d71cfbd1e9f1e 100644
--- a/base/show.jl
+++ b/base/show.jl
@@ -246,7 +246,7 @@ const expr_infix_wide = Set([:(=), :(+=), :(-=), :(*=), :(/=), :(\=), :(&=),
 const expr_infix = Set([:(:), :(<:), :(->), :(=>), symbol("::")])
 const expr_calls  = [:call =>('(',')'), :calldecl =>('(',')'), :ref =>('[',']'), :curly =>('{','}')]
 const expr_parens = [:tuple=>('(',')'), :vcat=>('[',']'), :cell1d=>('{','}'),
-                     :hcat =>('[',']'), :row =>('[',']')]
+                     :hcat =>('[',']'), :row =>('[',']'), :vect=>('[',']')]
 
 ## AST decoding helpers ##
 
diff --git a/src/julia-parser.scm b/src/julia-parser.scm
index 32999aacc3d91..9961ab8c867dc 100644
--- a/src/julia-parser.scm
+++ b/src/julia-parser.scm
@@ -934,14 +934,10 @@
 		       (loop (list 'typed_dict ex))
 		       (loop (list 'ref ex)))
 		   (case (car al)
+                     ((vect)  (loop (list* 'ref ex (cdr al))))
 		     ((dict)  (loop (list* 'typed_dict ex (cdr al))))
 		     ((hcat)  (loop (list* 'typed_hcat ex (cdr al))))
-		     ((vcat)
-		      (if (any (lambda (x)
-				 (and (pair? x) (eq? (car x) 'row)))
-			       (cdr al))
-			  (loop (list* 'typed_vcat ex (cdr al)))
-			  (loop (list* 'ref ex (cdr al)))))
+		     ((vcat)  (loop (list* 'typed_vcat ex (cdr al))))
 		     ((comprehension)
 		      (loop (list* 'typed_comprehension ex (cdr al))))
 		     ((dict_comprehension)
@@ -1387,21 +1383,20 @@
 		       (error (string "missing comma or " closer
 				      " in argument list"))))))))))
 
-; parse [] concatenation expressions and {} cell expressions
-(define (parse-vcat s first closer)
+(define (parse-vect s first closer)
   (let loop ((lst '())
 	     (nxt first))
     (let ((t (require-token s)))
       (if (eqv? t closer)
 	  (begin (take-token s)
-		 (cons 'vcat (reverse (cons nxt lst))))
+		 (cons 'vect (reverse (cons nxt lst))))
 	  (case t
 	    ((#\,)
 	     (take-token s)
 	     (if (eqv? (require-token s) closer)
 		 ;; allow ending with ,
 		 (begin (take-token s)
-			(cons 'vcat (reverse (cons nxt lst))))
+			(cons 'vect (reverse (cons nxt lst))))
 		 (loop (cons nxt lst) (parse-eq* s))))
 	    ((#\;)
 	     (error "unexpected semicolon in array expression"))
@@ -1411,7 +1406,7 @@
 	     (error "missing separator in array expression")))))))
 
 (define (parse-dict s first closer)
-  (let ((v (parse-vcat s first closer)))
+  (let ((v (parse-vect s first closer)))
     (if (any dict-literal? (cdr v))
         (if (every dict-literal? (cdr v))
             `(dict ,@(cdr v))
@@ -1447,7 +1442,7 @@
 		 (if (pair? outer)
 		     (fix 'vcat (update-outer vec outer))
 		     (if (or (null? vec) (null? (cdr vec)))
-			 (fix 'vcat vec)     ; [x]   => (vcat x)
+			 (fix 'vect vec)     ; [x]   => (vect x)
 			 (fix 'hcat vec))))  ; [x y] => (hcat x y)
 	  (case t
 	    ((#\; #\newline)
@@ -1488,8 +1483,8 @@
                 (else
                  (parse-dict s first closer)))
               (case (peek-token s)
-                ((#\,)
-                 (parse-vcat s first closer))
+                ((#\, closer)
+                 (parse-vect s first closer))
                 ((for)
                  (take-token s)
                  (parse-comprehension s first closer))
@@ -1764,6 +1759,7 @@
                  (if (null? vex)
                      '(cell1d)
                      (case (car vex)
+                       ((vect)  `(cell1d ,@(cdr vex)))
                        ((comprehension)
                         `(typed_comprehension (top Any) ,@(cdr vex)))
                        ((dict_comprehension)
@@ -1799,7 +1795,7 @@
 	  ((eqv? t #\[ )
 	   (take-token s)
 	   (let ((vex (parse-cat s #\])))
-             (if (null? vex) '(vcat) vex)))
+             (if (null? vex) '(vect) vex)))
 
 	  ;; string literal
 	  ((eqv? t #\")
diff --git a/src/julia-syntax.scm b/src/julia-syntax.scm
index 704309d4b32a4..5519fa58e24b2 100644
--- a/src/julia-syntax.scm
+++ b/src/julia-syntax.scm
@@ -1887,6 +1887,9 @@
 	 (error "invalid \":\" outside indexing"))
      `(call colon ,.(map expand-forms (cdr e))))
 
+   'vect
+   (lambda (e) (expand-forms `(call (top vect) ,@(cdr e))))
+
    'hcat
    (lambda (e) (expand-forms `(call hcat ,.(map expand-forms (cdr e)))))
 
@@ -1909,47 +1912,26 @@
 	    `(call vcat ,@a)))))
 
    'typed_hcat
-   (lambda (e)
-     (let ((t (cadr e))
-	   (a (cddr e)))
-       (let ((result (gensy))
-	     (ncols (length a)))
-	 `(block
-	   #;(if (call (top !) (call (top isa) ,t Type))
-	   (call (top error) "invalid array index"))
-	   (= ,result (call (top Array) ,(expand-forms t) 1 ,ncols))
-	   ,.(map (lambda (x i) `(call (top setindex!) ,result
-				       ,(expand-forms x) ,i))
-		  a (cdr (iota (+ ncols 1))))
-	   ,result))))
+   (lambda (e) `(call (top typed_hcat) ,(expand-forms (cadr e)) ,.(map expand-forms (cddr e))))
 
    'typed_vcat
    (lambda (e)
      (let ((t (cadr e))
-	   (rows (cddr e)))
-       (if (any (lambda (x) (not (and (pair? x) (eq? 'row (car x))))) rows)
-	   (error "invalid array literal")
-	   (let ((result (gensy))
-		 (nrows (length rows))
-		 (ncols (length (cdar rows))))
-	     (if (any (lambda (x) (not (= (length (cdr x)) ncols))) rows)
-		 (error "invalid array literal")
-		 `(block
-		   #;(if (call (top !) (call (top isa) ,t Type))
-		   (call (top error) "invalid array index"))
-		   (= ,result (call (top Array) ,(expand-forms t) ,nrows ,ncols))
-		   ,.(apply nconc
-			    (map
-			     (lambda (row i)
-			       (map
-				(lambda (x j)
-				  `(call (top setindex!) ,result
-					 ,(expand-forms x) ,i ,j))
-				(cdr row)
-				(cdr (iota (+ ncols 1)))))
-			     rows
-			     (cdr (iota (+ nrows 1)))))
-		   ,result))))))
+           (a (cddr e)))
+       (expand-forms
+        (if (any (lambda (x)
+             (and (pair? x) (eq? (car x) 'row)))
+           a)
+            ;; convert nested hcat inside vcat to hvcat
+            (let ((rows (map (lambda (x)
+                               (if (and (pair? x) (eq? (car x) 'row))
+                                   (cdr x)
+                                   (list x)))
+                             a)))
+              `(call (top typed_hvcat) ,t
+                     (tuple ,.(map length rows))
+                     ,.(apply nconc rows)))
+            `(call (top typed_vcat) ,t ,@a)))))
 
    '|'|  (lambda (e) `(call ctranspose ,(expand-forms (cadr e))))
    '|.'| (lambda (e) `(call  transpose ,(expand-forms (cadr e))))
diff --git a/test/arrayops.jl b/test/arrayops.jl
index f95e383a801e0..5236424a09c1d 100644
--- a/test/arrayops.jl
+++ b/test/arrayops.jl
@@ -258,6 +258,18 @@ Y = [1. 2. 3.; 4. 5. 6.]
 @test size(X) == size(Y)
 for i = 1:length(X) @test X[i] === Y[i] end
 
+_array_equiv(a,b) = eltype(a) == eltype(b) && a == b
+@test _array_equiv(Uint8[1:3;4], [0x1,0x2,0x3,0x4])
+if !Base._oldstyle_array_vcat_
+    @test_throws MethodError Uint8[1:3]
+    @test_throws MethodError Uint8[1:3,]
+    @test_throws MethodError Uint8[1:3,4:6]
+    a = Array(Range1{Int},1); a[1] = 1:3
+    @test _array_equiv([1:3,], a)
+    a = Array(Range1{Int},2); a[1] = 1:3; a[2] = 4:6
+    @test _array_equiv([1:3,4:6], a)
+end
+
 # "end"
 X = [ i+2j for i=1:5, j=1:5 ]
 @test X[end,end] == 15