changeset 8150:283989f2da9b

make null assignment matlab compatible
author Jaroslav Hajek <highegg@gmail.com>
date Fri, 26 Sep 2008 11:52:01 -0400
parents a8fb37ae61b8
children 3725f819b5b3
files liboctave/Array.cc liboctave/Array.h liboctave/ChangeLog liboctave/Sparse.cc src/ChangeLog src/Makefile.in src/OPERATORS/op-bm-bm.cc src/OPERATORS/op-cell.cc src/OPERATORS/op-cm-cm.cc src/OPERATORS/op-cs-cs.cc src/OPERATORS/op-fcm-fcm.cc src/OPERATORS/op-fcs-fcs.cc src/OPERATORS/op-fm-fm.cc src/OPERATORS/op-fs-fs.cc src/OPERATORS/op-i16-i16.cc src/OPERATORS/op-i32-i32.cc src/OPERATORS/op-i64-i64.cc src/OPERATORS/op-i8-i8.cc src/OPERATORS/op-int.h src/OPERATORS/op-m-m.cc src/OPERATORS/op-range.cc src/OPERATORS/op-s-s.cc src/OPERATORS/op-scm-scm.cc src/OPERATORS/op-sm-sm.cc src/OPERATORS/op-str-str.cc src/OPERATORS/op-ui16-ui16.cc src/OPERATORS/op-ui32-ui32.cc src/OPERATORS/op-ui64-ui64.cc src/OPERATORS/op-ui8-ui8.cc src/oct-obj.cc src/oct-obj.h src/ops.h src/ov-base-mat.cc src/ov-base-mat.h src/ov-base-sparse.cc src/ov-base-sparse.h src/ov-base.h src/ov-builtin.cc src/ov-cell.cc src/ov-null-mat.cc src/ov-null-mat.h src/ov-struct.cc src/ov-type-conv.h src/ov.cc src/ov.h src/parse.y src/pt-decl.h src/pt-misc.cc
diffstat 48 files changed, 1138 insertions(+), 609 deletions(-) [+]
line wrap: on
line diff
--- a/liboctave/Array.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/liboctave/Array.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -1758,7 +1758,7 @@
             }
 	}
     }
-  else
+  else if (! (idx_i.orig_empty () || idx_j.orig_empty ()))
     {
       (*current_liboctave_error_handler)
         ("a null assignment can have only one non-colon index");
@@ -1778,6 +1778,21 @@
 {
   octave_idx_type n_idx = ra_idx.length ();
 
+  // Special case matrices
+  if (ndims () == 2)
+    {
+      if (n_idx == 1)
+        {
+          maybe_delete_elements (ra_idx (0));
+          return;
+        }
+      else if (n_idx == 2)
+        {
+          maybe_delete_elements (ra_idx (0), ra_idx (1));
+          return;
+        }
+    }
+
   dim_vector lhs_dims = dims ();
 
   int n_lhs_dims = lhs_dims.length ();
@@ -1818,6 +1833,7 @@
 
   for (octave_idx_type i = 0; i < n_idx; i++)
     {
+      if (ra_idx(i).orig_empty ()) return;
       idx_is_colon_equiv(i) = ra_idx(i).is_colon_equiv (lhs_dims(i), 1);
 
       idx_is_colon(i) = ra_idx(i).is_colon ();
@@ -1873,18 +1889,15 @@
   if (idx_ok)
     {
       if (n_idx > 1
-	  && (all_ones (idx_is_colon) || all_ones (idx_is_colon_equiv)))
+	  && (all_ones (idx_is_colon)))
 	{
 	  // A(:,:,:) -- we are deleting elements in all dimensions, so
 	  // the result is [](0x0x0).
 
-	  dim_vector zeros;
-	  zeros.resize (n_idx);
-
-	  for (int i = 0; i < n_idx; i++)
-	    zeros(i) = 0;
-
-	  resize (zeros, rfv);
+	  dim_vector newdim = dims ();
+          newdim(0) = 0;
+
+	  resize (newdim, rfv);
 	}
 
       else if (n_idx > 1
@@ -3089,102 +3102,95 @@
 	}
 
       if (idx_i && idx_j)
-	{
-	  if (rhs_nr == 0 && rhs_nc == 0)
-	    {
-	      lhs.maybe_delete_elements (idx_i, idx_j);
-	    }
-	  else
-	    {
-	      if (rhs_is_scalar && n >= 0 && m >= 0)
-		{
-		  // No need to do anything if either of the indices
-		  // are empty.
-
-		  if (n > 0 && m > 0)
-		    {
-		      lhs.make_unique ();
-
-		      MAYBE_RESIZE_LHS;
-
-		      RT scalar = xrhs.elem (0, 0);
-
-		      for (octave_idx_type j = 0; j < m; j++)
-			{
-			  octave_idx_type jj = idx_j.elem (j);
-			  for (octave_idx_type i = 0; i < n; i++)
-			    {
-			      octave_idx_type ii = idx_i.elem (i);
-			      lhs.xelem (ii, jj) = scalar;
-			    }
-			}
-		    }
-		}
-	      else if ((n == 1 || m == 1)
-		       && (rhs_nr == 1 || rhs_nc == 1)
-		       && n * m == rhs_nr * rhs_nc)
-		{
-		  lhs.make_unique ();
-
-		  MAYBE_RESIZE_LHS;
-
-		  if (n > 0 && m > 0)
-		    {
-		      octave_idx_type k = 0;
-
-		      for (octave_idx_type j = 0; j < m; j++)
-			{
-			  octave_idx_type jj = idx_j.elem (j);
-			  for (octave_idx_type i = 0; i < n; i++)
-			    {
-			      octave_idx_type ii = idx_i.elem (i);
-			      lhs.xelem (ii, jj) = xrhs.elem (k++);
-			    }
-			}
-		    }
-		}
-	      else if (n == rhs_nr && m == rhs_nc)
-		{
-		  lhs.make_unique ();
-
-		  MAYBE_RESIZE_LHS;
-
-		  if (n > 0 && m > 0)
-		    {
-		      for (octave_idx_type j = 0; j < m; j++)
-			{
-			  octave_idx_type jj = idx_j.elem (j);
-			  for (octave_idx_type i = 0; i < n; i++)
-			    {
-			      octave_idx_type ii = idx_i.elem (i);
-			      lhs.xelem (ii, jj) = xrhs.elem (i, j);
-			    }
-			}
-		    }
-		}
-	      else if (n == 0 && m == 0)
-		{
-		  if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0)))
-		    {
-		      lhs.clear_index ();
-
-		      (*current_liboctave_error_handler)
-		("A([], []) = X: X must be an empty matrix or a scalar");
-
-		      retval = 0;
-		    }
-		}
-	      else
-		{
-		  lhs.clear_index ();
-
-		  (*current_liboctave_error_handler)
-    ("A(I, J) = X: X must be a scalar or the number of elements in I must match the number of rows in X and the number of elements in J must match the number of columns in X");
-
-		  retval = 0;
-		}
-	    }
-	}
+        {
+          if (rhs_is_scalar && n >= 0 && m >= 0)
+            {
+              // No need to do anything if either of the indices
+              // are empty.
+
+              if (n > 0 && m > 0)
+                {
+                  lhs.make_unique ();
+
+                  MAYBE_RESIZE_LHS;
+
+                  RT scalar = xrhs.elem (0, 0);
+
+                  for (octave_idx_type j = 0; j < m; j++)
+                    {
+                      octave_idx_type jj = idx_j.elem (j);
+                      for (octave_idx_type i = 0; i < n; i++)
+                        {
+                          octave_idx_type ii = idx_i.elem (i);
+                          lhs.xelem (ii, jj) = scalar;
+                        }
+                    }
+                }
+            }
+          else if ((n == 1 || m == 1)
+                   && (rhs_nr == 1 || rhs_nc == 1)
+                   && n * m == rhs_nr * rhs_nc)
+            {
+              lhs.make_unique ();
+
+              MAYBE_RESIZE_LHS;
+
+              if (n > 0 && m > 0)
+                {
+                  octave_idx_type k = 0;
+
+                  for (octave_idx_type j = 0; j < m; j++)
+                    {
+                      octave_idx_type jj = idx_j.elem (j);
+                      for (octave_idx_type i = 0; i < n; i++)
+                        {
+                          octave_idx_type ii = idx_i.elem (i);
+                          lhs.xelem (ii, jj) = xrhs.elem (k++);
+                        }
+                    }
+                }
+            }
+          else if (n == rhs_nr && m == rhs_nc)
+            {
+              lhs.make_unique ();
+
+              MAYBE_RESIZE_LHS;
+
+              if (n > 0 && m > 0)
+                {
+                  for (octave_idx_type j = 0; j < m; j++)
+                    {
+                      octave_idx_type jj = idx_j.elem (j);
+                      for (octave_idx_type i = 0; i < n; i++)
+                        {
+                          octave_idx_type ii = idx_i.elem (i);
+                          lhs.xelem (ii, jj) = xrhs.elem (i, j);
+                        }
+                    }
+                }
+            }
+          else if (n == 0 && m == 0)
+            {
+              if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0)))
+                {
+                  lhs.clear_index ();
+
+                  (*current_liboctave_error_handler)
+                    ("A([], []) = X: X must be an empty matrix or a scalar");
+
+                  retval = 0;
+                }
+            }
+          else
+            {
+              lhs.clear_index ();
+
+              (*current_liboctave_error_handler)
+                ("A(I, J) = X: X must be a scalar or the number of elements in I must match the number of rows in X and the number of elements in J must match the number of columns in X");
+
+              retval = 0;
+            }
+        }
       // idx_vector::freeze() printed an error message for us.
     }
   else if (n_idx == 1)
@@ -3198,49 +3204,42 @@
 	  idx_i.freeze (lhs_len, 0, true);
 
 	  if (idx_i)
-	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		{
-		  lhs.maybe_delete_elements (idx_i);
-		}
-	      else
-		{
-		  if (lhs_is_empty
-		      && idx_i.is_colon ()
-		      && ! (rhs_nr == 1 || rhs_nc == 1))
-		    {
-		      (*current_liboctave_warning_with_id_handler)
-			("Octave:fortran-indexing",
-			 "A(:) = X: X is not a vector or scalar");
-		    }
-		  else
-		    {
-		      octave_idx_type idx_nr = idx_i.orig_rows ();
-		      octave_idx_type idx_nc = idx_i.orig_columns ();
-
-		      if (! (rhs_nr == idx_nr && rhs_nc == idx_nc))
-			(*current_liboctave_warning_with_id_handler)
-			  ("Octave:fortran-indexing",
-			   "A(I) = X: X does not have same shape as I");
-		    }
-
-		  if (assign1 (lhs, xrhs, rfv))
-		    {
-		      octave_idx_type len = lhs.length ();
-
-		      if (len > 0)
-			{
-			  // The following behavior is much simplified
-			  // over previous versions of Octave.  It
-			  // seems to be compatible with Matlab.
-
-			  lhs.dimensions = dim_vector (1, lhs.length ());
-			}
-		    }
-		  else
-		    retval = 0;
-		}
-	    }
+            {
+              if (lhs_is_empty
+                  && idx_i.is_colon ()
+                  && ! (rhs_nr == 1 || rhs_nc == 1))
+                {
+                  (*current_liboctave_warning_with_id_handler)
+                    ("Octave:fortran-indexing",
+                     "A(:) = X: X is not a vector or scalar");
+                }
+              else
+                {
+                  octave_idx_type idx_nr = idx_i.orig_rows ();
+                  octave_idx_type idx_nc = idx_i.orig_columns ();
+
+                  if (! (rhs_nr == idx_nr && rhs_nc == idx_nc))
+                    (*current_liboctave_warning_with_id_handler)
+                      ("Octave:fortran-indexing",
+                       "A(I) = X: X does not have same shape as I");
+                }
+
+              if (assign1 (lhs, xrhs, rfv))
+                {
+                  octave_idx_type len = lhs.length ();
+
+                  if (len > 0)
+                    {
+                      // The following behavior is much simplified
+                      // over previous versions of Octave.  It
+                      // seems to be compatible with Matlab.
+
+                      lhs.dimensions = dim_vector (1, lhs.length ());
+                    }
+                }
+              else
+                retval = 0;
+            }
 	  // idx_vector::freeze() printed an error message for us.
 	}
       else if (lhs_nr == 1)
@@ -3248,17 +3247,12 @@
 	  idx_i.freeze (lhs_nc, "vector", true);
 
 	  if (idx_i)
-	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else
-		{
-		  if (assign1 (lhs, xrhs, rfv))
-		    lhs.dimensions = dim_vector (1, lhs.length ());
-		  else
-		    retval = 0;
-		}
-	    }
+            {
+              if (assign1 (lhs, xrhs, rfv))
+                lhs.dimensions = dim_vector (1, lhs.length ());
+              else
+                retval = 0;
+            }
 	  // idx_vector::freeze() printed an error message for us.
 	}
       else if (lhs_nc == 1)
@@ -3267,15 +3261,10 @@
 
 	  if (idx_i)
 	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else
-		{
-		  if (assign1 (lhs, xrhs, rfv))
-		    lhs.dimensions = dim_vector (lhs.length (), 1);
-		  else
-		    retval = 0;
-		}
+              if (assign1 (lhs, xrhs, rfv))
+                lhs.dimensions = dim_vector (lhs.length (), 1);
+              else
+                retval = 0;
 	    }
 	  // idx_vector::freeze() printed an error message for us.
 	}
@@ -3289,9 +3278,7 @@
 
 	  if (idx_i)
 	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else if (len == 0)
+	      if (len == 0)
 		{
 		  if (! (rhs_is_scalar || (rhs_nr == 0 || rhs_nc == 0)))
 		    {
--- a/liboctave/Array.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/liboctave/Array.h	Fri Sep 26 11:52:01 2008 -0400
@@ -502,8 +502,6 @@
 
   void maybe_delete_elements (Array<idx_vector>& ra_idx, const T& rfv);
 
-  void maybe_delete_elements (octave_idx_type dim, idx_vector& i);
-
   Array<T> value (void) const;
 
   Array<T> index (idx_vector& i, int resize_ok = 0,
--- a/liboctave/ChangeLog	Thu Sep 25 13:44:51 2008 -0400
+++ b/liboctave/ChangeLog	Fri Sep 26 11:52:01 2008 -0400
@@ -1,3 +1,12 @@
+2008-09-26  Jaroslav Hajek  <highegg@gmail.com>
+
+	* Array.cc (assign1, assign2, assignN): Do not call
+	maybe_delete_elements.
+	(maybe_delete_elements (Array<idx_vector>&)): Call the 1D and 2D
+	special handlers if possible.
+	* Sparse.cc (assign1, assign2, assignN): Do not call
+	maybe_delete_elements.
+
 2008-09-22  Brian Gough  <bjg@gnu.org>
 
 	* oct-rand.cc (initialize_mersenne_twister): Use separate
--- a/liboctave/Sparse.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/liboctave/Sparse.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -2865,354 +2865,347 @@
 	}
 
       if (idx_i && idx_j)
-	{
-	  if (rhs_nr == 0 && rhs_nc == 0)
-	    {
-	      lhs.maybe_delete_elements (idx_i, idx_j);
-	    }
-	  else
-	    {
-	      if (rhs_nr == 1 && rhs_nc == 1 && n >= 0 && m >= 0)
-		{
-		  if (n > 0 && m > 0)
-		    {
-		      idx_i.sort (true);
-		      n = idx_i.length (n);
-		      idx_j.sort (true);
-		      m = idx_j.length (m);
-
-		      octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : 
-			idx_i.max () + 1;
-		      octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : 
-			idx_j.max () + 1;
-		      octave_idx_type new_nr = max_row_idx > lhs_nr ? 
-			max_row_idx : lhs_nr;
-		      octave_idx_type new_nc = max_col_idx > lhs_nc ? 
-			max_col_idx : lhs_nc;
-		      RT scalar = rhs.elem (0, 0);
-
-		      // Count the number of non-zero terms
-		      octave_idx_type new_nzmx = lhs.nnz ();
-		      for (octave_idx_type j = 0; j < m; j++)
-			{
-			  octave_idx_type jj = idx_j.elem (j);
-			  if (jj < lhs_nc)
-			    {
-			      for (octave_idx_type i = 0; i < n; i++)
-				{
-				  OCTAVE_QUIT;
-
-				  octave_idx_type ii = idx_i.elem (i);
-			      
-				  if (ii < lhs_nr)
-				    {
-				      for (octave_idx_type k = c_lhs.cidx(jj); 
-					   k < c_lhs.cidx(jj+1); k++)
-					{
-					  if (c_lhs.ridx(k) == ii)
-					    new_nzmx--;
-					  if (c_lhs.ridx(k) >= ii)
-					    break;
-					}
-				    }
-				}
-			    }
-			}
-
-		      if (scalar != RT())
-			new_nzmx += m * n;
-
-		      Sparse<LT> stmp (new_nr, new_nc, new_nzmx);
-
-		      octave_idx_type jji = 0;
-		      octave_idx_type jj = idx_j.elem (jji);
-		      octave_idx_type kk = 0;
-		      stmp.cidx(0) = 0;
-		      for (octave_idx_type j = 0; j < new_nc; j++)
-			{
-			  if (jji < m && jj == j)
-			    {
-			      octave_idx_type iii = 0;
-			      octave_idx_type ii = idx_i.elem (iii);
-			      octave_idx_type ppp = 0;
-			      octave_idx_type ppi = (j >= lhs_nc ? 0 : 
-						     c_lhs.cidx(j+1) - 
-						     c_lhs.cidx(j));
-			      octave_idx_type pp = (ppp < ppi ? 
-					c_lhs.ridx(c_lhs.cidx(j)+ppp) :
-					new_nr);
-			      while (ppp < ppi || iii < n)
-				{
-				  if (iii < n && ii <= pp)
-				    {
-				      if (scalar != RT ())
-					{
-					  stmp.data(kk) = scalar;
-					  stmp.ridx(kk++) = ii;
-					}
-				      if (ii == pp)
-					pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);					
-				      if (++iii < n)
-					ii = idx_i.elem(iii);
-				    }
-				  else
-				    {
-				      stmp.data(kk) = 
-					c_lhs.data(c_lhs.cidx(j)+ppp);
-				      stmp.ridx(kk++) = pp;
-				      pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);
-				    }
-				}
-			      if (++jji < m)
-				jj = idx_j.elem(jji);
-			    }
-			  else if (j < lhs_nc) 
-			    {
-			      for (octave_idx_type i = c_lhs.cidx(j); 
-				   i < c_lhs.cidx(j+1); i++)
-				{
-				  stmp.data(kk) = c_lhs.data(i);
-				  stmp.ridx(kk++) = c_lhs.ridx(i);
-				}
-			    }
-			  stmp.cidx(j+1) = kk;
-			}
-		      
-		      lhs = stmp;
-		    }
-		  else
-		    {
+        {
+          if (rhs_nr == 1 && rhs_nc == 1 && n >= 0 && m >= 0)
+            {
+              if (n > 0 && m > 0)
+                {
+                  idx_i.sort (true);
+                  n = idx_i.length (n);
+                  idx_j.sort (true);
+                  m = idx_j.length (m);
+
+                  octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : 
+                    idx_i.max () + 1;
+                  octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : 
+                    idx_j.max () + 1;
+                  octave_idx_type new_nr = max_row_idx > lhs_nr ? 
+                    max_row_idx : lhs_nr;
+                  octave_idx_type new_nc = max_col_idx > lhs_nc ? 
+                    max_col_idx : lhs_nc;
+                  RT scalar = rhs.elem (0, 0);
+
+                  // Count the number of non-zero terms
+                  octave_idx_type new_nzmx = lhs.nnz ();
+                  for (octave_idx_type j = 0; j < m; j++)
+                    {
+                      octave_idx_type jj = idx_j.elem (j);
+                      if (jj < lhs_nc)
+                        {
+                          for (octave_idx_type i = 0; i < n; i++)
+                            {
+                              OCTAVE_QUIT;
+
+                              octave_idx_type ii = idx_i.elem (i);
+
+                              if (ii < lhs_nr)
+                                {
+                                  for (octave_idx_type k = c_lhs.cidx(jj); 
+                                       k < c_lhs.cidx(jj+1); k++)
+                                    {
+                                      if (c_lhs.ridx(k) == ii)
+                                        new_nzmx--;
+                                      if (c_lhs.ridx(k) >= ii)
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                  if (scalar != RT())
+                    new_nzmx += m * n;
+
+                  Sparse<LT> stmp (new_nr, new_nc, new_nzmx);
+
+                  octave_idx_type jji = 0;
+                  octave_idx_type jj = idx_j.elem (jji);
+                  octave_idx_type kk = 0;
+                  stmp.cidx(0) = 0;
+                  for (octave_idx_type j = 0; j < new_nc; j++)
+                    {
+                      if (jji < m && jj == j)
+                        {
+                          octave_idx_type iii = 0;
+                          octave_idx_type ii = idx_i.elem (iii);
+                          octave_idx_type ppp = 0;
+                          octave_idx_type ppi = (j >= lhs_nc ? 0 : 
+                                                 c_lhs.cidx(j+1) - 
+                                                 c_lhs.cidx(j));
+                          octave_idx_type pp = (ppp < ppi ? 
+                                                c_lhs.ridx(c_lhs.cidx(j)+ppp) :
+                                                new_nr);
+                          while (ppp < ppi || iii < n)
+                            {
+                              if (iii < n && ii <= pp)
+                                {
+                                  if (scalar != RT ())
+                                    {
+                                      stmp.data(kk) = scalar;
+                                      stmp.ridx(kk++) = ii;
+                                    }
+                                  if (ii == pp)
+                                    pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);					
+                                  if (++iii < n)
+                                    ii = idx_i.elem(iii);
+                                }
+                              else
+                                {
+                                  stmp.data(kk) = 
+                                    c_lhs.data(c_lhs.cidx(j)+ppp);
+                                  stmp.ridx(kk++) = pp;
+                                  pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);
+                                }
+                            }
+                          if (++jji < m)
+                            jj = idx_j.elem(jji);
+                        }
+                      else if (j < lhs_nc) 
+                        {
+                          for (octave_idx_type i = c_lhs.cidx(j); 
+                               i < c_lhs.cidx(j+1); i++)
+                            {
+                              stmp.data(kk) = c_lhs.data(i);
+                              stmp.ridx(kk++) = c_lhs.ridx(i);
+                            }
+                        }
+                      stmp.cidx(j+1) = kk;
+                    }
+
+                  lhs = stmp;
+                }
+              else
+                {
 #if 0
-		      // FIXME -- the following code will make this
-		      // function behave the same as the full matrix
-		      // case for things like
-		      //
-		      // x = sparse (ones (2));
-		      // x([],3) = 2;
-		      //
-		      // x =
-		      //
-		      // Compressed Column Sparse (rows = 2, cols = 3, nnz = 4)
-		      //
-		      // (1, 1) ->  1
-		      // (2, 1) ->  1
-		      // (1, 2) ->  1
-		      // (2, 2) ->  1
-		      //
-		      // However, Matlab doesn't resize in this case
-		      // even though it does in the full matrix case.
-
-		      if (n > 0)
-			{
-			  octave_idx_type max_row_idx = idx_i_is_colon ? 
-			    rhs_nr : idx_i.max () + 1;
-			  octave_idx_type new_nr = max_row_idx > lhs_nr ? 
-			    max_row_idx : lhs_nr;
-			  octave_idx_type new_nc = lhs_nc;
-
-			  lhs.resize (new_nr, new_nc);
-			}
-		      else if (m > 0)
-			{
-			  octave_idx_type max_col_idx = idx_j_is_colon ? 
-			    rhs_nc : idx_j.max () + 1;
-			  octave_idx_type new_nr = lhs_nr;
-			  octave_idx_type new_nc = max_col_idx > lhs_nc ? 
-			    max_col_idx : lhs_nc;
-
-			  lhs.resize  (new_nr, new_nc);
-			}
+                  // FIXME -- the following code will make this
+                  // function behave the same as the full matrix
+                  // case for things like
+                  //
+                  // x = sparse (ones (2));
+                  // x([],3) = 2;
+                  //
+                  // x =
+                  //
+                  // Compressed Column Sparse (rows = 2, cols = 3, nnz = 4)
+                  //
+                  // (1, 1) ->  1
+                  // (2, 1) ->  1
+                  // (1, 2) ->  1
+                  // (2, 2) ->  1
+                  //
+                  // However, Matlab doesn't resize in this case
+                  // even though it does in the full matrix case.
+
+                  if (n > 0)
+                    {
+                      octave_idx_type max_row_idx = idx_i_is_colon ? 
+                        rhs_nr : idx_i.max () + 1;
+                      octave_idx_type new_nr = max_row_idx > lhs_nr ? 
+                        max_row_idx : lhs_nr;
+                      octave_idx_type new_nc = lhs_nc;
+
+                      lhs.resize (new_nr, new_nc);
+                    }
+                  else if (m > 0)
+                    {
+                      octave_idx_type max_col_idx = idx_j_is_colon ? 
+                        rhs_nc : idx_j.max () + 1;
+                      octave_idx_type new_nr = lhs_nr;
+                      octave_idx_type new_nc = max_col_idx > lhs_nc ? 
+                        max_col_idx : lhs_nc;
+
+                      lhs.resize  (new_nr, new_nc);
+                    }
 #endif
-		    }
-		}
-	      else if (n == rhs_nr && m == rhs_nc)
-		{
-		  if (n > 0 && m > 0)
-		    {
-		      octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : 
-			idx_i.max () + 1;
-		      octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : 
-			idx_j.max () + 1;
-		      octave_idx_type new_nr = max_row_idx > lhs_nr ?
-			max_row_idx : lhs_nr;
-		      octave_idx_type new_nc = max_col_idx > lhs_nc ? 
-			max_col_idx : lhs_nc;
-
-		      OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_i, n);
-		      if (! idx_i.is_colon ())
-			{
-			  // Ok here we have to be careful with the indexing,
-			  // to treat cases like "a([3,2,1],:) = b", and still 
-			  // handle the need for strict sorting of the sparse 
-			  // elements.
-			  OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *,
-					       sidx, n);
-			  OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort,
-					       sidxX, n);
-
-			  for (octave_idx_type i = 0; i < n; i++)
-			    {
-			      sidx[i] = &sidxX[i];
-			      sidx[i]->i = idx_i.elem(i);
-			      sidx[i]->idx = i;
-			    }
-			  
-			  OCTAVE_QUIT;
-			  octave_sort<octave_idx_vector_sort *> 
-			    sort (octave_idx_vector_comp);
-
-			  sort.sort (sidx, n);
-
-			  intNDArray<octave_idx_type> new_idx (dim_vector (n,1));
-
-			  for (octave_idx_type i = 0; i < n; i++)
-			    {
-			      new_idx.xelem(i) = sidx[i]->i + 1;
-			      rhs_idx_i[i] = sidx[i]->idx;
-			    }
-
-			  idx_i = idx_vector (new_idx);
-			}
-		      else
-			for (octave_idx_type i = 0; i < n; i++)
-			  rhs_idx_i[i] = i;
-
-		      OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_j, m);
-		      if (! idx_j.is_colon ())
-			{
-			  // Ok here we have to be careful with the indexing,
-			  // to treat cases like "a([3,2,1],:) = b", and still 
-			  // handle the need for strict sorting of the sparse 
-			  // elements.
-			  OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *,
-					       sidx, m);
-			  OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort,
-					       sidxX, m);
-
-			  for (octave_idx_type i = 0; i < m; i++)
-			    {
-			      sidx[i] = &sidxX[i];
-			      sidx[i]->i = idx_j.elem(i);
-			      sidx[i]->idx = i;
-			    }
-			  
-			  OCTAVE_QUIT;
-			  octave_sort<octave_idx_vector_sort *> 
-			    sort (octave_idx_vector_comp);
-
-			  sort.sort (sidx, m);
-
-			  intNDArray<octave_idx_type> new_idx (dim_vector (m,1));
-
-			  for (octave_idx_type i = 0; i < m; i++)
-			    {
-			      new_idx.xelem(i) = sidx[i]->i + 1;
-			      rhs_idx_j[i] = sidx[i]->idx;
-			    }
-
-			  idx_j = idx_vector (new_idx);
-			}
-		      else
-			for (octave_idx_type i = 0; i < m; i++)
-			  rhs_idx_j[i] = i;
-
-		      // Maximum number of non-zero elements
-		      octave_idx_type new_nzmx = lhs.nnz() + rhs.nnz();
-
-		      Sparse<LT> stmp (new_nr, new_nc, new_nzmx);
-
-		      octave_idx_type jji = 0;
-		      octave_idx_type jj = idx_j.elem (jji);
-		      octave_idx_type kk = 0;
-		      stmp.cidx(0) = 0;
-		      for (octave_idx_type j = 0; j < new_nc; j++)
-			{
-			  if (jji < m && jj == j)
-			    {
-			      octave_idx_type iii = 0;
-			      octave_idx_type ii = idx_i.elem (iii);
-			      octave_idx_type ppp = 0;
-			      octave_idx_type ppi = (j >= lhs_nc ? 0 : 
-						     c_lhs.cidx(j+1) - 
-						     c_lhs.cidx(j));
-			      octave_idx_type pp = (ppp < ppi ? 
-						c_lhs.ridx(c_lhs.cidx(j)+ppp) :
-						new_nr);
-			      while (ppp < ppi || iii < n)
-				{
-				  if (iii < n && ii <= pp)
-				    {
-				      if (iii < n - 1 && 
-					  idx_i.elem (iii + 1) == ii)
-					{
-					  iii++;
-					  ii = idx_i.elem(iii);
-					  continue;
-					}
-
-				      RT rtmp = rhs.elem (rhs_idx_i[iii], 
-							  rhs_idx_j[jji]);
-				      if (rtmp != RT ())
-					{
-					  stmp.data(kk) = rtmp;
-					  stmp.ridx(kk++) = ii;
-					}
-				      if (ii == pp)
-					pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);					
-				      if (++iii < n)
-					ii = idx_i.elem(iii);
-				    }
-				  else
-				    {
-				      stmp.data(kk) = 
-					c_lhs.data(c_lhs.cidx(j)+ppp);
-				      stmp.ridx(kk++) = pp;
-				      pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);
-				    }
-				}
-			      if (++jji < m)
-				jj = idx_j.elem(jji);
-			    }
-			  else if (j < lhs_nc) 
-			    {
-			      for (octave_idx_type i = c_lhs.cidx(j); 
-				   i < c_lhs.cidx(j+1); i++)
-				{
-				  stmp.data(kk) = c_lhs.data(i);
-				  stmp.ridx(kk++) = c_lhs.ridx(i);
-				}
-			    }
-			  stmp.cidx(j+1) = kk;
-			}
-
-		      stmp.maybe_compress();
-		      lhs = stmp;
-		    }
-		}
-	      else if (n == 0 && m == 0)
-		{
-		  if (! ((rhs_nr == 1 && rhs_nc == 1)
-			 || (rhs_nr == 0 || rhs_nc == 0)))
-		    {
-		      (*current_liboctave_error_handler)
-		("A([], []) = X: X must be an empty matrix or a scalar");
-
-		      retval = 0;
-		    }
-		}
-	      else
-		{
-		  (*current_liboctave_error_handler)
-    ("A(I, J) = X: X must be a scalar or the number of elements in I must");
-		  (*current_liboctave_error_handler)
-    ("match the number of rows in X and the number of elements in J must");
-		  (*current_liboctave_error_handler)
-    ("match the number of columns in X");
-
-		  retval = 0;
-		}
-	    }
-	}
+                }
+            }
+          else if (n == rhs_nr && m == rhs_nc)
+            {
+              if (n > 0 && m > 0)
+                {
+                  octave_idx_type max_row_idx = idx_i_is_colon ? rhs_nr : 
+                    idx_i.max () + 1;
+                  octave_idx_type max_col_idx = idx_j_is_colon ? rhs_nc : 
+                    idx_j.max () + 1;
+                  octave_idx_type new_nr = max_row_idx > lhs_nr ?
+                    max_row_idx : lhs_nr;
+                  octave_idx_type new_nc = max_col_idx > lhs_nc ? 
+                    max_col_idx : lhs_nc;
+
+                  OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_i, n);
+                  if (! idx_i.is_colon ())
+                    {
+                      // Ok here we have to be careful with the indexing,
+                      // to treat cases like "a([3,2,1],:) = b", and still 
+                      // handle the need for strict sorting of the sparse 
+                      // elements.
+                      OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *,
+                                           sidx, n);
+                      OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort,
+                                           sidxX, n);
+
+                      for (octave_idx_type i = 0; i < n; i++)
+                        {
+                          sidx[i] = &sidxX[i];
+                          sidx[i]->i = idx_i.elem(i);
+                          sidx[i]->idx = i;
+                        }
+
+                      OCTAVE_QUIT;
+                      octave_sort<octave_idx_vector_sort *> 
+                        sort (octave_idx_vector_comp);
+
+                      sort.sort (sidx, n);
+
+                      intNDArray<octave_idx_type> new_idx (dim_vector (n,1));
+
+                      for (octave_idx_type i = 0; i < n; i++)
+                        {
+                          new_idx.xelem(i) = sidx[i]->i + 1;
+                          rhs_idx_i[i] = sidx[i]->idx;
+                        }
+
+                      idx_i = idx_vector (new_idx);
+                    }
+                  else
+                    for (octave_idx_type i = 0; i < n; i++)
+                      rhs_idx_i[i] = i;
+
+                  OCTAVE_LOCAL_BUFFER (octave_idx_type, rhs_idx_j, m);
+                  if (! idx_j.is_colon ())
+                    {
+                      // Ok here we have to be careful with the indexing,
+                      // to treat cases like "a([3,2,1],:) = b", and still 
+                      // handle the need for strict sorting of the sparse 
+                      // elements.
+                      OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort *,
+                                           sidx, m);
+                      OCTAVE_LOCAL_BUFFER (octave_idx_vector_sort,
+                                           sidxX, m);
+
+                      for (octave_idx_type i = 0; i < m; i++)
+                        {
+                          sidx[i] = &sidxX[i];
+                          sidx[i]->i = idx_j.elem(i);
+                          sidx[i]->idx = i;
+                        }
+
+                      OCTAVE_QUIT;
+                      octave_sort<octave_idx_vector_sort *> 
+                        sort (octave_idx_vector_comp);
+
+                      sort.sort (sidx, m);
+
+                      intNDArray<octave_idx_type> new_idx (dim_vector (m,1));
+
+                      for (octave_idx_type i = 0; i < m; i++)
+                        {
+                          new_idx.xelem(i) = sidx[i]->i + 1;
+                          rhs_idx_j[i] = sidx[i]->idx;
+                        }
+
+                      idx_j = idx_vector (new_idx);
+                    }
+                  else
+                    for (octave_idx_type i = 0; i < m; i++)
+                      rhs_idx_j[i] = i;
+
+                  // Maximum number of non-zero elements
+                  octave_idx_type new_nzmx = lhs.nnz() + rhs.nnz();
+
+                  Sparse<LT> stmp (new_nr, new_nc, new_nzmx);
+
+                  octave_idx_type jji = 0;
+                  octave_idx_type jj = idx_j.elem (jji);
+                  octave_idx_type kk = 0;
+                  stmp.cidx(0) = 0;
+                  for (octave_idx_type j = 0; j < new_nc; j++)
+                    {
+                      if (jji < m && jj == j)
+                        {
+                          octave_idx_type iii = 0;
+                          octave_idx_type ii = idx_i.elem (iii);
+                          octave_idx_type ppp = 0;
+                          octave_idx_type ppi = (j >= lhs_nc ? 0 : 
+                                                 c_lhs.cidx(j+1) - 
+                                                 c_lhs.cidx(j));
+                          octave_idx_type pp = (ppp < ppi ? 
+                                                c_lhs.ridx(c_lhs.cidx(j)+ppp) :
+                                                new_nr);
+                          while (ppp < ppi || iii < n)
+                            {
+                              if (iii < n && ii <= pp)
+                                {
+                                  if (iii < n - 1 && 
+                                      idx_i.elem (iii + 1) == ii)
+                                    {
+                                      iii++;
+                                      ii = idx_i.elem(iii);
+                                      continue;
+                                    }
+
+                                  RT rtmp = rhs.elem (rhs_idx_i[iii], 
+                                                      rhs_idx_j[jji]);
+                                  if (rtmp != RT ())
+                                    {
+                                      stmp.data(kk) = rtmp;
+                                      stmp.ridx(kk++) = ii;
+                                    }
+                                  if (ii == pp)
+                                    pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);					
+                                  if (++iii < n)
+                                    ii = idx_i.elem(iii);
+                                }
+                              else
+                                {
+                                  stmp.data(kk) = 
+                                    c_lhs.data(c_lhs.cidx(j)+ppp);
+                                  stmp.ridx(kk++) = pp;
+                                  pp = (++ppp < ppi ? c_lhs.ridx(c_lhs.cidx(j)+ppp) : new_nr);
+                                }
+                            }
+                          if (++jji < m)
+                            jj = idx_j.elem(jji);
+                        }
+                      else if (j < lhs_nc) 
+                        {
+                          for (octave_idx_type i = c_lhs.cidx(j); 
+                               i < c_lhs.cidx(j+1); i++)
+                            {
+                              stmp.data(kk) = c_lhs.data(i);
+                              stmp.ridx(kk++) = c_lhs.ridx(i);
+                            }
+                        }
+                      stmp.cidx(j+1) = kk;
+                    }
+
+                  stmp.maybe_compress();
+                  lhs = stmp;
+                }
+            }
+          else if (n == 0 && m == 0)
+            {
+              if (! ((rhs_nr == 1 && rhs_nc == 1)
+                     || (rhs_nr == 0 || rhs_nc == 0)))
+                {
+                  (*current_liboctave_error_handler)
+                    ("A([], []) = X: X must be an empty matrix or a scalar");
+
+                  retval = 0;
+                }
+            }
+          else
+            {
+              (*current_liboctave_error_handler)
+                ("A(I, J) = X: X must be a scalar or the number of elements in I must");
+              (*current_liboctave_error_handler)
+                ("match the number of rows in X and the number of elements in J must");
+              (*current_liboctave_error_handler)
+                ("match the number of columns in X");
+
+              retval = 0;
+            }
+        }
       // idx_vector::freeze() printed an error message for us.
     }
   else if (n_idx == 1)
@@ -3226,37 +3219,29 @@
 	  octave_idx_type n = idx_i.freeze (lhs_len, 0, true);
 
 	  if (idx_i)
-	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		{
-		  if (n != 0 && (lhs_nr != 0 || lhs_nc != 0))
-		    lhs.maybe_delete_elements (idx_i);
-		}
-	      else
-		{
-		  if (lhs_is_empty
-		      && idx_i.is_colon ()
-		      && ! (rhs_nr == 1 || rhs_nc == 1))
-		    {
-		      (*current_liboctave_warning_with_id_handler)
-			("Octave:fortran-indexing",
-			 "A(:) = X: X is not a vector or scalar");
-		    }
-		  else
-		    {
-		      octave_idx_type idx_nr = idx_i.orig_rows ();
-		      octave_idx_type idx_nc = idx_i.orig_columns ();
-
-		      if (! (rhs_nr == idx_nr && rhs_nc == idx_nc))
-			(*current_liboctave_warning_with_id_handler)
-			  ("Octave:fortran-indexing",
-			   "A(I) = X: X does not have same shape as I");
-		    }
-
-		  if (! assign1 (lhs, rhs))
-		    retval = 0;
-		}
-	    }
+            {
+              if (lhs_is_empty
+                  && idx_i.is_colon ()
+                  && ! (rhs_nr == 1 || rhs_nc == 1))
+                {
+                  (*current_liboctave_warning_with_id_handler)
+                    ("Octave:fortran-indexing",
+                     "A(:) = X: X is not a vector or scalar");
+                }
+              else
+                {
+                  octave_idx_type idx_nr = idx_i.orig_rows ();
+                  octave_idx_type idx_nc = idx_i.orig_columns ();
+
+                  if (! (rhs_nr == idx_nr && rhs_nc == idx_nc))
+                    (*current_liboctave_warning_with_id_handler)
+                      ("Octave:fortran-indexing",
+                       "A(I) = X: X does not have same shape as I");
+                }
+
+              if (! assign1 (lhs, rhs))
+                retval = 0;
+            }
 	  // idx_vector::freeze() printed an error message for us.
 	}
       else if (lhs_nr == 1)
@@ -3264,12 +3249,10 @@
 	  idx_i.freeze (lhs_nc, "vector", true);
 
 	  if (idx_i)
-	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else if (! assign1 (lhs, rhs))
-		retval = 0;
-	    }
+            {
+              if (! assign1 (lhs, rhs))
+                retval = 0;
+            }
 	  // idx_vector::freeze() printed an error message for us.
 	}
       else if (lhs_nc == 1)
@@ -3278,9 +3261,7 @@
 
 	  if (idx_i)
 	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else if (! assign1 (lhs, rhs))
+	      if (! assign1 (lhs, rhs))
 		retval = 0;
 	    }
 	  // idx_vector::freeze() printed an error message for us.
@@ -3297,9 +3278,7 @@
 
 	  if (idx_i)
 	    {
-	      if (rhs_nr == 0 && rhs_nc == 0)
-		lhs.maybe_delete_elements (idx_i);
-	      else if (len == 0)
+	      if (len == 0)
 		{
 		  if (! ((rhs_nr == 1 && rhs_nc == 1)
 			 || (rhs_nr == 0 || rhs_nc == 0)))
--- a/src/ChangeLog	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ChangeLog	Fri Sep 26 11:52:01 2008 -0400
@@ -1,3 +1,58 @@
+2008-09-26  Jaroslav Hajek  <highegg@gmail.com>
+
+	* ov-null-mat.h: New header file.
+	* ov-null-mat.cc: New source.
+	* ov.h (octave_value::is_null_value, octave_value::non_null_value,
+	octave_value::make_non_null_value):
+	Declare new member functions.
+	* ov.cc (octave_value:non_null_value, octave_value::make_non_null_value): 
+	Define them.
+	(octave_value::assign (assign_op op, const octave_value& rhs)): 
+	(register_types): Register null types.
+	Call non_null_value ().
+	* oct-obj.cc (octave_value_list::normalize_null_values): New member
+	function. 
+	* oct-obj.h (octave_value_list::normalize_null_values): Declare it.
+	* ov-base.h (is_null_value): New virtual member function.
+	* ops.h (NULLASSIGNOPDECL, DEFNULLASSIGNOP_FN): New macros.
+	* ov-base-mat.cc (octave_base_mat<MT>::delete_elements): New member func.
+	* ov-base-mat.h: Declare it.
+	* ov-base-sparse.cc (octave_base_sparse<MT>::delete_elements): New member func.
+	* ov-base-sparse.h: Declare it.
+	* ov-cell.cc (octave_cell:subsasgn): Handle null values.	
+	* ov-struct.cc (octave_cell:subsasgn): Handle null values.
+	* ov-builtin.cc (octave_builtin::do_multi_index_op): Normalize return
+	values.
+	* pt-misc.cc (tree_parameter_list::define_from_arg_vector): Call
+	octave_lvalue::define instead of octave_lvalue::assign.
+	* pt-decl.h (tree_decl_elt::rvalue): Call non_null_value ().
+	* OPERATORS/op-int.h (OCTAVE_INT_NULL_ASSIGN_OPS,
+	OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS): New macros.
+	* OPERATORS/op-m-m.cc: Install & define assignment & conversion operators.
+	* OPERATORS/op-bm-bm.cc: Dtto.
+	* OPERATORS/op-cell.cc: Dtto.
+	* OPERATORS/op-cm-cm.cc: Dtto.
+	* OPERATORS/op-cs-cs.cc: Dtto.
+	* OPERATORS/op-fcm-fcm.cc: Dtto.
+	* OPERATORS/op-fcs-fcs.cc: Dtto.
+	* OPERATORS/op-fm-fm.cc: Dtto.
+	* OPERATORS/op-fs-fs.cc: Dtto.
+	* OPERATORS/op-int.h: Dtto.
+	* OPERATORS/op-m-m.cc: Dtto.
+	* OPERATORS/op-range.cc: Dtto.
+	* OPERATORS/op-s-s.cc: Dtto.
+	* OPERATORS/op-scm-scm.cc: Dtto.
+	* OPERATORS/op-sm-sm.cc: Dtto.
+	* OPERATORS/op-str-str.cc: Dtto.
+	* OPERATORS/op-i16-i16.cc: Dtto.
+	* OPERATORS/op-i32-i32.cc: Dtto.
+	* OPERATORS/op-i64-i64.cc: Dtto.
+	* OPERATORS/op-i8-i8.cc: Dtto.
+	* OPERATORS/op-ui16-ui16.cc: Dtto.
+	* OPERATORS/op-ui32-ui32.cc: Dtto.
+	* OPERATORS/op-ui64-ui64.cc: Dtto.
+	* OPERATORS/op-ui8-ui8.cc: Dtto.
+
 2008-09-25  David Bateman  <dbateman@free.fr>
 
 	* pt-mat.cc (class tm_row_const): Add any_class test
--- a/src/Makefile.in	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/Makefile.in	Fri Sep 26 11:52:01 2008 -0400
@@ -100,7 +100,7 @@
 OV_INCLUDES := ov-re-mat.h ov-cx-mat.h ov-ch-mat.h ov-cs-list.h ov-list.h \
 	ov-struct.h ov-scalar.h ov-range.h ov-complex.h \
 	ov-colon.h ov-base.h ov-base-mat.h ov-base-scalar.h \
-	ov-str-mat.h ov-bool-mat.h ov-bool.h \
+	ov-str-mat.h ov-bool-mat.h ov-null-mat.h ov-bool.h \
 	ov-cell.h ov.h ov-fcn.h ov-builtin.h ov-dld-fcn.h \
 	ov-mex-fcn.h ov-usr-fcn.h ov-fcn-handle.h \
 	ov-fcn-inline.h ov-class.h ov-typeinfo.h ov-type-conv.h \
@@ -181,7 +181,7 @@
 	ov-cs-list.cc ov-list.cc ov-re-mat.cc ov-cx-mat.cc \
 	ov-range.cc ov-scalar.cc ov-complex.cc ov-str-mat.cc \
 	ov-struct.cc \
-	ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-cell.cc \
+	ov-colon.cc ov-bool-mat.cc ov-bool.cc ov-null-mat.cc ov-cell.cc \
 	ov.cc ov-fcn.cc ov-builtin.cc ov-dld-fcn.cc \
 	ov-mex-fcn.cc ov-usr-fcn.cc ov-fcn-handle.cc ov-fcn-inline.cc \
 	ov-class.cc ov-typeinfo.cc \
--- a/src/OPERATORS/op-bm-bm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-bm-bm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -44,6 +44,7 @@
 #include "ov-uint32.h"
 #include "ov-uint64.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -86,6 +87,8 @@
 
 DEFNDASSIGNOP_FN (assign, bool_matrix, bool_matrix, bool_array, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, bool_matrix, delete_elements)
+
 static octave_value
 oct_assignop_conv_and_assign (octave_base_value& a1,
 			      const octave_value_list& idx,
@@ -150,6 +153,10 @@
   INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint16_matrix, conv_and_assign);
   INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint32_matrix, conv_and_assign);
   INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_uint64_matrix, conv_and_assign);
+
+  INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_bool_matrix, octave_null_sq_str, null_assign);
 }
 
 /*
--- a/src/OPERATORS/op-cell.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-cell.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -31,6 +31,7 @@
 #include "ov-scalar.h"
 #include "ov-re-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 
 // cell ops.
@@ -82,6 +83,8 @@
 
 DEFASSIGNANYOP_FN (assign, cell, assign);
 
+DEFNULLASSIGNOP_FN (null_assign, cell, delete_elements)
+
 void
 install_cell_ops (void)
 {
@@ -94,6 +97,10 @@
   INSTALL_CATOP (octave_matrix, octave_cell, matrix_cell);
 
   INSTALL_ASSIGNANYOP (op_asn_eq, octave_cell, assign);
+
+  INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_cell, octave_null_sq_str, null_assign);
 }
 
 /*
--- a/src/OPERATORS/op-cm-cm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-cm-cm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -31,6 +31,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -160,6 +161,8 @@
 
 DEFNDASSIGNOP_FN (assign, complex_matrix, complex_matrix, complex_array, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, complex_matrix, delete_elements)
+
 CONVDECL (complex_matrix_to_float_complex_matrix)
 {
   CAST_CONV_ARG (const octave_complex_matrix&);
@@ -206,6 +209,10 @@
 
   INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_complex_matrix, assign);
 
+  INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_complex_matrix, octave_null_sq_str, null_assign);
+
   INSTALL_CONVOP (octave_complex_matrix, octave_float_complex_matrix, 
 		  complex_matrix_to_float_complex_matrix);
 }
--- a/src/OPERATORS/op-cs-cs.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-cs-cs.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -32,6 +32,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -219,6 +220,10 @@
 
   INSTALL_ASSIGNCONV (octave_complex, octave_complex, octave_complex_matrix);
 
+  INSTALL_ASSIGNCONV (octave_complex, octave_null_matrix, octave_complex_matrix);
+  INSTALL_ASSIGNCONV (octave_complex, octave_null_str, octave_complex_matrix);
+  INSTALL_ASSIGNCONV (octave_complex, octave_null_sq_str, octave_complex_matrix);
+
   INSTALL_CONVOP (octave_complex, octave_float_complex_matrix, 
 		  complex_to_float_complex);
 }
--- a/src/OPERATORS/op-fcm-fcm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-fcm-fcm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -31,6 +31,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -186,6 +187,8 @@
 DEFNDASSIGNOP_FN (dbl_assign, complex_matrix, float_complex_matrix, 
 		  complex_array, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, float_complex_matrix, delete_elements)
+
 CONVDECL (float_complex_matrix_to_complex_matrix)
 {
   CAST_CONV_ARG (const octave_float_complex_matrix&);
@@ -262,6 +265,13 @@
   INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, 
 		    octave_complex_matrix, dbl_assign);
 
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, 
+                    octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, 
+                    octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_complex_matrix, 
+                    octave_null_sq_str, null_assign);
+
   INSTALL_CONVOP (octave_float_complex_matrix, octave_complex_matrix, 
 		  float_complex_matrix_to_complex_matrix);
 }
--- a/src/OPERATORS/op-fcs-fcs.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-fcs-fcs.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -32,6 +32,7 @@
 #include "ov-flt-complex.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -232,6 +233,10 @@
 
   INSTALL_ASSIGNCONV (octave_complex, octave_float_complex, octave_complex_matrix);
 
+  INSTALL_ASSIGNCONV (octave_float_complex, octave_null_matrix, octave_float_complex_matrix);
+  INSTALL_ASSIGNCONV (octave_float_complex, octave_null_str, octave_float_complex_matrix);
+  INSTALL_ASSIGNCONV (octave_float_complex, octave_null_sq_str, octave_float_complex_matrix);
+
   INSTALL_CONVOP (octave_float_complex, octave_complex_matrix, 
 		  float_complex_to_complex);
 }
--- a/src/OPERATORS/op-fm-fm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-fm-fm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -31,6 +31,7 @@
 #include "ov-re-mat.h"
 #include "ov-flt-re-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -152,6 +153,8 @@
 
 DEFNDASSIGNOP_FN (dbl_assign, matrix, float_matrix, array, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, float_matrix, delete_elements)
+
 CONVDECL (float_matrix_to_matrix)
 {
   CAST_CONV_ARG (const octave_float_matrix&);
@@ -203,6 +206,10 @@
   INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, 
 		    octave_float_matrix, dbl_assign);
 
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_null_sq_str, null_assign);
+
   INSTALL_CONVOP (octave_float_matrix, octave_matrix, float_matrix_to_matrix);
 }
 
--- a/src/OPERATORS/op-fs-fs.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-fs-fs.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -32,6 +32,7 @@
 #include "ov-float.h"
 #include "ov-flt-re-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -166,6 +167,10 @@
   INSTALL_ASSIGNCONV (octave_float_scalar, octave_float_scalar, octave_float_matrix);
   INSTALL_ASSIGNCONV (octave_scalar, octave_float_scalar, octave_matrix);
 
+  INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_matrix, octave_float_matrix);
+  INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_str, octave_float_matrix);
+  INSTALL_ASSIGNCONV (octave_float_scalar, octave_null_sq_str, octave_float_matrix);
+
   INSTALL_CONVOP (octave_float_scalar, octave_matrix, float_to_scalar);
 }
 
--- a/src/OPERATORS/op-i16-i16.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-i16-i16.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/OPERATORS/op-i32-i32.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-i32-i32.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/OPERATORS/op-i64-i64.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-i64-i64.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -135,6 +136,8 @@
 OCTAVE_MM_INT_ASSIGN_OPS (mmui32, int64_, uint32_, uint32_)
 OCTAVE_MM_INT_ASSIGN_OPS (mmui64, int64_, uint64_, uint64_)
 
+OCTAVE_INT_NULL_ASSIGN_OPS (int64)
+
 OCTAVE_MIXED_INT_CMP_OPS (int64, int8)
 OCTAVE_MIXED_INT_CMP_OPS (int64, uint8)
 OCTAVE_MIXED_INT_CMP_OPS (int64, int16)
@@ -200,6 +203,8 @@
   OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui32, int64_, uint32_);
   OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui64, int64_, uint64_);
 
+  OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS (int64)
+
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, int8);
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, uint8);
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (int64, int16);
--- a/src/OPERATORS/op-i8-i8.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-i8-i8.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/OPERATORS/op-int.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-int.h	Fri Sep 26 11:52:01 2008 -0400
@@ -884,6 +884,9 @@
   DEFNDASSIGNOP_FN (TYPE ## fcms_assign, float_complex_matrix, TYPE ## _scalar, float_complex_array, assign) \
   DEFNDASSIGNOP_FN (TYPE ## fcmm_assign, float_complex_matrix, TYPE ## _matrix, float_complex_array, assign)
 
+#define OCTAVE_INT_NULL_ASSIGN_OPS(TYPE) \
+  DEFNULLASSIGNOP_FN (TYPE ## null_assign, TYPE ## _matrix, delete_elements)
+
 #define OCTAVE_INT_OPS(TYPE) \
   OCTAVE_SS_INT_OPS (TYPE) \
   OCTAVE_SM_INT_OPS (TYPE) \
@@ -893,7 +896,8 @@
   OCTAVE_RE_INT_ASSIGN_OPS (TYPE) \
   OCTAVE_FLT_RE_INT_ASSIGN_OPS (TYPE) \
   OCTAVE_CX_INT_ASSIGN_OPS (TYPE) \
-  OCTAVE_FLT_CX_INT_ASSIGN_OPS (TYPE)
+  OCTAVE_FLT_CX_INT_ASSIGN_OPS (TYPE) \
+  OCTAVE_INT_NULL_ASSIGN_OPS(TYPE)
 
 #define OCTAVE_INSTALL_S_INT_UNOPS(TYPE) \
   INSTALL_UNOP (op_not, octave_ ## TYPE ## _scalar, s_not); \
@@ -1137,6 +1141,11 @@
   INSTALL_ASSIGNCONV (octave_float_complex_scalar, octave_ ## TYPE ## _scalar, octave_complex_matrix) \
   INSTALL_ASSIGNCONV (octave_float_complex_matrix, octave_ ## TYPE ## _matrix, octave_complex_matrix)
 
+#define OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS(TYPE) \
+  INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_matrix, TYPE ## null_assign) \
+  INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_str, TYPE ## null_assign) \
+  INSTALL_ASSIGNOP (op_asn_eq, octave_ ## TYPE ## _matrix, octave_null_sq_str, TYPE ## null_assign)
+
 #define OCTAVE_INSTALL_INT_OPS(TYPE) \
   OCTAVE_INSTALL_SS_INT_OPS (TYPE) \
   OCTAVE_INSTALL_SM_INT_OPS (TYPE) \
@@ -1146,7 +1155,8 @@
   OCTAVE_INSTALL_RE_INT_ASSIGN_OPS (TYPE) \
   OCTAVE_INSTALL_FLT_RE_INT_ASSIGN_OPS (TYPE) \
   OCTAVE_INSTALL_CX_INT_ASSIGN_OPS (TYPE) \
-  OCTAVE_INSTALL_FLT_CX_INT_ASSIGN_OPS (TYPE)
+  OCTAVE_INSTALL_FLT_CX_INT_ASSIGN_OPS (TYPE) \
+  OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS(TYPE)
 
 #define OCTAVE_INSTALL_SM_INT_ASSIGNCONV(TLHS, TRHS) \
   INSTALL_ASSIGNCONV (octave_ ## TLHS ## _scalar, octave_ ## TRHS ## _scalar, octave_ ## TLHS ## _matrix) \
--- a/src/OPERATORS/op-m-m.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-m-m.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -31,6 +31,7 @@
 #include "ov-re-mat.h"
 #include "ov-flt-re-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -130,6 +131,8 @@
 DEFNDASSIGNOP_FN (assign, matrix, matrix, array, assign)
 DEFNDASSIGNOP_FN (sgl_assign, float_matrix, matrix, float_array, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, matrix, delete_elements)
+
 CONVDECL (matrix_to_float_matrix)
 {
   CAST_CONV_ARG (const octave_matrix&);
@@ -177,6 +180,10 @@
   INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_matrix, assign);
   INSTALL_ASSIGNOP (op_asn_eq, octave_float_matrix, octave_matrix, sgl_assign);
 
+  INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_matrix, octave_null_sq_str, null_assign);
+
   INSTALL_CONVOP (octave_matrix, octave_float_matrix, matrix_to_float_matrix);
 }
 
--- a/src/OPERATORS/op-range.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-range.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -38,6 +38,7 @@
 #include "ov-bool.h"
 #include "ov-bool-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 
 // range unary ops.
@@ -82,6 +83,13 @@
   return new octave_float_matrix (FloatNDArray (v.array_value ()));
 }
 
+CONVDECL (range_to_matrix)
+{
+  CAST_CONV_ARG (const octave_range&);
+
+  return new octave_matrix (v.array_value ());
+}
+
 void
 install_range_ops (void)
 {
@@ -108,6 +116,17 @@
   INSTALL_CATOP (octave_char_matrix, octave_range, chm_r);
 
   INSTALL_CONVOP (octave_range, octave_float_matrix, range_to_float_matrix);
+
+  // FIXME: this would be unneccessary if octave_base_value::numeric_assign always tried converting
+  // lhs before rhs.
+  
+  INSTALL_ASSIGNCONV (octave_range, octave_null_matrix, octave_matrix);
+  INSTALL_ASSIGNCONV (octave_range, octave_null_str, octave_matrix);
+  INSTALL_ASSIGNCONV (octave_range, octave_null_sq_str, octave_matrix);
+
+  // However, this should probably be here just in case we need it.
+  
+  INSTALL_WIDENOP (octave_range, octave_matrix, range_to_matrix);
 }
 
 /*
--- a/src/OPERATORS/op-s-s.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-s-s.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -33,6 +33,7 @@
 #include "ov-re-mat.h"
 #include "ov-flt-re-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -163,6 +164,10 @@
   INSTALL_ASSIGNCONV (octave_scalar, octave_scalar, octave_matrix);
   INSTALL_ASSIGNCONV (octave_float_scalar, octave_scalar, octave_float_matrix);
 
+  INSTALL_ASSIGNCONV (octave_scalar, octave_null_matrix, octave_matrix);
+  INSTALL_ASSIGNCONV (octave_scalar, octave_null_str, octave_matrix);
+  INSTALL_ASSIGNCONV (octave_scalar, octave_null_sq_str, octave_matrix);
+
   INSTALL_CONVOP (octave_scalar, octave_float_matrix, scalar_to_float);
 }
 
--- a/src/OPERATORS/op-scm-scm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-scm-scm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -29,6 +29,7 @@
 #include "oct-obj.h"
 #include "ov.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 
 #include "sparse-xdiv.h"
@@ -179,6 +180,8 @@
 
 DEFASSIGNOP_FN (assign, sparse_complex_matrix, sparse_complex_matrix, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, sparse_complex_matrix, delete_elements)
+
 void
 install_scm_scm_ops (void)
 {
@@ -235,6 +238,13 @@
 
   INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, 
 		    octave_sparse_complex_matrix, assign);
+
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, 
+                    octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, 
+                    octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_complex_matrix, 
+                    octave_null_sq_str, null_assign);
 }
 
 /*
--- a/src/OPERATORS/op-sm-sm.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-sm-sm.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -30,6 +30,7 @@
 #include "ov.h"
 #include "ov-typeinfo.h"
 #include "ov-re-mat.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 
 #include "sparse-xpow.h"
@@ -148,6 +149,8 @@
 
 DEFASSIGNOP_FN (assign, sparse_matrix, sparse_matrix, assign)
 
+DEFNULLASSIGNOP_FN (null_assign, sparse_matrix, delete_elements)
+
 void
 install_sm_sm_ops (void)
 {
@@ -186,6 +189,10 @@
 
   INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_sparse_matrix, 
 		    assign);
+
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_sparse_matrix, octave_null_sq_str, null_assign);
 }
 
 /*
--- a/src/OPERATORS/op-str-str.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-str-str.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -30,6 +30,7 @@
 #include "ov.h"
 #include "ov-str-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 
 // string unary ops.
@@ -92,6 +93,8 @@
   return octave_value ();
 }
 
+DEFNULLASSIGNOP_FN (null_assign, char_matrix_str, delete_elements)
+
 DEFNDCHARCATOP_FN (str_str, char_matrix_str, char_matrix_str, concat)
 
 void
@@ -142,6 +145,14 @@
   INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_char_matrix_sq_str, assign);
   INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_char_matrix_str, assign);
   INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_char_matrix_sq_str, assign);
+
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_str, octave_null_sq_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_matrix, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_str, null_assign);
+  INSTALL_ASSIGNOP (op_asn_eq, octave_char_matrix_sq_str, octave_null_sq_str, null_assign);
+
 }
 
 /*
--- a/src/OPERATORS/op-ui16-ui16.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-ui16-ui16.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/OPERATORS/op-ui32-ui32.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-ui32-ui32.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/OPERATORS/op-ui64-ui64.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-ui64-ui64.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
@@ -135,6 +136,8 @@
 OCTAVE_MM_INT_ASSIGN_OPS (mmui32, uint64_, uint32_, uint32_)
 OCTAVE_MM_INT_ASSIGN_OPS (mmi64, uint64_, int64_, int64_)
 
+OCTAVE_INT_NULL_ASSIGN_OPS (uint64)
+
 OCTAVE_MIXED_INT_CMP_OPS (uint64, int8)
 OCTAVE_MIXED_INT_CMP_OPS (uint64, uint8)
 OCTAVE_MIXED_INT_CMP_OPS (uint64, int16)
@@ -200,6 +203,8 @@
   OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmui32, uint64_, uint32_);
   OCTAVE_INSTALL_MM_INT_ASSIGN_OPS (mmi64, uint64_, int64_);
 
+  OCTAVE_INSTALL_INT_NULL_ASSIGN_OPS (uint64)
+
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, int8);
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, uint8);
   OCTAVE_INSTALL_SM_INT_ASSIGNCONV (uint64, int16);
--- a/src/OPERATORS/op-ui8-ui8.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/OPERATORS/op-ui8-ui8.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -77,6 +77,7 @@
 #include "ov-cx-mat.h"
 #include "ov-flt-cx-mat.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 #include "ops.h"
 #include "xdiv.h"
 #include "xpow.h"
--- a/src/oct-obj.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/oct-obj.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -237,6 +237,14 @@
   return argv;
 }
 
+void
+octave_value_list::normalize_null_values (void)
+{
+  octave_idx_type len = length ();
+  for (octave_idx_type i = 0; i < len; i++)
+    data[i].make_non_null_value ();
+}
+
 /*
 ;;; Local Variables: ***
 ;;; mode: C++ ***
--- a/src/oct-obj.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/oct-obj.h	Fri Sep 26 11:52:01 2008 -0400
@@ -121,6 +121,8 @@
 
   string_vector name_tags (void) const { return names; }
 
+  void normalize_null_values (void);
+
 private:
 
   static octave_allocator allocator;
--- a/src/ops.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ops.h	Fri Sep 26 11:52:01 2008 -0400
@@ -152,6 +152,12 @@
 			 const octave_value_list& idx, \
 			 const octave_base_value& a2)
 
+#define NULLASSIGNOPDECL(name) \
+  static octave_value \
+  oct_assignop_ ## name (octave_base_value& a, \
+			 const octave_value_list& idx, \
+			 const octave_base_value&)
+
 #define ASSIGNANYOPDECL(name) \
   static octave_value \
   oct_assignop_ ## name (octave_base_value& a1, \
@@ -170,6 +176,15 @@
     return octave_value (); \
   }
 
+#define DEFNULLASSIGNOP_FN(name, t, f) \
+  NULLASSIGNOPDECL (name) \
+  { \
+    CAST_UNOP_ARG (octave_ ## t&); \
+ \
+    v.f (idx); \
+    return octave_value (); \
+  }
+
 #define DEFNDASSIGNOP_FN(name, t1, t2, e, f) \
   ASSIGNOPDECL (name) \
   { \
--- a/src/ov-base-mat.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-base-mat.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -206,6 +206,23 @@
 }
 
 template <class MT>
+void
+octave_base_matrix<MT>::delete_elements (const octave_value_list& idx)
+{
+  octave_idx_type len = idx.length ();
+
+  Array<idx_vector> ra_idx (len);
+
+  for (octave_idx_type i = 0; i < len; i++)
+    ra_idx(i) = idx(i).index_vector ();
+
+  matrix.maybe_delete_elements (ra_idx, MT::resize_fill_value ());
+
+  // Invalidate the matrix type
+  typ.invalidate_type ();
+}
+
+template <class MT>
 octave_value
 octave_base_matrix<MT>::resize (const dim_vector& dv, bool fill) const
 {
--- a/src/ov-base-mat.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-base-mat.h	Fri Sep 26 11:52:01 2008 -0400
@@ -88,6 +88,8 @@
 
   void assign (const octave_value_list& idx, const MT& rhs);
 
+  void delete_elements (const octave_value_list& idx);
+
   dim_vector dims (void) const { return matrix.dims (); }
 
   octave_idx_type nnz (void) const { return matrix.nnz (); }
--- a/src/ov-base-sparse.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-base-sparse.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -196,6 +196,23 @@
   typ.invalidate_type ();
 }
 
+template <class MT>
+void
+octave_base_sparse<MT>::delete_elements (const octave_value_list& idx)
+{
+  octave_idx_type len = idx.length ();
+
+  Array<idx_vector> ra_idx (len);
+
+  for (octave_idx_type i = 0; i < len; i++)
+    ra_idx(i) = idx(i).index_vector ();
+
+  matrix.maybe_delete_elements (ra_idx);
+
+  // Invalidate the matrix type
+  typ.invalidate_type ();
+}
+
 template <class T>
 octave_value 
 octave_base_sparse<T>::resize (const dim_vector& dv, bool) const
--- a/src/ov-base-sparse.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-base-sparse.h	Fri Sep 26 11:52:01 2008 -0400
@@ -97,6 +97,8 @@
 
   void assign (const octave_value_list& idx, const T& rhs);
 
+  void delete_elements (const octave_value_list& idx);
+
   dim_vector dims (void) const { return matrix.dims (); }
 
   octave_value do_index_op (const octave_value_list& idx,
--- a/src/ov-base.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-base.h	Fri Sep 26 11:52:01 2008 -0400
@@ -286,6 +286,8 @@
 
   virtual bool is_true (void) const { return false; }
 
+  virtual bool is_null_value (void) const { return false; }
+
   virtual bool is_constant (void) const { return false; }
 
   virtual bool is_function_handle (void) const { return false; }
--- a/src/ov-builtin.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-builtin.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -105,6 +105,9 @@
       try
 	{
 	  retval = (*f) (args, nargout);
+          // Do not allow null values to be returned from functions.
+          // FIXME: perhaps true builtins should be allowed?
+          retval.normalize_null_values ();
 	}
       catch (octave_execution_exception)
 	{
--- a/src/ov-cell.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-cell.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -230,8 +230,8 @@
 	    if (t_rhs.is_cell ())
 	      octave_base_matrix<Cell>::assign (i, t_rhs.cell_value ());
 	    else
-	      if (t_rhs.is_empty ())
-		octave_base_matrix<Cell>::assign (i, Cell());
+	      if (t_rhs.is_null_value ())
+		octave_base_matrix<Cell>::delete_elements (i);
 	      else
 		octave_base_matrix<Cell>::assign (i, Cell (t_rhs));
 
@@ -263,7 +263,8 @@
 		octave_base_matrix<Cell>::assign (i, tmp_cell);
 	      }
 	    else
-	      octave_base_matrix<Cell>::assign (i, Cell (t_rhs));
+              // Regularize a null matrix if stored into a struct component.
+	      octave_base_matrix<Cell>::assign (i, Cell (t_rhs.non_null_value ()));
 
 	    if (! error_state)
 	      {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ov-null-mat.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -0,0 +1,111 @@
+/*
+
+Copyright (C) 2008 Jaroslav Hajek
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "ov-null-mat.h"
+#include "ops.h"
+#include "defun.h"
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_matrix, "null_matrix", "double");
+
+const octave_value octave_null_matrix::instance (new octave_null_matrix ());
+
+static octave_base_value *
+default_null_matrix_numeric_conversion_function (const octave_base_value& a)
+{
+  CAST_CONV_ARG (const octave_null_matrix&);
+
+  return a.empty_clone ();
+}
+
+octave_base_value::type_conv_fcn
+octave_null_matrix::numeric_conversion_function (void) const
+{
+  return default_null_matrix_numeric_conversion_function;
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_str, "null_string", "char");
+
+const octave_value octave_null_str::instance (new octave_null_str ());
+
+static octave_base_value *
+default_null_str_numeric_conversion_function (const octave_base_value& a)
+{
+  CAST_CONV_ARG (const octave_null_str&);
+
+  return a.empty_clone ();
+}
+
+octave_base_value::type_conv_fcn
+octave_null_str::numeric_conversion_function (void) const
+{
+  return default_null_str_numeric_conversion_function;
+}
+
+DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA (octave_null_sq_str, "null_sq_string", "char");
+
+const octave_value octave_null_sq_str::instance (new octave_null_sq_str ());
+
+static octave_base_value *
+default_null_sq_str_numeric_conversion_function (const octave_base_value& a)
+{
+  CAST_CONV_ARG (const octave_null_sq_str&);
+
+  return a.empty_clone ();
+}
+
+octave_base_value::type_conv_fcn
+octave_null_sq_str::numeric_conversion_function (void) const
+{
+  return default_null_sq_str_numeric_conversion_function;
+}
+
+DEFUN (isnull, args, ,
+  "-*- texinfo -*-\n\
+@deftypefn {Built-in Function} {} isnull (@var{x})\n\
+Return 1 if @var{x} is a special null matrix, string or single quoted string.\n\
+Indexed assignment with such a value as right-hand side should delete array elements.\n\
+This function should be used when overloading indexed assignment for user-defined \n\
+classes instead of @code{isempty}, to distinguish the cases:\n\
+@table @asis\n\
+@item @code{A(I) = []}\n\
+This should delete elements if @code{I} is nonempty.\n\
+@item @code{X = []; A(I) = X}\n\
+This should give an error if @code{I} is nonempty.\n\
+@end table\n\
+@end deftypefn")
+{
+  octave_value retval;
+
+  int nargin = args.length ();
+
+  if (nargin == 1 && args(0).is_defined ())
+    retval = args(0).is_null_value ();
+  else
+    print_usage ();
+
+  return retval;
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/ov-null-mat.h	Fri Sep 26 11:52:01 2008 -0400
@@ -0,0 +1,100 @@
+/*
+
+Copyright (C) 2008 Jaroslav Hajek
+
+This file is part of Octave.
+
+Octave is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+Octave is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<http://www.gnu.org/licenses/>.
+
+*/
+
+#if !defined (octave_null_matrix_h)
+#define octave_null_matrix_h 1
+
+#include "ov.h"
+#include "ov-re-mat.h"
+#include "ov-str-mat.h"
+
+// Design rationale:
+// The constructors are hidden. There is only one null matrix (or null string) object,
+// that can have shallow copies. Cloning the object returns just a normal empty matrix,
+// so all the shallow copies are, in fact, read-only. This conveniently ensures that any
+// attempt to fiddle with the null matrix destroys its special status.
+
+// The special [] value.
+
+class
+OCTINTERP_API
+octave_null_matrix : public octave_matrix
+{
+  octave_null_matrix (void) : octave_matrix () { }
+
+public:
+
+  static const octave_value instance;
+
+  bool is_null_value (void) const { return true; }
+
+  type_conv_fcn numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+// The special "" value
+
+class 
+OCTINTERP_API
+octave_null_str : public octave_char_matrix_str
+{
+  octave_null_str (void) : octave_char_matrix_str () { }
+
+public:
+
+  static const octave_value instance;
+
+  bool is_null_value (void) const { return true; }
+
+  type_conv_fcn numeric_conversion_function (void) const;
+
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+// The special '' value
+
+class 
+OCTINTERP_API
+octave_null_sq_str : public octave_char_matrix_sq_str
+{
+  octave_null_sq_str (void) : octave_char_matrix_sq_str () { }
+
+public:
+
+  static const octave_value instance;
+
+  bool is_null_value (void) const { return true; }
+
+  type_conv_fcn numeric_conversion_function (void) const;
+
+private:
+
+  DECLARE_OV_TYPEID_FUNCTIONS_AND_DATA
+};
+
+#endif
--- a/src/ov-struct.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-struct.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -344,7 +344,7 @@
 		  }
 		else
 		  {
-		    if (t_rhs.is_empty()) 
+		    if (t_rhs.is_null_value()) 
 		      {
 			map.maybe_delete_elements (idx.front());
 
@@ -385,7 +385,8 @@
 		map.assign (key, tmp_cell);
 	      }
 	    else
-	      map.assign (key, t_rhs);
+              // Regularize a null matrix if stored into a struct component.
+	      map.assign (key, t_rhs.non_null_value ());
 
 	    if (! error_state)
 	      {
--- a/src/ov-type-conv.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov-type-conv.h	Fri Sep 26 11:52:01 2008 -0400
@@ -20,6 +20,56 @@
 
 */
 
+static 
+octave_value
+octave_type_conv_body (const octave_value &arg, const std::string& name, int t_result)
+{
+  int t_arg = arg.type_id ();
+  octave_value retval;
+
+  if (t_arg == t_result || arg.class_name () == name)
+    {
+      retval = arg;
+    }
+  else
+    {
+      octave_base_value::type_conv_fcn cf
+        = octave_value_typeinfo::lookup_type_conv_op (t_arg, t_result);
+       
+      if (cf)
+        {
+          octave_base_value *tmp (cf (*(arg.internal_rep ())));
+
+          if (tmp)
+            {
+              retval = octave_value (tmp);
+
+              retval.maybe_mutate ();
+            }
+        }
+      else
+        {
+          octave_base_value::type_conv_fcn cf
+            = arg.numeric_conversion_function ();
+
+          if (cf)
+            {
+              octave_base_value *tmp (cf (*(arg.internal_rep ())));
+
+              if (tmp)
+                {
+                  octave_value xarg (tmp);
+
+                  retval = octave_type_conv_body (xarg, name, t_result);
+                }
+            }
+        }
+    }
+
+  return retval;
+}
+                         
+
 #define OCTAVE_TYPE_CONV_BODY3(NAME, MATRIX_RESULT_T, SCALAR_RESULT_T) \
  \
   octave_value retval; \
@@ -30,41 +80,19 @@
     { \
       const octave_value arg = args(0); \
  \
-      int t_arg = arg.type_id (); \
- \
       int t_result = MATRIX_RESULT_T::static_type_id (); \
  \
-      if (t_arg == t_result || arg.class_name () == #NAME) \
-	{ \
-	  retval = arg; \
-	} \
-      else \
+      retval = octave_type_conv_body (arg, #NAME, t_result); \
+      if (retval.is_undefined ()) \
         { \
-          octave_base_value::type_conv_fcn cf \
-	    = octave_value_typeinfo::lookup_type_conv_op (t_arg, t_result); \
- \
-          if (cf) \
-	    { \
-	      octave_base_value *tmp (cf (*(arg.internal_rep ()))); \
+          std::string arg_tname = arg.type_name (); \
  \
-	      if (tmp) \
-		{ \
-		  retval = octave_value (tmp); \
+          std::string result_tname = arg.numel () == 1 \
+            ? SCALAR_RESULT_T::static_type_name () \
+            : MATRIX_RESULT_T::static_type_name (); \
  \
-		  retval.maybe_mutate (); \
-		} \
-	    } \
-	  else \
-	    { \
-	      std::string arg_tname = arg.type_name (); \
- \
-	      std::string result_tname = arg.numel () == 1 \
-		? SCALAR_RESULT_T::static_type_name () \
-		: MATRIX_RESULT_T::static_type_name (); \
- \
-	      gripe_invalid_conversion (arg_tname, result_tname); \
-	    } \
-	} \
+          gripe_invalid_conversion (arg_tname, result_tname); \
+        } \
     } \
   else \
     print_usage (); \
--- a/src/ov.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -69,6 +69,7 @@
 #include "ov-fcn-handle.h"
 #include "ov-fcn-inline.h"
 #include "ov-typeinfo.h"
+#include "ov-null-mat.h"
 
 #include "defun.h"
 #include "error.h"
@@ -1153,7 +1154,8 @@
 octave_value::assign (assign_op op, const octave_value& rhs)
 {
   if (op == op_asn_eq)
-    operator = (rhs);
+    // Regularize a null matrix if stored into a variable.
+    operator = (rhs.non_null_value ());
   else
     {
       // FIXME -- only do the following stuff if we can't find
@@ -1516,6 +1518,28 @@
                                              type_name (), "complex vector"));
 }
 
+
+octave_value 
+octave_value::non_null_value (void) const
+{
+  if (is_null_value ())
+    return octave_value (rep->empty_clone ());
+  else
+    return *this;
+}
+
+void 
+octave_value::make_non_null_value (void) 
+{
+  if (is_null_value ())
+    {
+      octave_base_value *rc = rep->empty_clone ();
+      if (--rep->count == 0)
+        delete rep;
+      rep = rc;
+    }
+}
+
 int
 octave_value::write (octave_stream& os, int block_size,
 		     oct_data_conv::data_type output_type, int skip,
@@ -2397,6 +2421,9 @@
   octave_float_complex::register_type ();
   octave_float_matrix::register_type ();
   octave_float_complex_matrix::register_type ();
+  octave_null_matrix::register_type ();
+  octave_null_str::register_type ();
+  octave_null_sq_str::register_type ();
 }
 
 #if 0
--- a/src/ov.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/ov.h	Fri Sep 26 11:52:01 2008 -0400
@@ -489,6 +489,9 @@
   bool is_magic_colon (void) const
     { return rep->is_magic_colon (); }
 
+  bool is_null_value (void) const
+    { return rep->is_null_value (); }
+
   // Are any or all of the elements in this constant nonzero?
 
   octave_value all (int dim = 0) const
@@ -835,6 +838,14 @@
   Array<FloatComplex> float_complex_vector_value (bool frc_str_conv = false,
 				       bool frc_vec_conv = false) const;
 
+  // Make a copy that is not a special null matrix
+
+  octave_value non_null_value (void) const;
+
+  // Ditto, but in place.
+
+  void make_non_null_value (void);
+
   // Conversions.  These should probably be private.  If a user of this
   // class wants a certain kind of constant, he should simply ask for
   // it, and we should convert it if possible.
--- a/src/parse.y	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/parse.y	Fri Sep 26 11:52:01 2008 -0400
@@ -65,6 +65,7 @@
 #include "oct-map.h"
 #include "ov-fcn-handle.h"
 #include "ov-usr-fcn.h"
+#include "ov-null-mat.h"
 #include "toplev.h"
 #include "pager.h"
 #include "parse.h"
@@ -577,13 +578,19 @@
 
 matrix		: '[' ']'
 		  {
-		    $$ = new tree_constant (octave_value (Matrix ()));
+		    $$ = new tree_constant (octave_null_matrix::instance);
 		    lexer_flags.looking_at_matrix_or_assign_lhs = false;
 		    lexer_flags.pending_local_variables.clear ();
 		  }
 		| '[' ';' ']'
 		  {
-		    $$ = new tree_constant (octave_value (Matrix ()));
+		    $$ = new tree_constant (octave_null_matrix::instance);
+		    lexer_flags.looking_at_matrix_or_assign_lhs = false;
+		    lexer_flags.pending_local_variables.clear ();
+		  }
+		| '[' ',' ']'
+		  {
+		    $$ = new tree_constant (octave_null_matrix::instance);
 		    lexer_flags.looking_at_matrix_or_assign_lhs = false;
 		    lexer_flags.pending_local_variables.clear ();
 		  }
@@ -1721,9 +1728,17 @@
       {
 	std::string txt = tok_val->text ();
 
-	char delim = op == DQ_STRING ? '"' : '\'';
-
-	octave_value tmp (txt, delim);
+        char delim = op == DQ_STRING ? '"' : '\'';
+        octave_value tmp (txt, delim);
+
+        if (txt.empty ())
+          {
+            if (op == DQ_STRING)
+              tmp = octave_null_str::instance;
+            else
+              tmp = octave_null_sq_str::instance;
+          }
+
 	retval = new tree_constant (tmp, l, c);
 
 	if (op == DQ_STRING)
--- a/src/pt-decl.h	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/pt-decl.h	Fri Sep 26 11:52:01 2008 -0400
@@ -65,7 +65,8 @@
 
   bool lvalue_ok (void) { return id ? id->lvalue_ok () : false; }
 
-  octave_value rvalue (void) { return id ? id->rvalue () : octave_value (); }
+  // Do not allow functions return null values
+  octave_value rvalue (void) { return id ? id->rvalue ().non_null_value () : octave_value (); }
 
   octave_value_list rvalue (int nargout)
   {
--- a/src/pt-misc.cc	Thu Sep 25 13:44:51 2008 -0400
+++ b/src/pt-misc.cc	Fri Sep 26 11:52:01 2008 -0400
@@ -179,7 +179,7 @@
 		}
 	    }
 	  else
-	    ref.assign (octave_value::op_asn_eq, args(i));
+	    ref.define (args(i));
 	}
       else
 	elt->eval ();