diff libinterp/octave-value/ov-fcn-handle.cc @ 31607:aac27ad79be6 stable

maint: Re-indent code after switch to using namespace macros. * build-env.h, build-env.in.cc, Cell.h, __betainc__.cc, __eigs__.cc, __ftp__.cc, __ichol__.cc, __ilu__.cc, __isprimelarge__.cc, __magick_read__.cc, __pchip_deriv__.cc, amd.cc, base-text-renderer.cc, base-text-renderer.h, besselj.cc, bitfcns.cc, bsxfun.cc, c-file-ptr-stream.h, call-stack.cc, call-stack.h, ccolamd.cc, cellfun.cc, chol.cc, colamd.cc, dasrt.cc, data.cc, debug.cc, defaults.cc, defaults.h, det.cc, display.cc, display.h, dlmread.cc, dynamic-ld.cc, dynamic-ld.h, ellipj.cc, environment.cc, environment.h, error.cc, error.h, errwarn.h, event-manager.cc, event-manager.h, event-queue.cc, event-queue.h, fcn-info.cc, fcn-info.h, fft.cc, fft2.cc, file-io.cc, filter.cc, find.cc, ft-text-renderer.cc, ft-text-renderer.h, gcd.cc, gl-render.cc, gl-render.h, gl2ps-print.cc, gl2ps-print.h, graphics-toolkit.cc, graphics-toolkit.h, graphics.cc, gsvd.cc, gtk-manager.cc, gtk-manager.h, help.cc, help.h, hook-fcn.cc, hook-fcn.h, input.cc, input.h, interpreter-private.cc, interpreter-private.h, interpreter.cc, interpreter.h, inv.cc, jsondecode.cc, jsonencode.cc, latex-text-renderer.cc, latex-text-renderer.h, load-path.cc, load-path.h, load-save.cc, load-save.h, lookup.cc, ls-hdf5.cc, ls-mat4.cc, ls-mat5.cc, lsode.cc, lu.cc, mappers.cc, matrix_type.cc, max.cc, mex.cc, mexproto.h, mxarray.h, mxtypes.in.h, oct-errno.in.cc, oct-hdf5-types.cc, oct-hist.cc, oct-hist.h, oct-map.cc, oct-map.h, oct-opengl.h, oct-prcstrm.h, oct-process.cc, oct-process.h, oct-stdstrm.h, oct-stream.cc, oct-stream.h, oct-strstrm.h, octave-default-image.h, ordqz.cc, ordschur.cc, pager.cc, pager.h, pinv.cc, pow2.cc, pr-output.cc, psi.cc, qr.cc, quadcc.cc, rand.cc, regexp.cc, settings.cc, settings.h, sighandlers.cc, sighandlers.h, sparse-xpow.cc, sqrtm.cc, stack-frame.cc, stack-frame.h, stream-euler.cc, strfns.cc, svd.cc, syminfo.cc, syminfo.h, symrcm.cc, symrec.cc, symrec.h, symscope.cc, symscope.h, symtab.cc, symtab.h, sysdep.cc, sysdep.h, text-engine.cc, text-engine.h, text-renderer.cc, text-renderer.h, time.cc, toplev.cc, typecast.cc, url-handle-manager.cc, url-handle-manager.h, urlwrite.cc, utils.cc, utils.h, variables.cc, variables.h, xdiv.cc, __delaunayn__.cc, __init_fltk__.cc, __init_gnuplot__.cc, __ode15__.cc, __voronoi__.cc, audioread.cc, convhulln.cc, gzip.cc, cdef-class.cc, cdef-class.h, cdef-fwd.h, cdef-manager.cc, cdef-manager.h, cdef-method.cc, cdef-method.h, cdef-object.cc, cdef-object.h, cdef-package.cc, cdef-package.h, cdef-property.cc, cdef-property.h, cdef-utils.cc, cdef-utils.h, ov-base-diag.cc, ov-base-int.cc, ov-base-mat.cc, ov-base-mat.h, ov-base-scalar.cc, ov-base.cc, ov-base.h, ov-bool-mat.cc, ov-bool-mat.h, ov-bool-sparse.cc, ov-bool.cc, ov-builtin.h, ov-cell.cc, ov-ch-mat.cc, ov-class.cc, ov-class.h, ov-classdef.cc, ov-classdef.h, ov-complex.cc, ov-cx-diag.cc, ov-cx-mat.cc, ov-cx-sparse.cc, ov-dld-fcn.cc, ov-dld-fcn.h, ov-fcn-handle.cc, ov-fcn-handle.h, ov-fcn.h, ov-float.cc, ov-flt-complex.cc, ov-flt-cx-diag.cc, ov-flt-cx-mat.cc, ov-flt-re-diag.cc, ov-flt-re-mat.cc, ov-flt-re-mat.h, ov-intx.h, ov-java.cc, ov-lazy-idx.cc, ov-legacy-range.cc, ov-magic-int.cc, ov-mex-fcn.cc, ov-mex-fcn.h, ov-null-mat.cc, ov-perm.cc, ov-range.cc, ov-re-diag.cc, ov-re-mat.cc, ov-re-mat.h, ov-re-sparse.cc, ov-scalar.cc, ov-str-mat.cc, ov-struct.cc, ov-typeinfo.cc, ov-typeinfo.h, ov-usr-fcn.cc, ov-usr-fcn.h, ov.cc, ov.h, ovl.h, octave.cc, octave.h, op-b-sbm.cc, op-bm-sbm.cc, op-cs-scm.cc, op-fm-fcm.cc, op-fs-fcm.cc, op-s-scm.cc, op-scm-cs.cc, op-scm-s.cc, op-sm-cs.cc, ops.h, anon-fcn-validator.cc, anon-fcn-validator.h, bp-table.cc, bp-table.h, comment-list.cc, comment-list.h, filepos.h, lex.h, oct-lvalue.cc, oct-lvalue.h, parse.h, profiler.cc, profiler.h, pt-anon-scopes.cc, pt-anon-scopes.h, pt-arg-list.cc, pt-arg-list.h, pt-args-block.cc, pt-args-block.h, pt-array-list.cc, pt-array-list.h, pt-assign.cc, pt-assign.h, pt-binop.cc, pt-binop.h, pt-bp.cc, pt-bp.h, pt-cbinop.cc, pt-cbinop.h, pt-cell.cc, pt-cell.h, pt-check.cc, pt-check.h, pt-classdef.cc, pt-classdef.h, pt-cmd.h, pt-colon.cc, pt-colon.h, pt-const.cc, pt-const.h, pt-decl.cc, pt-decl.h, pt-eval.cc, pt-eval.h, pt-except.cc, pt-except.h, pt-exp.cc, pt-exp.h, pt-fcn-handle.cc, pt-fcn-handle.h, pt-id.cc, pt-id.h, pt-idx.cc, pt-idx.h, pt-jump.h, pt-loop.cc, pt-loop.h, pt-mat.cc, pt-mat.h, pt-misc.cc, pt-misc.h, pt-pr-code.cc, pt-pr-code.h, pt-select.cc, pt-select.h, pt-spmd.cc, pt-spmd.h, pt-stmt.cc, pt-stmt.h, pt-tm-const.cc, pt-tm-const.h, pt-unop.cc, pt-unop.h, pt-walk.cc, pt-walk.h, pt.cc, pt.h, token.cc, token.h, Range.cc, Range.h, idx-vector.cc, idx-vector.h, range-fwd.h, CollocWt.cc, CollocWt.h, aepbalance.cc, aepbalance.h, chol.cc, chol.h, gepbalance.cc, gepbalance.h, gsvd.cc, gsvd.h, hess.cc, hess.h, lo-mappers.cc, lo-mappers.h, lo-specfun.cc, lo-specfun.h, lu.cc, lu.h, oct-convn.cc, oct-convn.h, oct-fftw.cc, oct-fftw.h, oct-norm.cc, oct-norm.h, oct-rand.cc, oct-rand.h, oct-spparms.cc, oct-spparms.h, qr.cc, qr.h, qrp.cc, qrp.h, randgamma.cc, randgamma.h, randmtzig.cc, randmtzig.h, randpoisson.cc, randpoisson.h, schur.cc, schur.h, sparse-chol.cc, sparse-chol.h, sparse-lu.cc, sparse-lu.h, sparse-qr.cc, sparse-qr.h, svd.cc, svd.h, child-list.cc, child-list.h, dir-ops.cc, dir-ops.h, file-ops.cc, file-ops.h, file-stat.cc, file-stat.h, lo-sysdep.cc, lo-sysdep.h, lo-sysinfo.cc, lo-sysinfo.h, mach-info.cc, mach-info.h, oct-env.cc, oct-env.h, oct-group.cc, oct-group.h, oct-password.cc, oct-password.h, oct-syscalls.cc, oct-syscalls.h, oct-time.cc, oct-time.h, oct-uname.cc, oct-uname.h, action-container.cc, action-container.h, base-list.h, cmd-edit.cc, cmd-edit.h, cmd-hist.cc, cmd-hist.h, f77-fcn.h, file-info.cc, file-info.h, lo-array-errwarn.cc, lo-array-errwarn.h, lo-hash.cc, lo-hash.h, lo-ieee.h, lo-regexp.cc, lo-regexp.h, lo-utils.cc, lo-utils.h, oct-base64.cc, oct-base64.h, oct-glob.cc, oct-glob.h, oct-inttypes.h, oct-mutex.cc, oct-mutex.h, oct-refcount.h, oct-shlib.cc, oct-shlib.h, oct-sparse.cc, oct-sparse.h, oct-string.h, octave-preserve-stream-state.h, pathsearch.cc, pathsearch.h, quit.cc, quit.h, unwind-prot.cc, unwind-prot.h, url-transfer.cc, url-transfer.h: Re-indent code after switch to using namespace macros.
author Rik <rik@octave.org>
date Thu, 01 Dec 2022 18:02:15 -0800
parents e88a07dec498
children 597f3ee61a48
line wrap: on
line diff
--- a/libinterp/octave-value/ov-fcn-handle.cc	Thu Dec 01 14:23:45 2022 -0800
+++ b/libinterp/octave-value/ov-fcn-handle.cc	Thu Dec 01 18:02:15 2022 -0800
@@ -86,1049 +86,433 @@
 
 OCTAVE_BEGIN_NAMESPACE(octave)
 
-  class invalid_fcn_handle : public base_fcn_handle
-  {
-  public:
-
-    invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { }
-
-    invalid_fcn_handle (const invalid_fcn_handle&) = default;
-
-    ~invalid_fcn_handle (void) = default;
-
-    invalid_fcn_handle * clone (void) const
-    {
-      return new invalid_fcn_handle (*this);
-    }
-
-    std::string type (void) const { return "<invalid>"; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-  };
-
-  // Create a handle to an unnamed internal function.  There will be no
-  // way to save and reload it.  See, for example, the F__fltk_check__
-  // function in __init_fltk__.cc.
-
-  class internal_fcn_handle : public base_fcn_handle
+class invalid_fcn_handle : public base_fcn_handle
+{
+public:
+
+  invalid_fcn_handle (void) : base_fcn_handle ("<invalid>") { }
+
+  invalid_fcn_handle (const invalid_fcn_handle&) = default;
+
+  ~invalid_fcn_handle (void) = default;
+
+  invalid_fcn_handle * clone (void) const
   {
-  public:
-
-    internal_fcn_handle (const octave_value& fcn)
-      : base_fcn_handle ("<internal>"), m_fcn (fcn)
-    { }
-
-    internal_fcn_handle (const internal_fcn_handle&) = default;
-
-    ~internal_fcn_handle (void) = default;
-
-    internal_fcn_handle * clone (void) const
-    {
-      return new internal_fcn_handle (*this);
-    }
-
-    std::string type (void) const { return "<internal>"; }
-
-    bool is_internal (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool = false)
-    {
-      return m_fcn.function_value ();
-    }
-
-    octave_user_function * user_function_value (bool = false)
-    {
-      return m_fcn.user_function_value ();
-    }
-
-    octave_value fcn_val (void) { return m_fcn; }
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    friend bool is_equal_to (const internal_fcn_handle& fh1,
-                             const internal_fcn_handle& fh2);
-
-  private:
-
-    octave_value m_fcn;
-  };
-
-  class simple_fcn_handle : public base_fcn_handle
+    return new invalid_fcn_handle (*this);
+  }
+
+  std::string type (void) const { return "<invalid>"; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+};
+
+// Create a handle to an unnamed internal function.  There will be no
+// way to save and reload it.  See, for example, the F__fltk_check__
+// function in __init_fltk__.cc.
+
+class internal_fcn_handle : public base_fcn_handle
+{
+public:
+
+  internal_fcn_handle (const octave_value& fcn)
+    : base_fcn_handle ("<internal>"), m_fcn (fcn)
+  { }
+
+  internal_fcn_handle (const internal_fcn_handle&) = default;
+
+  ~internal_fcn_handle (void) = default;
+
+  internal_fcn_handle * clone (void) const
   {
-  public:
-
-    // FIXME: octaveroot is temporary information used when loading
-    // handles.  Can we avoid using it in the constructor?
-
-    simple_fcn_handle (const std::string& name = "",
-                       const std::string& file = "",
-                       const std::string& /*octaveroot*/ = "")
-      : base_fcn_handle (name, file), m_fcn ()
-    { }
-
-    simple_fcn_handle (const octave_value& fcn, const std::string& name)
-      : base_fcn_handle (name), m_fcn (fcn)
-    {
-      if (m_fcn.is_defined ())
-        {
-          octave_function *oct_fcn = m_fcn.function_value ();
-
-          if (oct_fcn)
-            m_file = oct_fcn->fcn_file_name ();
-        }
-    }
-
-    simple_fcn_handle (const simple_fcn_handle&) = default;
-
-    ~simple_fcn_handle (void) = default;
-
-    simple_fcn_handle * clone (void) const
-    {
-      return new simple_fcn_handle (*this);
-    }
-
-    std::string type (void) const { return "simple"; }
-
-    bool is_simple (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool);
-
-    octave_user_function * user_function_value (bool);
-
-    octave_value fcn_val (void);
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    bool save_ascii (std::ostream& os);
-
-    bool load_ascii (std::istream& is);
-
-    bool save_binary (std::ostream& os, bool save_as_floats);
-
-    bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
-
-    bool save_hdf5 (octave_hdf5_id loc_hid, const char *name,
-                    bool save_as_floats);
-
-    bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
-                    octave_hdf5_id& type_hid);
-
-    void print_raw (std::ostream& os, bool pr_as_read_syntax,
-                    int current_print_indent_level) const;
-
-    friend bool is_equal_to (const simple_fcn_handle& fh1,
-                             const simple_fcn_handle& fh2);
-
-  private:
-
-    octave_value m_fcn;
-  };
-
-  class scoped_fcn_handle : public base_fcn_handle
+    return new internal_fcn_handle (*this);
+  }
+
+  std::string type (void) const { return "<internal>"; }
+
+  bool is_internal (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false)
+  {
+    return m_fcn.function_value ();
+  }
+
+  octave_user_function * user_function_value (bool = false)
   {
-  public:
-
-    // FIXME: octaveroot is temporary information used when loading
-    // handles.  Can we avoid using it in the constructor?
-
-    scoped_fcn_handle (const std::string& name = "",
-                       const std::string& file = "",
-                       const std::string& /*octaveroot*/ = "")
-      : base_fcn_handle (name, file)
-    { }
-
-    scoped_fcn_handle (const octave_value& fcn, const std::string& name,
-                       const std::list<std::string>& parentage);
-
-    scoped_fcn_handle (const scoped_fcn_handle&) = default;
-
-    ~scoped_fcn_handle (void) = default;
-
-    scoped_fcn_handle * clone (void) const
-    {
-      return new scoped_fcn_handle (*this);
-    }
-
-    std::string type (void) const { return "scopedfunction"; }
-
-    bool is_scoped (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool = false)
-    {
-      return m_fcn.function_value ();
-    }
-
-    octave_user_function * user_function_value (bool = false)
-    {
-      return m_fcn.user_function_value ();
-    }
-
-    octave_value fcn_val (void) { return m_fcn; }
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    bool save_ascii (std::ostream& os);
-
-    bool load_ascii (std::istream& is);
-
-    bool save_binary (std::ostream& os, bool save_as_floats);
-
-    bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
-
-    bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                    bool save_as_floats);
-
-    bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
-                    octave_hdf5_id& type_hid);
-
-    void print_raw (std::ostream&, bool pr_as_read_syntax,
-                    int current_print_indent_level) const;
-
-    friend bool is_equal_to (const scoped_fcn_handle& fh1,
-                             const scoped_fcn_handle& fh2);
-
-  protected:
-
-    void find_function (void);
-
-    // The function we are handling.
-    octave_value m_fcn;
-
-    // List of parent function names.  The first element is the name of
-    // m_fcn.
-    std::list<std::string> m_parentage;
-  };
-
-  class base_nested_fcn_handle : public base_fcn_handle
+    return m_fcn.user_function_value ();
+  }
+
+  octave_value fcn_val (void) { return m_fcn; }
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  friend bool is_equal_to (const internal_fcn_handle& fh1,
+                           const internal_fcn_handle& fh2);
+
+private:
+
+  octave_value m_fcn;
+};
+
+class simple_fcn_handle : public base_fcn_handle
+{
+public:
+
+  // FIXME: octaveroot is temporary information used when loading
+  // handles.  Can we avoid using it in the constructor?
+
+  simple_fcn_handle (const std::string& name = "",
+                     const std::string& file = "",
+                     const std::string& /*octaveroot*/ = "")
+    : base_fcn_handle (name, file), m_fcn ()
+  { }
+
+  simple_fcn_handle (const octave_value& fcn, const std::string& name)
+    : base_fcn_handle (name), m_fcn (fcn)
   {
-  public:
-
-    // FIXME: octaveroot is temporary information used when loading
-    // handles.  Can we avoid using it in the constructor?
-
-    base_nested_fcn_handle (const std::string& name = "",
-                            const std::string& file = "",
-                            const std::string& /*octaveroot*/ = "")
-      : base_fcn_handle (name, file)
-    { }
-
-    base_nested_fcn_handle (const octave_value& fcn, const std::string& name)
-      : base_fcn_handle (name), m_fcn (fcn)
-    { }
-
-    std::string type (void) const { return "nested"; }
-
-    using base_fcn_handle::is_nested;
-
-    bool is_nested (void) const { return true; }
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool = false)
-    {
-      return m_fcn.function_value ();
-    }
-
-    octave_user_function * user_function_value (bool = false)
-    {
-      return m_fcn.user_function_value ();
-    }
-
-    octave_value fcn_val (void) { return m_fcn; }
-
-    virtual octave_value workspace (void) const = 0;
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    bool save_ascii (std::ostream& os);
-
-    bool load_ascii (std::istream& is);
-
-    bool save_binary (std::ostream& os, bool save_as_floats);
-
-    bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
-
-    bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                    bool save_as_floats);
-
-    bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
-                    octave_hdf5_id& type_hid);
-
-    void print_raw (std::ostream&, bool pr_as_read_syntax,
-                    int current_print_indent_level) const;
-
-  protected:
-
-    // The function we are handling.
-    octave_value m_fcn;
-  };
-
-  class nested_fcn_handle : public base_nested_fcn_handle
-  {
-  public:
-
-    // FIXME: octaveroot is temporary information used when loading
-    // handles.  Can we avoid using it in the constructor?
-
-    nested_fcn_handle (const std::string& name = "",
-                       const std::string& file = "",
-                       const std::string& octaveroot = "")
-      : base_nested_fcn_handle (name, file, octaveroot)
-    { }
-
-    nested_fcn_handle (const octave_value& fcn, const std::string& name,
-                       const std::shared_ptr<stack_frame>& stack_context)
-      : base_nested_fcn_handle (fcn, name), m_stack_context (stack_context)
-    {
-      if (m_stack_context)
-        m_stack_context->mark_closure_context ();
-    }
-
-    nested_fcn_handle (const nested_fcn_handle&) = default;
-
-    ~nested_fcn_handle (void) = default;
-
-    using base_nested_fcn_handle::is_nested;
-
-    bool is_nested (const std::shared_ptr<stack_frame>& frame) const
-    {
-      return frame == m_stack_context;
-    }
-
-    nested_fcn_handle * clone (void) const
-    {
-      return new nested_fcn_handle (*this);
-    }
-
-    octave_value make_weak_nested_handle (void) const;
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    octave_value workspace (void) const;
-
-    friend bool is_equal_to (const nested_fcn_handle& fh1,
-                             const nested_fcn_handle& fh2);
-
-    std::shared_ptr<stack_frame> stack_context (void) const
-    {
-      return m_stack_context;
-    }
-
-  protected:
-
-    // Pointer to closure stack frames.
-    std::shared_ptr<stack_frame> m_stack_context;
-  };
-
-  class weak_nested_fcn_handle : public base_nested_fcn_handle
+    if (m_fcn.is_defined ())
+      {
+        octave_function *oct_fcn = m_fcn.function_value ();
+
+        if (oct_fcn)
+          m_file = oct_fcn->fcn_file_name ();
+      }
+  }
+
+  simple_fcn_handle (const simple_fcn_handle&) = default;
+
+  ~simple_fcn_handle (void) = default;
+
+  simple_fcn_handle * clone (void) const
   {
-  public:
-
-    weak_nested_fcn_handle (const nested_fcn_handle& nfh)
-      : base_nested_fcn_handle (nfh), m_stack_context (nfh.stack_context ())
-    { }
-
-    weak_nested_fcn_handle (const weak_nested_fcn_handle&) = default;
-
-    ~weak_nested_fcn_handle (void) = default;
-
-    weak_nested_fcn_handle * clone (void) const
-    {
-      return new weak_nested_fcn_handle (*this);
-    }
-
-    bool is_weak_nested (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    octave_value workspace (void) const;
-
-    friend bool is_equal_to (const weak_nested_fcn_handle& fh1,
-                             const weak_nested_fcn_handle& fh2);
-
-  protected:
-
-    // Pointer to closure stack frames.
-    std::weak_ptr<stack_frame> m_stack_context;
-  };
-
-  class class_simple_fcn_handle : public base_fcn_handle
+    return new simple_fcn_handle (*this);
+  }
+
+  std::string type (void) const { return "simple"; }
+
+  bool is_simple (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool);
+
+  octave_user_function * user_function_value (bool);
+
+  octave_value fcn_val (void);
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_hid, const char *name,
+                  bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
+                  octave_hdf5_id& type_hid);
+
+  void print_raw (std::ostream& os, bool pr_as_read_syntax,
+                  int current_print_indent_level) const;
+
+  friend bool is_equal_to (const simple_fcn_handle& fh1,
+                           const simple_fcn_handle& fh2);
+
+private:
+
+  octave_value m_fcn;
+};
+
+class scoped_fcn_handle : public base_fcn_handle
+{
+public:
+
+  // FIXME: octaveroot is temporary information used when loading
+  // handles.  Can we avoid using it in the constructor?
+
+  scoped_fcn_handle (const std::string& name = "",
+                     const std::string& file = "",
+                     const std::string& /*octaveroot*/ = "")
+    : base_fcn_handle (name, file)
+  { }
+
+  scoped_fcn_handle (const octave_value& fcn, const std::string& name,
+                     const std::list<std::string>& parentage);
+
+  scoped_fcn_handle (const scoped_fcn_handle&) = default;
+
+  ~scoped_fcn_handle (void) = default;
+
+  scoped_fcn_handle * clone (void) const
   {
-  public:
-
-    // FIXME: octaveroot is temporary information used when loading
-    // handles.  Can we avoid using it in the constructor?
-
-    class_simple_fcn_handle (const std::string& name,
-                             const std::string& file,
-                             const std::string& /*octaveroot*/)
-      : base_fcn_handle (name, file)
-    { }
-
-    // FIXME: is the method name supposed to be just the method name or
-    // also contain the object name?
-
-    class_simple_fcn_handle (const std::string& class_nm,
-                             const std::string& meth_nm);
-
-    class_simple_fcn_handle (const octave_value& fcn,
-                             const std::string& class_nm,
-                             const std::string& meth_nm);
-
-    class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn,
-                             const std::string& class_nm,
-                             const std::string& meth_nm);
-
-    class_simple_fcn_handle (const class_simple_fcn_handle&) = default;
-
-    ~class_simple_fcn_handle (void) = default;
-
-    class_simple_fcn_handle * clone (void) const
-    {
-      return new class_simple_fcn_handle (*this);
-    }
-
-    std::string type (void) const { return "classsimple"; }
-
-    bool is_class_simple (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool = false)
-    {
-      // FIXME: Shouldn't the lookup rules here match those used in the
-      // call method?
-
-      if (m_fcn.is_defined ())
-        return m_fcn.function_value ();
-
-      symbol_table& symtab = __get_symbol_table__ ();
-
-      // FIXME: is caching the correct thing to do?
-      // Cache this value so that the pointer will be valid as long as the
-      // function handle object is valid.
-
-      // FIXME: This should probably dispatch to the respective class method.
-      // But that breaks if a function handle is used in a class method with
-      // e.g. bsxfun with arguments of a different class (see bug #59661).
-      // m_fcn = symtab.find_method (m_name, m_dispatch_class);
-      m_fcn = symtab.find_function (m_name, octave_value_list ());
-
-      return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
-    }
-
-    octave_user_function * user_function_value (bool = false)
-    {
-      return m_fcn.user_function_value ();
-    }
-
-    octave_value fcn_val (void) { return m_fcn; }
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    std::string dispatch_class (void) const { return m_dispatch_class; }
-
-    bool save_ascii (std::ostream& os);
-
-    bool load_ascii (std::istream& is);
-
-    bool save_binary (std::ostream& os, bool save_as_floats);
-
-    bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
-
-    bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                    bool save_as_floats);
-
-    bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
-                    octave_hdf5_id& type_hid);
-
-    void print_raw (std::ostream&, bool pr_as_read_syntax,
-                    int current_print_indent_level) const;
-
-    friend bool is_equal_to (const class_simple_fcn_handle& fh1,
-                             const class_simple_fcn_handle& fh2);
-
-  protected:
-
-    // The object containing the method we are handing.
-    octave_value m_obj;
-
-    // The method we are handling.
-    octave_value m_fcn;
-
-    // Name of the class that m_fcn belongs to.
-    std::string m_dispatch_class;
-  };
-
-  // Handles to anonymous functions are similar to handles to nested
-  // functions.  If they are created in a context that contains nested
-  // functions, then they store a link to the parent call stack frames
-  // that are active when they are created.  These call stack frames
-  // (closure frames) provide access to variables needed by any nested
-  // functions that are called from the anonymous function.  Anonymous
-  // functions also store a list of values from their parent scope
-  // corresponding to the symbols in the anonymous function.  This list
-  // of values captures the variable values that are visible in the
-  // scope where they are created.
-  //
-  // Note that because handles to anonymous and nested functions capture
-  // call stack frames when they are created, they will cause deletion
-  // of the values in those frames to be deferred until the handles to
-  // the anonymous or nested functions are deleted.
-  //
-  // Would it be possible to avoid storing the closure frames for
-  // handles to anonymous functions if we can determine that the
-  // anonymous function has no unbound variables (or parameters, which
-  // could be handles to nested functions?) or if it is not created in a
-  // context that contains nested functions?
-  //
-  // Would it be possible to define anonymous functions as a special
-  // type of nested function object that also has an variable
-  // initialization list associated with it?
-
-  class base_anonymous_fcn_handle : public base_fcn_handle
+    return new scoped_fcn_handle (*this);
+  }
+
+  std::string type (void) const { return "scopedfunction"; }
+
+  bool is_scoped (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false)
+  {
+    return m_fcn.function_value ();
+  }
+
+  octave_user_function * user_function_value (bool = false)
   {
-  public:
-
-    static const std::string anonymous;
-
-    // Setting NAME here is a bit of a kluge to cope with a bad choice
-    // made to append the number of local variables to the @<anonymous>
-    // tag in the binary file format.  See also the save_binary and
-    // load_binary functions.
-
-    base_anonymous_fcn_handle (const std::string& name = "")
-      : base_fcn_handle (name)
-    { }
-
-    base_anonymous_fcn_handle (const octave_value& fcn,
-                               const stack_frame::local_vars_map& local_vars)
-      : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars)
-    { }
-
-    base_anonymous_fcn_handle (const base_anonymous_fcn_handle&) = default;
-
-    ~base_anonymous_fcn_handle (void) = default;
-
-    std::string type (void) const { return "anonymous"; }
-
-    bool is_anonymous (void) const { return true; }
-
-    // FIXME: These must go away.  They don't do the right thing for
-    // scoping or overloads.
-    octave_function * function_value (bool = false)
-    {
-      return m_fcn.function_value ();
-    }
-
-    octave_user_function * user_function_value (bool = false)
-    {
-      return m_fcn.user_function_value ();
-    }
-
-    octave_value fcn_val (void) { return m_fcn; }
-
-    virtual octave_value workspace (void) const = 0;
-
-    // Should be const.
-    octave_scalar_map info (void);
-
-    bool save_ascii (std::ostream& os);
-
-    bool load_ascii (std::istream& is);
-
-    bool save_binary (std::ostream& os, bool save_as_floats);
-
-    bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
-
-    bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                    bool save_as_floats);
-
-    bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
-                    octave_hdf5_id& type_hid);
-
-    void print_raw (std::ostream&, bool pr_as_read_syntax,
-                    int current_print_indent_level) const;
-
-    // Anonymous function handles are printed without a newline.
-    bool print_as_scalar (void) const { return false; }
-
-    bool parse (const std::string& fcn_text);
-
-  protected:
-
-    // The function we are handling.
-    octave_value m_fcn;
-
-    // List of captured variable values for anonymous fucntions.
-    stack_frame::local_vars_map m_local_vars;
-  };
-
-  class anonymous_fcn_handle : public base_anonymous_fcn_handle
-  {
-  public:
-
-    using base_anonymous_fcn_handle::anonymous;
-
-    // Setting NAME here is a bit of a kluge to cope with a bad choice
-    // made to append the number of local variables to the @<anonymous>
-    // tag in the binary file format.  See also the save_binary and
-    // load_binary functions.
-
-    anonymous_fcn_handle (const std::string& name = "")
-      : base_anonymous_fcn_handle (name), m_stack_context ()
-    { }
-
-    anonymous_fcn_handle (const octave_value& fcn,
-                          const stack_frame::local_vars_map& local_vars,
-                          const std::shared_ptr<stack_frame>& stack_context = std::shared_ptr<stack_frame> ());
-
-    anonymous_fcn_handle (const anonymous_fcn_handle&) = default;
-
-    ~anonymous_fcn_handle (void) = default;
-
-    anonymous_fcn_handle * clone (void) const
-    {
-      return new anonymous_fcn_handle (*this);
-    }
-
-    octave_value make_weak_anonymous_handle (void) const;
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    octave_value workspace (void) const;
-
-    friend bool is_equal_to (const anonymous_fcn_handle& fh1,
-                             const anonymous_fcn_handle& fh2);
-
-    std::shared_ptr<stack_frame> stack_context (void) const
-    {
-      return m_stack_context;
-    }
-
-  protected:
-
-    // Pointer to closure stack frames.
-    std::shared_ptr<stack_frame> m_stack_context;
-  };
-
-  class weak_anonymous_fcn_handle : public base_anonymous_fcn_handle
+    return m_fcn.user_function_value ();
+  }
+
+  octave_value fcn_val (void) { return m_fcn; }
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                  bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
+                  octave_hdf5_id& type_hid);
+
+  void print_raw (std::ostream&, bool pr_as_read_syntax,
+                  int current_print_indent_level) const;
+
+  friend bool is_equal_to (const scoped_fcn_handle& fh1,
+                           const scoped_fcn_handle& fh2);
+
+protected:
+
+  void find_function (void);
+
+  // The function we are handling.
+  octave_value m_fcn;
+
+  // List of parent function names.  The first element is the name of
+  // m_fcn.
+  std::list<std::string> m_parentage;
+};
+
+class base_nested_fcn_handle : public base_fcn_handle
+{
+public:
+
+  // FIXME: octaveroot is temporary information used when loading
+  // handles.  Can we avoid using it in the constructor?
+
+  base_nested_fcn_handle (const std::string& name = "",
+                          const std::string& file = "",
+                          const std::string& /*octaveroot*/ = "")
+    : base_fcn_handle (name, file)
+  { }
+
+  base_nested_fcn_handle (const octave_value& fcn, const std::string& name)
+    : base_fcn_handle (name), m_fcn (fcn)
+  { }
+
+  std::string type (void) const { return "nested"; }
+
+  using base_fcn_handle::is_nested;
+
+  bool is_nested (void) const { return true; }
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false)
   {
-  public:
-
-    using base_anonymous_fcn_handle::anonymous;
-
-    weak_anonymous_fcn_handle (const anonymous_fcn_handle& afh)
-      : base_anonymous_fcn_handle (afh), m_stack_context (afh.stack_context ())
-    { }
-
-    weak_anonymous_fcn_handle (const weak_anonymous_fcn_handle&) = default;
-
-    ~weak_anonymous_fcn_handle (void) = default;
-
-    weak_anonymous_fcn_handle * clone (void) const
-    {
-      return new weak_anonymous_fcn_handle (*this);
-    }
-
-    bool is_weak_anonymous (void) const { return true; }
-
-    octave_value_list call (int nargout, const octave_value_list& args);
-
-    octave_value workspace (void) const;
-
-    friend bool is_equal_to (const weak_anonymous_fcn_handle& fh1,
-                             const weak_anonymous_fcn_handle& fh2);
-
-  protected:
-
-    // Pointer to closure stack frames.
-    std::weak_ptr<stack_frame> m_stack_context;
-  };
-
-  extern bool is_equal_to (const anonymous_fcn_handle& fh1,
-                           const anonymous_fcn_handle& fh2);
-
-  static void err_invalid_fcn_handle (const std::string& name)
-  {
-    error ("invalid function handle, unable to find function for @%s",
-           name.c_str ());
-  }
-
-  octave_value base_fcn_handle::make_weak_nested_handle (void) const
-  {
-    std::string type_str = type ();
-    error ("invalid conversion from %s handle to weak nestead handle",
-           type_str.c_str ());
-  }
-
-  octave_value base_fcn_handle::make_weak_anonymous_handle (void) const
-  {
-    std::string type_str = type ();
-    error ("invalid conversion from %s handle to weak anonymous handle",
-           type_str.c_str ());
+    return m_fcn.function_value ();
   }
 
-  octave_value_list
-  base_fcn_handle::subsref (const std::string& type,
-                            const std::list<octave_value_list>& idx,
-                            int nargout)
-  {
-    octave_value_list retval;
-
-    switch (type[0])
-      {
-      case '(':
-        {
-          int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
-
-          retval = call (tmp_nargout, idx.front ());
-        }
-        break;
-
-      case '{':
-      case '.':
-        error ("function handle cannot be indexed with %c", type[0]);
-
-      default:
-        panic_impossible ();
-      }
-
-    // FIXME: perhaps there should be an
-    // octave_value_list::next_subsref member function?  See also
-    // octave_builtin::subsref.
-
-    if (idx.size () > 1)
-      retval = retval(0).next_subsref (nargout, type, idx);
-
-    return retval;
-  }
-
-  octave_value
-  base_fcn_handle::convert_to_str_internal (bool, bool, char type) const
-  {
-    std::ostringstream buf;
-    print_raw (buf, true, 0);
-    return octave_value (buf.str (), type);
-  }
-
-  bool
-  base_fcn_handle::save_ascii (std::ostream&)
-  {
-    unimplemented ("save", "text");
-
-    return true;
-  }
-
-  bool
-  base_fcn_handle::load_ascii (std::istream&)
-  {
-    unimplemented ("load", "text");
-
-    return true;
-  }
-
-  bool
-  base_fcn_handle::save_binary (std::ostream&, bool)
-  {
-    unimplemented ("save", "binary");
-
-    return true;
-  }
-
-  bool
-  base_fcn_handle::load_binary (std::istream&, bool, mach_info::float_format)
-  {
-    unimplemented ("load", "binary");
-
-    return true;
-  }
-
-  bool
-  base_fcn_handle::save_hdf5 (octave_hdf5_id, const char *, bool)
+  octave_user_function * user_function_value (bool = false)
   {
-    unimplemented ("save", "hdf5");
-
-    return true;
-  }
-
-  bool
-  base_fcn_handle::load_hdf5 (octave_hdf5_id&, octave_hdf5_id&, octave_hdf5_id&)
-  {
-    unimplemented ("load", "hdf5");
-
-    return true;
+    return m_fcn.user_function_value ();
   }
 
-  void base_fcn_handle::warn_load (const char *file_type) const
-  {
-    std::string obj_type = type ();
-
-    warning_with_id
-      ("Octave:load-save-unavailable",
-       "%s: loading %s files not available in this version of Octave",
-       obj_type.c_str (), file_type);
-  }
-
-  void base_fcn_handle::warn_save (const char *file_type) const
-  {
-    std::string obj_type = type ();
-
-    warning_with_id
-      ("Octave:load-save-unavailable",
-       "%s: saving %s files not available in this version of Octave",
-       obj_type.c_str (), file_type);
-  }
-
-  void base_fcn_handle::unimplemented (const char *op, const char *fmt) const
+  octave_value fcn_val (void) { return m_fcn; }
+
+  virtual octave_value workspace (void) const = 0;
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                  bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
+                  octave_hdf5_id& type_hid);
+
+  void print_raw (std::ostream&, bool pr_as_read_syntax,
+                  int current_print_indent_level) const;
+
+protected:
+
+  // The function we are handling.
+  octave_value m_fcn;
+};
+
+class nested_fcn_handle : public base_nested_fcn_handle
+{
+public:
+
+  // FIXME: octaveroot is temporary information used when loading
+  // handles.  Can we avoid using it in the constructor?
+
+  nested_fcn_handle (const std::string& name = "",
+                     const std::string& file = "",
+                     const std::string& octaveroot = "")
+    : base_nested_fcn_handle (name, file, octaveroot)
+  { }
+
+  nested_fcn_handle (const octave_value& fcn, const std::string& name,
+                     const std::shared_ptr<stack_frame>& stack_context)
+    : base_nested_fcn_handle (fcn, name), m_stack_context (stack_context)
   {
-    std::string htype = type ();
-
-    warning ("%s for %s handles with %s format is not implemented",
-             op, htype.c_str (), fmt);
-  }
-
-  octave_value_list
-  invalid_fcn_handle::call (int, const octave_value_list&)
-  {
-    error ("invalid call to invalid function handle");
+    if (m_stack_context)
+      m_stack_context->mark_closure_context ();
   }
 
-  octave_value_list
-  internal_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    interpreter& interp = __get_interpreter__ ();
-
-    return interp.feval (m_fcn, args, nargout);
-  }
-
-  octave_scalar_map internal_fcn_handle::info (void)
+  nested_fcn_handle (const nested_fcn_handle&) = default;
+
+  ~nested_fcn_handle (void) = default;
+
+  using base_nested_fcn_handle::is_nested;
+
+  bool is_nested (const std::shared_ptr<stack_frame>& frame) const
   {
-    octave_scalar_map m;
-
-    m.setfield ("function", fcn_name ());
-    m.setfield ("type", type ());
-    m.setfield ("file", "");
-
-    return m;
+    return frame == m_stack_context;
+  }
+
+  nested_fcn_handle * clone (void) const
+  {
+    return new nested_fcn_handle (*this);
   }
 
-  bool is_equal_to (const internal_fcn_handle& fh1,
-                    const internal_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  octave_value_list
-  simple_fcn_handle::call (int nargout, const octave_value_list& args)
+  octave_value make_weak_nested_handle (void) const;
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  octave_value workspace (void) const;
+
+  friend bool is_equal_to (const nested_fcn_handle& fh1,
+                           const nested_fcn_handle& fh2);
+
+  std::shared_ptr<stack_frame> stack_context (void) const
   {
-    // FIXME: if m_name has a '.' in the name, lookup first component.  If
-    // it is a classdef meta object, then build TYPE and IDX arguments and
-    // make a subsref call using them.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    octave_value fcn_to_call;
-
-    // The following code is similar to part of
-    // tree_evaluator::visit_index_expression but simpler because it
-    // handles a more restricted case.
-
-    symbol_table& symtab = interp.get_symbol_table ();
-
-    std::size_t pos = m_name.find ('.');
-
-    if (pos != std::string::npos)
-      {
-        // FIXME: check to see which of these cases actually work in
-        // Octave and Matlab.  For the last two, assume handle is
-        // created before object is defined as an object.
-        //
-        // We can have one of
-        //
-        //   pkg-list . fcn  (args)
-        //   pkg-list . cls . meth (args)
-        //   class-name . method  (args)
-        //   class-name . static-method  (args)
-        //   object . method  (args)
-        //   object . static-method  (args)
-
-        // Evaluate package elements until we find a function,
-        // classdef object, or classdef_meta object that is not a
-        // package.  An object may only appear as the first element,
-        // then it must be followed directly by a function name.
-
-        std::size_t beg = 0;
-        std::size_t end = pos;
-
-        std::vector<std::string> idx_elts;
-
-        while (true)
-          {
-            end = m_name.find ('.', beg);
-
-            idx_elts.push_back (m_name.substr (beg, end-beg));
-
-            if (end == std::string::npos)
-              break;
-
-            beg = end+1;
-          }
-
-        std::size_t n_elts = idx_elts.size ();
-
-        bool have_object = false;
-        octave_value partial_expr_val;
-
-        // Lazy evaluation.  The first element was not known to be defined
-        // as an object in the scope where the handle was created.  See if
-        // there is a definition in the current scope.
-
-        partial_expr_val = interp.varval (idx_elts[0]);
-
-        if (partial_expr_val.is_defined ())
-          {
-            if (! partial_expr_val.is_classdef_object () || n_elts != 2)
-              err_invalid_fcn_handle (m_name);
-
-            have_object = true;
-          }
-        else
-          partial_expr_val = symtab.find_function (idx_elts[0], ovl ());
-
-        std::string type;
-        std::list<octave_value_list> arg_list;
-
-        for (std::size_t i = 1; i < n_elts; i++)
-          {
-            if (partial_expr_val.is_package ())
-              {
-                if (have_object)
-                  err_invalid_fcn_handle (m_name);
-
-                type = ".";
-                arg_list.push_back (ovl (idx_elts[i]));
-
-                try
-                  {
-                    // Silently ignore extra output values.
-
-                    octave_value_list tmp_list
-                      = partial_expr_val.subsref (type, arg_list, 0);
-
-                    partial_expr_val
-                      = tmp_list.length () ? tmp_list(0) : octave_value ();
-
-                    if (partial_expr_val.is_cs_list ())
-                      err_invalid_fcn_handle (m_name);
-
-                    arg_list.clear ();
-                  }
-                catch (const index_exception&)
-                  {
-                    err_invalid_fcn_handle (m_name);
-                  }
-              }
-            else if (have_object || partial_expr_val.is_classdef_meta ())
-              {
-                // Object or class name must be the next to the last
-                // element (it was the previous one, so if this is the
-                // final element, it should be a classdef method,
-                // but we'll let the classdef or classdef_meta subsref
-                // function sort that out.
-
-                if (i != n_elts-1)
-                  err_invalid_fcn_handle (m_name);
-
-                type = ".(";
-                arg_list.push_back (ovl (idx_elts[i]));
-                arg_list.push_back (args);
-
-                return partial_expr_val.subsref (type, arg_list, nargout);
-              }
-            else
-              err_invalid_fcn_handle (m_name);
-          }
-
-        // If we get here, we must have a function to call.
-
-        if (! partial_expr_val.is_function ())
-          err_invalid_fcn_handle (m_name);
-
-        fcn_to_call = partial_expr_val;
-      }
-    else
-      {
-        // No "." in the name.
-
-        // Perform function lookup given current arguments.  We'll need
-        // to do this regardless of whether a function was found when
-        // the handle was created.
-
-        octave_value ov_fcn = symtab.find_function (m_name, args);
-
-        if (m_fcn.is_defined ())
-          {
-            // A simple function was found when the handle was created.
-            // Use that unless we find a class method to override it.
-
-            fcn_to_call = m_fcn;
-
-            if (ov_fcn.is_defined ())
-              {
-                octave_function *fcn = ov_fcn.function_value ();
-
-                std::string dispatch_class = fcn->dispatch_class ();
-
-                if (fcn->is_class_method ())
-                  {
-                    // Function found through lookup is a class method
-                    // so use it instead of the simple one found when
-                    // the handle was created.
-
-                    fcn_to_call = ov_fcn;
-                  }
-              }
-          }
-        else
-          {
-            // There was no simple function found when the handle was
-            // created so use the one found here (if any).
-
-            fcn_to_call = ov_fcn;
-          }
-      }
-
-    if (! fcn_to_call.is_defined ())
-      err_invalid_fcn_handle (m_name);
-
-    return interp.feval (fcn_to_call, args, nargout);
+    return m_stack_context;
+  }
+
+protected:
+
+  // Pointer to closure stack frames.
+  std::shared_ptr<stack_frame> m_stack_context;
+};
+
+class weak_nested_fcn_handle : public base_nested_fcn_handle
+{
+public:
+
+  weak_nested_fcn_handle (const nested_fcn_handle& nfh)
+    : base_nested_fcn_handle (nfh), m_stack_context (nfh.stack_context ())
+  { }
+
+  weak_nested_fcn_handle (const weak_nested_fcn_handle&) = default;
+
+  ~weak_nested_fcn_handle (void) = default;
+
+  weak_nested_fcn_handle * clone (void) const
+  {
+    return new weak_nested_fcn_handle (*this);
   }
 
-  octave_function * simple_fcn_handle::function_value (bool)
+  bool is_weak_nested (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  octave_value workspace (void) const;
+
+  friend bool is_equal_to (const weak_nested_fcn_handle& fh1,
+                           const weak_nested_fcn_handle& fh2);
+
+protected:
+
+  // Pointer to closure stack frames.
+  std::weak_ptr<stack_frame> m_stack_context;
+};
+
+class class_simple_fcn_handle : public base_fcn_handle
+{
+public:
+
+  // FIXME: octaveroot is temporary information used when loading
+  // handles.  Can we avoid using it in the constructor?
+
+  class_simple_fcn_handle (const std::string& name,
+                           const std::string& file,
+                           const std::string& /*octaveroot*/)
+    : base_fcn_handle (name, file)
+  { }
+
+  // FIXME: is the method name supposed to be just the method name or
+  // also contain the object name?
+
+  class_simple_fcn_handle (const std::string& class_nm,
+                           const std::string& meth_nm);
+
+  class_simple_fcn_handle (const octave_value& fcn,
+                           const std::string& class_nm,
+                           const std::string& meth_nm);
+
+  class_simple_fcn_handle (const octave_value& obj, const octave_value& fcn,
+                           const std::string& class_nm,
+                           const std::string& meth_nm);
+
+  class_simple_fcn_handle (const class_simple_fcn_handle&) = default;
+
+  ~class_simple_fcn_handle (void) = default;
+
+  class_simple_fcn_handle * clone (void) const
+  {
+    return new class_simple_fcn_handle (*this);
+  }
+
+  std::string type (void) const { return "classsimple"; }
+
+  bool is_class_simple (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false)
   {
     // FIXME: Shouldn't the lookup rules here match those used in the
     // call method?
@@ -1142,1674 +526,2290 @@
     // Cache this value so that the pointer will be valid as long as the
     // function handle object is valid.
 
+    // FIXME: This should probably dispatch to the respective class method.
+    // But that breaks if a function handle is used in a class method with
+    // e.g. bsxfun with arguments of a different class (see bug #59661).
+    // m_fcn = symtab.find_method (m_name, m_dispatch_class);
     m_fcn = symtab.find_function (m_name, octave_value_list ());
 
     return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
   }
 
-  octave_user_function * simple_fcn_handle::user_function_value (bool)
+  octave_user_function * user_function_value (bool = false)
   {
-    // FIXME: Shouldn't the lookup rules here match those used in the
-    // call method?
-
-    if (m_fcn.is_defined ())
-      return m_fcn.user_function_value ();
-
-    symbol_table& symtab = __get_symbol_table__ ();
-
-    // FIXME: is caching the correct thing to do?
-    // Cache this value so that the pointer will be valid as long as the
-    // function handle object is valid.
-
-    m_fcn = symtab.find_user_function (m_name);
-
-    return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr;
+    return m_fcn.user_function_value ();
   }
 
-  octave_value simple_fcn_handle::fcn_val (void)
+  octave_value fcn_val (void) { return m_fcn; }
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  std::string dispatch_class (void) const { return m_dispatch_class; }
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                  bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
+                  octave_hdf5_id& type_hid);
+
+  void print_raw (std::ostream&, bool pr_as_read_syntax,
+                  int current_print_indent_level) const;
+
+  friend bool is_equal_to (const class_simple_fcn_handle& fh1,
+                           const class_simple_fcn_handle& fh2);
+
+protected:
+
+  // The object containing the method we are handing.
+  octave_value m_obj;
+
+  // The method we are handling.
+  octave_value m_fcn;
+
+  // Name of the class that m_fcn belongs to.
+  std::string m_dispatch_class;
+};
+
+// Handles to anonymous functions are similar to handles to nested
+// functions.  If they are created in a context that contains nested
+// functions, then they store a link to the parent call stack frames
+// that are active when they are created.  These call stack frames
+// (closure frames) provide access to variables needed by any nested
+// functions that are called from the anonymous function.  Anonymous
+// functions also store a list of values from their parent scope
+// corresponding to the symbols in the anonymous function.  This list
+// of values captures the variable values that are visible in the
+// scope where they are created.
+//
+// Note that because handles to anonymous and nested functions capture
+// call stack frames when they are created, they will cause deletion
+// of the values in those frames to be deferred until the handles to
+// the anonymous or nested functions are deleted.
+//
+// Would it be possible to avoid storing the closure frames for
+// handles to anonymous functions if we can determine that the
+// anonymous function has no unbound variables (or parameters, which
+// could be handles to nested functions?) or if it is not created in a
+// context that contains nested functions?
+//
+// Would it be possible to define anonymous functions as a special
+// type of nested function object that also has an variable
+// initialization list associated with it?
+
+class base_anonymous_fcn_handle : public base_fcn_handle
+{
+public:
+
+  static const std::string anonymous;
+
+  // Setting NAME here is a bit of a kluge to cope with a bad choice
+  // made to append the number of local variables to the @<anonymous>
+  // tag in the binary file format.  See also the save_binary and
+  // load_binary functions.
+
+  base_anonymous_fcn_handle (const std::string& name = "")
+    : base_fcn_handle (name)
+  { }
+
+  base_anonymous_fcn_handle (const octave_value& fcn,
+                             const stack_frame::local_vars_map& local_vars)
+    : base_fcn_handle (anonymous), m_fcn (fcn), m_local_vars (local_vars)
+  { }
+
+  base_anonymous_fcn_handle (const base_anonymous_fcn_handle&) = default;
+
+  ~base_anonymous_fcn_handle (void) = default;
+
+  std::string type (void) const { return "anonymous"; }
+
+  bool is_anonymous (void) const { return true; }
+
+  // FIXME: These must go away.  They don't do the right thing for
+  // scoping or overloads.
+  octave_function * function_value (bool = false)
   {
-    if (m_fcn.is_defined ())
-      return m_fcn;
-
-    symbol_table& symtab = __get_symbol_table__ ();
-
-    // FIXME: is caching the correct thing to do?
-    // Cache this value so that the pointer will be valid as long as the
-    // function handle object is valid.
-
-    m_fcn = symtab.find_user_function (m_name);
-
-    return m_fcn;
+    return m_fcn.function_value ();
+  }
+
+  octave_user_function * user_function_value (bool = false)
+  {
+    return m_fcn.user_function_value ();
   }
 
-  octave_scalar_map simple_fcn_handle::info (void)
+  octave_value fcn_val (void) { return m_fcn; }
+
+  virtual octave_value workspace (void) const = 0;
+
+  // Should be const.
+  octave_scalar_map info (void);
+
+  bool save_ascii (std::ostream& os);
+
+  bool load_ascii (std::istream& is);
+
+  bool save_binary (std::ostream& os, bool save_as_floats);
+
+  bool load_binary (std::istream& is, bool swap, mach_info::float_format fmt);
+
+  bool save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                  bool save_as_floats);
+
+  bool load_hdf5 (octave_hdf5_id& group_hid, octave_hdf5_id& space_hid,
+                  octave_hdf5_id& type_hid);
+
+  void print_raw (std::ostream&, bool pr_as_read_syntax,
+                  int current_print_indent_level) const;
+
+  // Anonymous function handles are printed without a newline.
+  bool print_as_scalar (void) const { return false; }
+
+  bool parse (const std::string& fcn_text);
+
+protected:
+
+  // The function we are handling.
+  octave_value m_fcn;
+
+  // List of captured variable values for anonymous fucntions.
+  stack_frame::local_vars_map m_local_vars;
+};
+
+class anonymous_fcn_handle : public base_anonymous_fcn_handle
+{
+public:
+
+  using base_anonymous_fcn_handle::anonymous;
+
+  // Setting NAME here is a bit of a kluge to cope with a bad choice
+  // made to append the number of local variables to the @<anonymous>
+  // tag in the binary file format.  See also the save_binary and
+  // load_binary functions.
+
+  anonymous_fcn_handle (const std::string& name = "")
+    : base_anonymous_fcn_handle (name), m_stack_context ()
+  { }
+
+  anonymous_fcn_handle (const octave_value& fcn,
+                        const stack_frame::local_vars_map& local_vars,
+                        const std::shared_ptr<stack_frame>& stack_context = std::shared_ptr<stack_frame> ());
+
+  anonymous_fcn_handle (const anonymous_fcn_handle&) = default;
+
+  ~anonymous_fcn_handle (void) = default;
+
+  anonymous_fcn_handle * clone (void) const
   {
-    octave_scalar_map m;
-
-    m.setfield ("function", fcn_name ());
-    m.setfield ("type", type ());
-    // When is FILE defined for simple function handles?
-    m.setfield ("file", file ());
-
-    return m;
+    return new anonymous_fcn_handle (*this);
+  }
+
+  octave_value make_weak_anonymous_handle (void) const;
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  octave_value workspace (void) const;
+
+  friend bool is_equal_to (const anonymous_fcn_handle& fh1,
+                           const anonymous_fcn_handle& fh2);
+
+  std::shared_ptr<stack_frame> stack_context (void) const
+  {
+    return m_stack_context;
   }
 
-  bool simple_fcn_handle::save_ascii (std::ostream& os)
+protected:
+
+  // Pointer to closure stack frames.
+  std::shared_ptr<stack_frame> m_stack_context;
+};
+
+class weak_anonymous_fcn_handle : public base_anonymous_fcn_handle
+{
+public:
+
+  using base_anonymous_fcn_handle::anonymous;
+
+  weak_anonymous_fcn_handle (const anonymous_fcn_handle& afh)
+    : base_anonymous_fcn_handle (afh), m_stack_context (afh.stack_context ())
+  { }
+
+  weak_anonymous_fcn_handle (const weak_anonymous_fcn_handle&) = default;
+
+  ~weak_anonymous_fcn_handle (void) = default;
+
+  weak_anonymous_fcn_handle * clone (void) const
   {
-    os << "# octaveroot: " << config::octave_exec_home () << "\n";
-
-    std::string fnm = file ();
-    if (! fnm.empty ())
-      os << "# path: " << fnm << "\n";
-
-    os << "# subtype: " << type () << "\n";
-
-    os << m_name << "\n";
-
-    return true;
-  }
-
-  bool simple_fcn_handle::load_ascii (std::istream& is)
-  {
-    // FIXME: If m_file is not empty, try to load the file and define
-    // the function?  Is it an error if that fails?  Or should this job
-    // always be deferred until the handle is used?
-
-    return is.good ();
+    return new weak_anonymous_fcn_handle (*this);
   }
 
-  bool simple_fcn_handle::save_binary (std::ostream& os, bool)
-  {
-    std::ostringstream nmbuf;
-
-    // When is FILE defined for simple function handles?
-    std::string fnm;
-
-    nmbuf << m_name << "@<simple>\n" << config::octave_exec_home ()
-          << "\n" << fnm;
-
-    std::string buf_str = nmbuf.str ();
-    int32_t tmp = buf_str.length ();
-    os.write (reinterpret_cast<char *> (&tmp), 4);
-    os.write (buf_str.c_str (), buf_str.length ());
-
-    return true;
-  }
-
-  bool simple_fcn_handle::load_binary (std::istream& is, bool,
-                                       mach_info::float_format)
-  {
-    return is.good ();
-  }
-
-  bool simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                                     bool)
-  {
+  bool is_weak_anonymous (void) const { return true; }
+
+  octave_value_list call (int nargout, const octave_value_list& args);
+
+  octave_value workspace (void) const;
+
+  friend bool is_equal_to (const weak_anonymous_fcn_handle& fh1,
+                           const weak_anonymous_fcn_handle& fh2);
+
+protected:
+
+  // Pointer to closure stack frames.
+  std::weak_ptr<stack_frame> m_stack_context;
+};
+
+extern bool is_equal_to (const anonymous_fcn_handle& fh1,
+                         const anonymous_fcn_handle& fh2);
+
+static void err_invalid_fcn_handle (const std::string& name)
+{
+  error ("invalid function handle, unable to find function for @%s",
+         name.c_str ());
+}
+
+octave_value base_fcn_handle::make_weak_nested_handle (void) const
+{
+  std::string type_str = type ();
+  error ("invalid conversion from %s handle to weak nestead handle",
+         type_str.c_str ());
+}
+
+octave_value base_fcn_handle::make_weak_anonymous_handle (void) const
+{
+  std::string type_str = type ();
+  error ("invalid conversion from %s handle to weak anonymous handle",
+         type_str.c_str ());
+}
+
+octave_value_list
+base_fcn_handle::subsref (const std::string& type,
+                          const std::list<octave_value_list>& idx,
+                          int nargout)
+{
+  octave_value_list retval;
+
+  switch (type[0])
+    {
+    case '(':
+      {
+        int tmp_nargout = (type.length () > 1 && nargout == 0) ? 1 : nargout;
+
+        retval = call (tmp_nargout, idx.front ());
+      }
+      break;
+
+    case '{':
+    case '.':
+      error ("function handle cannot be indexed with %c", type[0]);
+
+    default:
+      panic_impossible ();
+    }
+
+  // FIXME: perhaps there should be an
+  // octave_value_list::next_subsref member function?  See also
+  // octave_builtin::subsref.
+
+  if (idx.size () > 1)
+    retval = retval(0).next_subsref (nargout, type, idx);
+
+  return retval;
+}
+
+octave_value
+base_fcn_handle::convert_to_str_internal (bool, bool, char type) const
+{
+  std::ostringstream buf;
+  print_raw (buf, true, 0);
+  return octave_value (buf.str (), type);
+}
+
+bool
+base_fcn_handle::save_ascii (std::ostream&)
+{
+  unimplemented ("save", "text");
+
+  return true;
+}
+
+bool
+base_fcn_handle::load_ascii (std::istream&)
+{
+  unimplemented ("load", "text");
+
+  return true;
+}
+
+bool
+base_fcn_handle::save_binary (std::ostream&, bool)
+{
+  unimplemented ("save", "binary");
+
+  return true;
+}
+
+bool
+base_fcn_handle::load_binary (std::istream&, bool, mach_info::float_format)
+{
+  unimplemented ("load", "binary");
+
+  return true;
+}
+
+bool
+base_fcn_handle::save_hdf5 (octave_hdf5_id, const char *, bool)
+{
+  unimplemented ("save", "hdf5");
+
+  return true;
+}
+
+bool
+base_fcn_handle::load_hdf5 (octave_hdf5_id&, octave_hdf5_id&, octave_hdf5_id&)
+{
+  unimplemented ("load", "hdf5");
+
+  return true;
+}
+
+void base_fcn_handle::warn_load (const char *file_type) const
+{
+  std::string obj_type = type ();
+
+  warning_with_id
+  ("Octave:load-save-unavailable",
+   "%s: loading %s files not available in this version of Octave",
+   obj_type.c_str (), file_type);
+}
+
+void base_fcn_handle::warn_save (const char *file_type) const
+{
+  std::string obj_type = type ();
+
+  warning_with_id
+  ("Octave:load-save-unavailable",
+   "%s: saving %s files not available in this version of Octave",
+   obj_type.c_str (), file_type);
+}
+
+void base_fcn_handle::unimplemented (const char *op, const char *fmt) const
+{
+  std::string htype = type ();
+
+  warning ("%s for %s handles with %s format is not implemented",
+           op, htype.c_str (), fmt);
+}
+
+octave_value_list
+invalid_fcn_handle::call (int, const octave_value_list&)
+{
+  error ("invalid call to invalid function handle");
+}
+
+octave_value_list
+internal_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  interpreter& interp = __get_interpreter__ ();
+
+  return interp.feval (m_fcn, args, nargout);
+}
+
+octave_scalar_map internal_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  m.setfield ("function", fcn_name ());
+  m.setfield ("type", type ());
+  m.setfield ("file", "");
+
+  return m;
+}
+
+bool is_equal_to (const internal_fcn_handle& fh1,
+                  const internal_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+octave_value_list
+simple_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  // FIXME: if m_name has a '.' in the name, lookup first component.  If
+  // it is a classdef meta object, then build TYPE and IDX arguments and
+  // make a subsref call using them.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  octave_value fcn_to_call;
+
+  // The following code is similar to part of
+  // tree_evaluator::visit_index_expression but simpler because it
+  // handles a more restricted case.
+
+  symbol_table& symtab = interp.get_symbol_table ();
+
+  std::size_t pos = m_name.find ('.');
+
+  if (pos != std::string::npos)
+    {
+      // FIXME: check to see which of these cases actually work in
+      // Octave and Matlab.  For the last two, assume handle is
+      // created before object is defined as an object.
+      //
+      // We can have one of
+      //
+      //   pkg-list . fcn  (args)
+      //   pkg-list . cls . meth (args)
+      //   class-name . method  (args)
+      //   class-name . static-method  (args)
+      //   object . method  (args)
+      //   object . static-method  (args)
+
+      // Evaluate package elements until we find a function,
+      // classdef object, or classdef_meta object that is not a
+      // package.  An object may only appear as the first element,
+      // then it must be followed directly by a function name.
+
+      std::size_t beg = 0;
+      std::size_t end = pos;
+
+      std::vector<std::string> idx_elts;
+
+      while (true)
+        {
+          end = m_name.find ('.', beg);
+
+          idx_elts.push_back (m_name.substr (beg, end-beg));
+
+          if (end == std::string::npos)
+            break;
+
+          beg = end+1;
+        }
+
+      std::size_t n_elts = idx_elts.size ();
+
+      bool have_object = false;
+      octave_value partial_expr_val;
+
+      // Lazy evaluation.  The first element was not known to be defined
+      // as an object in the scope where the handle was created.  See if
+      // there is a definition in the current scope.
+
+      partial_expr_val = interp.varval (idx_elts[0]);
+
+      if (partial_expr_val.is_defined ())
+        {
+          if (! partial_expr_val.is_classdef_object () || n_elts != 2)
+            err_invalid_fcn_handle (m_name);
+
+          have_object = true;
+        }
+      else
+        partial_expr_val = symtab.find_function (idx_elts[0], ovl ());
+
+      std::string type;
+      std::list<octave_value_list> arg_list;
+
+      for (std::size_t i = 1; i < n_elts; i++)
+        {
+          if (partial_expr_val.is_package ())
+            {
+              if (have_object)
+                err_invalid_fcn_handle (m_name);
+
+              type = ".";
+              arg_list.push_back (ovl (idx_elts[i]));
+
+              try
+                {
+                  // Silently ignore extra output values.
+
+                  octave_value_list tmp_list
+                    = partial_expr_val.subsref (type, arg_list, 0);
+
+                  partial_expr_val
+                    = tmp_list.length () ? tmp_list(0) : octave_value ();
+
+                  if (partial_expr_val.is_cs_list ())
+                    err_invalid_fcn_handle (m_name);
+
+                  arg_list.clear ();
+                }
+              catch (const index_exception&)
+                {
+                  err_invalid_fcn_handle (m_name);
+                }
+            }
+          else if (have_object || partial_expr_val.is_classdef_meta ())
+            {
+              // Object or class name must be the next to the last
+              // element (it was the previous one, so if this is the
+              // final element, it should be a classdef method,
+              // but we'll let the classdef or classdef_meta subsref
+              // function sort that out.
+
+              if (i != n_elts-1)
+                err_invalid_fcn_handle (m_name);
+
+              type = ".(";
+              arg_list.push_back (ovl (idx_elts[i]));
+              arg_list.push_back (args);
+
+              return partial_expr_val.subsref (type, arg_list, nargout);
+            }
+          else
+            err_invalid_fcn_handle (m_name);
+        }
+
+      // If we get here, we must have a function to call.
+
+      if (! partial_expr_val.is_function ())
+        err_invalid_fcn_handle (m_name);
+
+      fcn_to_call = partial_expr_val;
+    }
+  else
+    {
+      // No "." in the name.
+
+      // Perform function lookup given current arguments.  We'll need
+      // to do this regardless of whether a function was found when
+      // the handle was created.
+
+      octave_value ov_fcn = symtab.find_function (m_name, args);
+
+      if (m_fcn.is_defined ())
+        {
+          // A simple function was found when the handle was created.
+          // Use that unless we find a class method to override it.
+
+          fcn_to_call = m_fcn;
+
+          if (ov_fcn.is_defined ())
+            {
+              octave_function *fcn = ov_fcn.function_value ();
+
+              std::string dispatch_class = fcn->dispatch_class ();
+
+              if (fcn->is_class_method ())
+                {
+                  // Function found through lookup is a class method
+                  // so use it instead of the simple one found when
+                  // the handle was created.
+
+                  fcn_to_call = ov_fcn;
+                }
+            }
+        }
+      else
+        {
+          // There was no simple function found when the handle was
+          // created so use the one found here (if any).
+
+          fcn_to_call = ov_fcn;
+        }
+    }
+
+  if (! fcn_to_call.is_defined ())
+    err_invalid_fcn_handle (m_name);
+
+  return interp.feval (fcn_to_call, args, nargout);
+}
+
+octave_function *simple_fcn_handle::function_value (bool)
+{
+  // FIXME: Shouldn't the lookup rules here match those used in the
+  // call method?
+
+  if (m_fcn.is_defined ())
+    return m_fcn.function_value ();
+
+  symbol_table& symtab = __get_symbol_table__ ();
+
+  // FIXME: is caching the correct thing to do?
+  // Cache this value so that the pointer will be valid as long as the
+  // function handle object is valid.
+
+  m_fcn = symtab.find_function (m_name, octave_value_list ());
+
+  return m_fcn.is_defined () ? m_fcn.function_value () : nullptr;
+}
+
+octave_user_function *simple_fcn_handle::user_function_value (bool)
+{
+  // FIXME: Shouldn't the lookup rules here match those used in the
+  // call method?
+
+  if (m_fcn.is_defined ())
+    return m_fcn.user_function_value ();
+
+  symbol_table& symtab = __get_symbol_table__ ();
+
+  // FIXME: is caching the correct thing to do?
+  // Cache this value so that the pointer will be valid as long as the
+  // function handle object is valid.
+
+  m_fcn = symtab.find_user_function (m_name);
+
+  return m_fcn.is_defined () ? m_fcn.user_function_value () : nullptr;
+}
+
+octave_value simple_fcn_handle::fcn_val (void)
+{
+  if (m_fcn.is_defined ())
+    return m_fcn;
+
+  symbol_table& symtab = __get_symbol_table__ ();
+
+  // FIXME: is caching the correct thing to do?
+  // Cache this value so that the pointer will be valid as long as the
+  // function handle object is valid.
+
+  m_fcn = symtab.find_user_function (m_name);
+
+  return m_fcn;
+}
+
+octave_scalar_map simple_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  m.setfield ("function", fcn_name ());
+  m.setfield ("type", type ());
+  // When is FILE defined for simple function handles?
+  m.setfield ("file", file ());
+
+  return m;
+}
+
+bool simple_fcn_handle::save_ascii (std::ostream& os)
+{
+  os << "# octaveroot: " << config::octave_exec_home () << "\n";
+
+  std::string fnm = file ();
+  if (! fnm.empty ())
+    os << "# path: " << fnm << "\n";
+
+  os << "# subtype: " << type () << "\n";
+
+  os << m_name << "\n";
+
+  return true;
+}
+
+bool simple_fcn_handle::load_ascii (std::istream& is)
+{
+  // FIXME: If m_file is not empty, try to load the file and define
+  // the function?  Is it an error if that fails?  Or should this job
+  // always be deferred until the handle is used?
+
+  return is.good ();
+}
+
+bool simple_fcn_handle::save_binary (std::ostream& os, bool)
+{
+  std::ostringstream nmbuf;
+
+  // When is FILE defined for simple function handles?
+  std::string fnm;
+
+  nmbuf << m_name << "@<simple>\n" << config::octave_exec_home ()
+        << "\n" << fnm;
+
+  std::string buf_str = nmbuf.str ();
+  int32_t tmp = buf_str.length ();
+  os.write (reinterpret_cast<char *> (&tmp), 4);
+  os.write (buf_str.c_str (), buf_str.length ());
+
+  return true;
+}
+
+bool simple_fcn_handle::load_binary (std::istream& is, bool,
+                                     mach_info::float_format)
+{
+  return is.good ();
+}
+
+bool simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                                   bool)
+{
 #if defined (HAVE_HDF5)
 
-    bool retval = true;
-
-    octave_hdf5_id group_hid = -1;
+  bool retval = true;
+
+  octave_hdf5_id group_hid = -1;
 #if defined (HAVE_HDF5_18)
-    group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                           octave_H5P_DEFAULT);
+  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                         octave_H5P_DEFAULT);
 #else
-    group_hid = H5Gcreate (loc_id, name, 0);
+  group_hid = H5Gcreate (loc_id, name, 0);
 #endif
-    if (group_hid < 0)
+  if (group_hid < 0)
+    return false;
+
+  octave_hdf5_id space_hid, data_hid, type_hid;
+  space_hid = data_hid = type_hid = -1;
+
+  // attach the type of the variable
+  type_hid = H5Tcopy (H5T_C_S1);
+  H5Tset_size (type_hid, m_name.length () + 1);
+  if (type_hid < 0)
+    {
+      H5Gclose (group_hid);
       return false;
-
-    octave_hdf5_id space_hid, data_hid, type_hid;
-    space_hid = data_hid = type_hid = -1;
-
-    // attach the type of the variable
-    type_hid = H5Tcopy (H5T_C_S1);
-    H5Tset_size (type_hid, m_name.length () + 1);
-    if (type_hid < 0)
-      {
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
-    hdims[0] = 0;
-    hdims[1] = 0;
-    space_hid = H5Screate_simple (0, hdims, nullptr);
-    if (space_hid < 0)
-      {
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
+    }
+
+  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
+  hdims[0] = 0;
+  hdims[1] = 0;
+  space_hid = H5Screate_simple (0, hdims, nullptr);
+  if (space_hid < 0)
+    {
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
 #if defined (HAVE_HDF5_18)
-    data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
-                          octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                          octave_H5P_DEFAULT);
+  data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
+                        octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                        octave_H5P_DEFAULT);
 #else
-    data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
-                          octave_H5P_DEFAULT);
+  data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
+                        octave_H5P_DEFAULT);
 #endif
-    if (data_hid < 0
-        || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
-                     octave_H5P_DEFAULT, m_name.c_str ()) < 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-    H5Dclose (data_hid);
-
-    std::string octaveroot = config::octave_exec_home ();
-
-    // When is FILE defined for simple fucntion handles?
-    std::string fpath;
-
-    H5Sclose (space_hid);
-    hdims[0] = 1;
-    hdims[1] = octaveroot.length ();
-    space_hid = H5Screate_simple (0, hdims, nullptr);
-    if (space_hid < 0)
-      {
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Tclose (type_hid);
-    type_hid = H5Tcopy (H5T_C_S1);
-    H5Tset_size (type_hid, octaveroot.length () + 1);
-    octave_hdf5_id a_id;
+  if (data_hid < 0
+      || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
+                   octave_H5P_DEFAULT, m_name.c_str ()) < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+  H5Dclose (data_hid);
+
+  std::string octaveroot = config::octave_exec_home ();
+
+  // When is FILE defined for simple fucntion handles?
+  std::string fpath;
+
+  H5Sclose (space_hid);
+  hdims[0] = 1;
+  hdims[1] = octaveroot.length ();
+  space_hid = H5Screate_simple (0, hdims, nullptr);
+  if (space_hid < 0)
+    {
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Tclose (type_hid);
+  type_hid = H5Tcopy (H5T_C_S1);
+  H5Tset_size (type_hid, octaveroot.length () + 1);
+  octave_hdf5_id a_id;
 #if defined (HAVE_HDF5_18)
-    a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
-                      octave_H5P_DEFAULT, octave_H5P_DEFAULT);
+  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
+                    octave_H5P_DEFAULT, octave_H5P_DEFAULT);
 #else
-    a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
-                      octave_H5P_DEFAULT);
+  a_id = H5Acreate (group_hid, "OCTAVEROOT", type_hid, space_hid,
+                    octave_H5P_DEFAULT);
 #endif
 
-    if (a_id >= 0)
-      {
-        retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
-
-        H5Aclose (a_id);
-      }
-    else
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Sclose (space_hid);
-    hdims[0] = 1;
-    hdims[1] = fpath.length ();
-    space_hid = H5Screate_simple (0, hdims, nullptr);
-    if (space_hid < 0)
-      {
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Tclose (type_hid);
-    type_hid = H5Tcopy (H5T_C_S1);
-    H5Tset_size (type_hid, fpath.length () + 1);
+  if (a_id >= 0)
+    {
+      retval = (H5Awrite (a_id, type_hid, octaveroot.c_str ()) >= 0);
+
+      H5Aclose (a_id);
+    }
+  else
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Sclose (space_hid);
+  hdims[0] = 1;
+  hdims[1] = fpath.length ();
+  space_hid = H5Screate_simple (0, hdims, nullptr);
+  if (space_hid < 0)
+    {
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Tclose (type_hid);
+  type_hid = H5Tcopy (H5T_C_S1);
+  H5Tset_size (type_hid, fpath.length () + 1);
 
 #if defined (HAVE_HDF5_18)
-    a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
-                      octave_H5P_DEFAULT, octave_H5P_DEFAULT);
+  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
+                    octave_H5P_DEFAULT, octave_H5P_DEFAULT);
 #else
-    a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
-                      octave_H5P_DEFAULT);
+  a_id = H5Acreate (group_hid, "FILE", type_hid, space_hid,
+                    octave_H5P_DEFAULT);
 #endif
 
-    if (a_id >= 0)
-      {
-        retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
-
-        H5Aclose (a_id);
-      }
-    else
-      retval = false;
-
-    H5Sclose (space_hid);
-    H5Tclose (type_hid);
-    H5Gclose (group_hid);
-
-    return retval;
+  if (a_id >= 0)
+    {
+      retval = (H5Awrite (a_id, type_hid, fpath.c_str ()) >= 0);
+
+      H5Aclose (a_id);
+    }
+  else
+    retval = false;
+
+  H5Sclose (space_hid);
+  H5Tclose (type_hid);
+  H5Gclose (group_hid);
+
+  return retval;
 
 #else
 
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    warn_save ("hdf5");
-
-    return false;
-
-#endif
-  }
-
-  bool simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
-                                     octave_hdf5_id& space_hid,
-                                     octave_hdf5_id& type_hid)
-  {
-#if defined (HAVE_HDF5)
-
-    unimplemented ("load", "hdf5");
-
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return true;
-
-#else
-
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return false;
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  warn_save ("hdf5");
+
+  return false;
 
 #endif
-  }
-
-  void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax,
-                                     int current_print_indent_level) const
-  {
-    octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
-                           current_print_indent_level);
-  }
-
-  bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name)
-      {
-        if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-          return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-
-        if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ())
-          return true;
-      }
-
-    return false;
-  }
-
-  scoped_fcn_handle::scoped_fcn_handle (const octave_value& fcn,
-                                        const std::string& name,
-                                        const std::list<std::string>& parentage)
-    : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage)
-  {
-    // FIXME: should it be an error if FCN is undefined?
-
-    if (m_fcn.is_defined ())
-      {
-        octave_function *oct_fcn = m_fcn.function_value ();
-
-        if (oct_fcn)
-          m_file = oct_fcn->fcn_file_name ();
-      }
-
-    m_parentage.push_front (name);
-  }
-
-  octave_value_list
-  scoped_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    // FIXME: we aren't really using the scope yet.  Hmm.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    if (! m_fcn.is_defined ())
-      {
-        // Try to find it?
-
-        find_function ();
-      }
-
-    if (! m_fcn.is_defined ())
-      err_invalid_fcn_handle (m_name);
-
-    return interp.feval (m_fcn, args, nargout);
-  }
-
-  octave_scalar_map scoped_fcn_handle::info (void)
-  {
-    octave_scalar_map m;
-
-    m.setfield ("function", fcn_name ());
-    m.setfield ("type", type ());
-    m.setfield ("file", file ());
-
-    m.setfield ("parentage", Cell (m_parentage));
-
-    return m;
-  }
-
-  bool scoped_fcn_handle::save_ascii (std::ostream& os)
-  {
-    os << "# octaveroot: " << config::octave_exec_home () << "\n";
-
-    std::string fnm = file ();
-    if (! fnm.empty ())
-      os << "# path: " << fnm << "\n";
-
-    os << "# subtype: " << type () << "\n";
-
-    os << m_name << "\n";
-
-    octave_value tmp = Cell (m_parentage);
-    tmp.save_ascii (os);
-
-    return os.good ();
-  }
-
-  bool scoped_fcn_handle::load_ascii (std::istream& is)
-  {
-    octave_cell ov_cell;
-    ov_cell.load_ascii (is);
-
-    if (ov_cell.iscellstr ())
-      {
-        Array<std::string> cellstr_val = ov_cell.cellstr_value ();
-
-        for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
-          m_parentage.push_back (cellstr_val(i));
-      }
-
-    return is.good ();
-  }
-
-  bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
-  {
-    std::ostringstream nmbuf;
-
-    std::string fnm = file ();
-
-    nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home ()
-          << "\n" << fnm;
-
-    std::string buf_str = nmbuf.str ();
-    int32_t len = buf_str.length ();
-    os.write (reinterpret_cast<char *> (&len), 4);
-    os.write (buf_str.c_str (), buf_str.length ());
-
-    octave_value tmp = Cell (m_parentage);
-    tmp.save_binary (os, save_as_floats);
-
-    return os.good ();
-  }
-
-  bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
-                                       mach_info::float_format fmt)
-  {
-    octave_cell ov_cell;
-    ov_cell.load_binary (is, swap, fmt);
-
-    if (ov_cell.iscellstr ())
-      {
-        Array<std::string> cellstr_val = ov_cell.cellstr_value ();
-
-        for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
-          m_parentage.push_back (cellstr_val(i));
-      }
-
-    return is.good ();
-  }
-
-  bool scoped_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
-                                     bool)
-  {
+}
+
+bool simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
+                                   octave_hdf5_id& space_hid,
+                                   octave_hdf5_id& type_hid)
+{
 #if defined (HAVE_HDF5)
 
-    unimplemented ("save", "hdf5");
-
-    // FIXME: save parentage.
-
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    return true;
-
-#else
-
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    warn_save ("hdf5");
-
-    return false;
-
-#endif
-  }
-
-  bool scoped_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
-                                     octave_hdf5_id& space_hid,
-                                     octave_hdf5_id& type_hid)
-  {
-#if defined (HAVE_HDF5)
-
-    unimplemented ("load", "hdf5");
-
-    // FIXME: load parentage.
-
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return true;
+  unimplemented ("load", "hdf5");
+
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return true;
 
 #else
 
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return false;
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return false;
 
 #endif
-  }
-
-  void scoped_fcn_handle::print_raw (std::ostream& os,
-                                     bool pr_as_read_syntax,
-                                     int current_print_indent_level) const
-  {
-    octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
-                           current_print_indent_level);
-  }
-
- bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name
-        && fh2.m_parentage == fh2.m_parentage
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  void scoped_fcn_handle::find_function (void)
-  {
-    // Since a scoped function is not visible by itself, try to load the
-    // file named in m_file then find and define the scoped function.
-    // It is not an error if this fails.  We can report later that the
-    // handle is invalid.
-
-    symbol_table& symtab = __get_symbol_table__ ();
-
-    if (m_parentage.size () == 1)
-      {
-        std::string dir_name = sys::file_ops::dirname (m_file);
-
-        std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
-
-        if (pos != std::string::npos)
-          dir_name = dir_name.substr (0, pos);
-        else if (dir_name == "private")
-          dir_name = ".";
-
-        std::string fcn_name = m_parentage.front ();
-
-        // FIXME: Does dir_name need to be in the load path for this to work?
-
-        m_fcn = symtab.find_private_function (dir_name, m_name);
-
-        // FIXME: Verify that it is a private function?
-      }
-    else
-      {
-        std::string primary_parent_name = m_parentage.back ();
-
-        octave_value ov_parent_fcn
-          = symtab.find_user_function (primary_parent_name);
-
-        if (ov_parent_fcn.is_defined ())
-          {
-            octave_user_function *fcn = ov_parent_fcn.user_function_value ();
-
-            if (fcn)
-              {
-                std::string file_name = fcn->fcn_file_name ();
-
-                std::string oct_home = config::octave_exec_home ();
-
-                if (file_name.substr (0, oct_home.size ()) == oct_home)
-                  file_name = file_name.substr (oct_home.size ());
-
-                octave_value subfcn = fcn->find_subfunction (m_name);
-
-                if (subfcn.is_defined ())
-                  m_fcn = subfcn;
-              }
-          }
-      }
-  }
-
-  octave_scalar_map base_nested_fcn_handle::info (void)
-  {
-    octave_scalar_map m;
-
-    m.setfield ("function", fcn_name ());
-    m.setfield ("type", type ());
-    m.setfield ("file", "");
-    m.setfield ("workspace", workspace ());
-
-    return m;
-  }
-
-  // FIXME: For save, we need a way to save the (possibly shared)
-  // workspace.  For load, we need a way to load and link to the
-  // (possibly shared) workspace that was saved.
-  //
-  // Since a nested function is not visible by itself, do we need to try
-  // to load the file named in m_file then find and define the function?
-  // Is it an error if that fails?  Or should this job always be
-  // deferred until the handle is used?
-
-  bool base_nested_fcn_handle::save_ascii (std::ostream& os)
-  {
-    unimplemented ("save", "text");
-
-    octave_unused_parameter (os);
-
-    return true;
-  }
-
-  bool base_nested_fcn_handle::load_ascii (std::istream& is)
-  {
-    unimplemented ("load", "text");
-
-    octave_unused_parameter (is);
-
-    return true;
-  }
-
-  bool base_nested_fcn_handle::save_binary (std::ostream& os,
-                                            bool save_as_floats)
-  {
-    unimplemented ("save", "binary");
-
-    octave_unused_parameter (os);
-    octave_unused_parameter (save_as_floats);
-
-    return true;
-  }
-
-  bool base_nested_fcn_handle::load_binary (std::istream& is, bool swap,
-                                            mach_info::float_format fmt)
-  {
-    unimplemented ("load", "binary");
-
-    octave_unused_parameter (is);
-    octave_unused_parameter (swap);
-    octave_unused_parameter (fmt);
-
-    return true;
-  }
-
-  bool base_nested_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
-                                          const char *name, bool)
-  {
+}
+
+void simple_fcn_handle::print_raw (std::ostream& os, bool pr_as_read_syntax,
+                                   int current_print_indent_level) const
+{
+  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
+                         current_print_indent_level);
+}
+
+bool is_equal_to (const simple_fcn_handle& fh1, const simple_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name)
+    {
+      if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+        return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+
+      if (fh1.m_fcn.is_undefined () && fh2.m_fcn.is_undefined ())
+        return true;
+    }
+
+  return false;
+}
+
+scoped_fcn_handle::scoped_fcn_handle (const octave_value& fcn,
+                                      const std::string& name,
+                                      const std::list<std::string>& parentage)
+  : base_fcn_handle (name), m_fcn (fcn), m_parentage (parentage)
+{
+  // FIXME: should it be an error if FCN is undefined?
+
+  if (m_fcn.is_defined ())
+    {
+      octave_function *oct_fcn = m_fcn.function_value ();
+
+      if (oct_fcn)
+        m_file = oct_fcn->fcn_file_name ();
+    }
+
+  m_parentage.push_front (name);
+}
+
+octave_value_list
+scoped_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  // FIXME: we aren't really using the scope yet.  Hmm.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  if (! m_fcn.is_defined ())
+    {
+      // Try to find it?
+
+      find_function ();
+    }
+
+  if (! m_fcn.is_defined ())
+    err_invalid_fcn_handle (m_name);
+
+  return interp.feval (m_fcn, args, nargout);
+}
+
+octave_scalar_map scoped_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  m.setfield ("function", fcn_name ());
+  m.setfield ("type", type ());
+  m.setfield ("file", file ());
+
+  m.setfield ("parentage", Cell (m_parentage));
+
+  return m;
+}
+
+bool scoped_fcn_handle::save_ascii (std::ostream& os)
+{
+  os << "# octaveroot: " << config::octave_exec_home () << "\n";
+
+  std::string fnm = file ();
+  if (! fnm.empty ())
+    os << "# path: " << fnm << "\n";
+
+  os << "# subtype: " << type () << "\n";
+
+  os << m_name << "\n";
+
+  octave_value tmp = Cell (m_parentage);
+  tmp.save_ascii (os);
+
+  return os.good ();
+}
+
+bool scoped_fcn_handle::load_ascii (std::istream& is)
+{
+  octave_cell ov_cell;
+  ov_cell.load_ascii (is);
+
+  if (ov_cell.iscellstr ())
+    {
+      Array<std::string> cellstr_val = ov_cell.cellstr_value ();
+
+      for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
+        m_parentage.push_back (cellstr_val(i));
+    }
+
+  return is.good ();
+}
+
+bool scoped_fcn_handle::save_binary (std::ostream& os, bool save_as_floats)
+{
+  std::ostringstream nmbuf;
+
+  std::string fnm = file ();
+
+  nmbuf << m_name << "@<scopedfunction>\n" << config::octave_exec_home ()
+        << "\n" << fnm;
+
+  std::string buf_str = nmbuf.str ();
+  int32_t len = buf_str.length ();
+  os.write (reinterpret_cast<char *> (&len), 4);
+  os.write (buf_str.c_str (), buf_str.length ());
+
+  octave_value tmp = Cell (m_parentage);
+  tmp.save_binary (os, save_as_floats);
+
+  return os.good ();
+}
+
+bool scoped_fcn_handle::load_binary (std::istream& is, bool swap,
+                                     mach_info::float_format fmt)
+{
+  octave_cell ov_cell;
+  ov_cell.load_binary (is, swap, fmt);
+
+  if (ov_cell.iscellstr ())
+    {
+      Array<std::string> cellstr_val = ov_cell.cellstr_value ();
+
+      for (octave_idx_type i = 0; i < cellstr_val.numel (); i++)
+        m_parentage.push_back (cellstr_val(i));
+    }
+
+  return is.good ();
+}
+
+bool scoped_fcn_handle::save_hdf5 (octave_hdf5_id loc_id, const char *name,
+                                   bool)
+{
 #if defined (HAVE_HDF5)
 
-    unimplemented ("save", "hdf5");
-
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    return true;
+  unimplemented ("save", "hdf5");
+
+  // FIXME: save parentage.
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  return true;
 
 #else
 
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    warn_save ("hdf5");
-
-    return false;
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  warn_save ("hdf5");
+
+  return false;
 
 #endif
-  }
-
-  bool base_nested_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
-                                          octave_hdf5_id& space_hid,
-                                          octave_hdf5_id& type_hid)
-  {
+}
+
+bool scoped_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
+                                   octave_hdf5_id& space_hid,
+                                   octave_hdf5_id& type_hid)
+{
 #if defined (HAVE_HDF5)
 
-    unimplemented ("load", "hdf5");
-
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return true;
+  unimplemented ("load", "hdf5");
+
+  // FIXME: load parentage.
+
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return true;
 
 #else
 
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return false;
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return false;
 
 #endif
-  }
-
-  void base_nested_fcn_handle::print_raw (std::ostream& os,
-                                          bool pr_as_read_syntax,
-                                          int current_print_indent_level) const
-  {
-    octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
-                           current_print_indent_level);
-  }
-
-  octave_value nested_fcn_handle::make_weak_nested_handle (void) const
-  {
-    return octave_value (new octave_fcn_handle
-                         (new weak_nested_fcn_handle (*this)));
-  }
-
-  octave_value_list
-  nested_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    tree_evaluator& tw = __get_evaluator__ ();
-
-    octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
-
-    tw.push_stack_frame (oct_usr_fcn, m_stack_context);
-
-    unwind_action act ([&tw] () { tw.pop_stack_frame (); });
-
-    return oct_usr_fcn->execute (tw, nargout, args);
-  }
-
-  octave_value nested_fcn_handle::workspace (void) const
-  {
-    return m_stack_context->workspace ();
-  }
-
-  bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  octave_value_list
-  weak_nested_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    tree_evaluator& tw = __get_evaluator__ ();
-
-    octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
-
-    std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
-
-    tw.push_stack_frame (oct_usr_fcn, frames);
-
-    unwind_action act ([&tw] () { tw.pop_stack_frame (); });
-
-    return oct_usr_fcn->execute (tw, nargout, args);
-  }
-
-  octave_value weak_nested_fcn_handle::workspace (void) const
-  {
-    std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
-
-    return frames ? frames->workspace () : octave_value ();
-  }
-
-  bool is_equal_to (const weak_nested_fcn_handle& fh1,
-                    const weak_nested_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  class_simple_fcn_handle::class_simple_fcn_handle (const std::string& class_nm,
-                                                    const std::string& meth_nm)
-    : base_fcn_handle (meth_nm), m_obj (), m_fcn (),
-      m_dispatch_class (class_nm)
-  { }
-
-  class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& fcn,
-                                                    const std::string& class_nm,
-                                                    const std::string& meth_nm)
-    : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn),
-      m_dispatch_class (class_nm)
-  { }
-
-  class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& obj,
-                                                    const octave_value& fcn,
-                                                    const std::string& class_nm,
-                                                    const std::string& meth_nm)
-    : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn),
-      m_dispatch_class (class_nm)
-  { }
-
-  octave_value_list
-  class_simple_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    interpreter& interp = __get_interpreter__ ();
-
-    if (m_obj.is_defined ())
-      {
-        octave_value_list tmp_args = args;
-        tmp_args.prepend (m_obj);
-
-        return interp.feval (m_fcn, tmp_args, nargout);
-      }
-
-    // FIXME: is this the best approach?  Should we be saving current
-    // dispatch class and restoring that value instead of
-    // unconditionally setting it to "" when we return from this
-    // function?
-
-    tree_evaluator& tw = interp.get_evaluator ();
-
-    unwind_action act ([&tw] () { tw.set_dispatch_class (""); });
-
-    tw.set_dispatch_class (m_dispatch_class);
-
-    if (m_fcn.is_defined ())
-      return interp.feval (m_fcn, args, nargout);
-
-    return interp.feval (fcn_name (), args, nargout);
-  }
-
-  octave_scalar_map class_simple_fcn_handle::info (void)
-  {
-    octave_scalar_map m;
-
-    m.setfield ("function", fcn_name ());
-    m.setfield ("type", type ());
-    m.setfield ("file", "");
-    m.setfield ("class", dispatch_class ());
-
-    return m;
-  }
-
-  // FIXME: Since a class method is not visible by itself, do we need to
-  // try to load the file named in m_file then find and define the
-  // function?  Is it an error if that fails?  Or should this job always
-  // be deferred until the handle is used?
-
-  bool class_simple_fcn_handle::save_ascii (std::ostream& os)
-  {
-    unimplemented ("save", "text");
-
-    octave_unused_parameter (os);
-
-    return true;
-  }
-
-  bool class_simple_fcn_handle::load_ascii (std::istream& is)
-  {
-    unimplemented ("load", "text");
-
-    octave_unused_parameter (is);
-
-    return true;
-  }
-
-  bool class_simple_fcn_handle::save_binary (std::ostream& os,
-                                             bool save_as_floats)
-  {
-    unimplemented ("save", "binary");
-
-    octave_unused_parameter (os);
-    octave_unused_parameter (save_as_floats);
-
-    return true;
-  }
-
-  bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap,
-                                             mach_info::float_format fmt)
-  {
-    unimplemented ("load", "binary");
-
-    octave_unused_parameter (is);
-    octave_unused_parameter (swap);
-    octave_unused_parameter (fmt);
-
-    return true;
-  }
-
-  bool class_simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
-                                           const char *name, bool)
-  {
+}
+
+void scoped_fcn_handle::print_raw (std::ostream& os,
+                                   bool pr_as_read_syntax,
+                                   int current_print_indent_level) const
+{
+  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
+                         current_print_indent_level);
+}
+
+bool is_equal_to (const scoped_fcn_handle& fh1, const scoped_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name
+      && fh2.m_parentage == fh2.m_parentage
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+void scoped_fcn_handle::find_function (void)
+{
+  // Since a scoped function is not visible by itself, try to load the
+  // file named in m_file then find and define the scoped function.
+  // It is not an error if this fails.  We can report later that the
+  // handle is invalid.
+
+  symbol_table& symtab = __get_symbol_table__ ();
+
+  if (m_parentage.size () == 1)
+    {
+      std::string dir_name = sys::file_ops::dirname (m_file);
+
+      std::size_t pos = dir_name.find_last_of (sys::file_ops::dir_sep_chars ());
+
+      if (pos != std::string::npos)
+        dir_name = dir_name.substr (0, pos);
+      else if (dir_name == "private")
+        dir_name = ".";
+
+      std::string fcn_name = m_parentage.front ();
+
+      // FIXME: Does dir_name need to be in the load path for this to work?
+
+      m_fcn = symtab.find_private_function (dir_name, m_name);
+
+      // FIXME: Verify that it is a private function?
+    }
+  else
+    {
+      std::string primary_parent_name = m_parentage.back ();
+
+      octave_value ov_parent_fcn
+        = symtab.find_user_function (primary_parent_name);
+
+      if (ov_parent_fcn.is_defined ())
+        {
+          octave_user_function *fcn = ov_parent_fcn.user_function_value ();
+
+          if (fcn)
+            {
+              std::string file_name = fcn->fcn_file_name ();
+
+              std::string oct_home = config::octave_exec_home ();
+
+              if (file_name.substr (0, oct_home.size ()) == oct_home)
+                file_name = file_name.substr (oct_home.size ());
+
+              octave_value subfcn = fcn->find_subfunction (m_name);
+
+              if (subfcn.is_defined ())
+                m_fcn = subfcn;
+            }
+        }
+    }
+}
+
+octave_scalar_map base_nested_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  m.setfield ("function", fcn_name ());
+  m.setfield ("type", type ());
+  m.setfield ("file", "");
+  m.setfield ("workspace", workspace ());
+
+  return m;
+}
+
+// FIXME: For save, we need a way to save the (possibly shared)
+// workspace.  For load, we need a way to load and link to the
+// (possibly shared) workspace that was saved.
+//
+// Since a nested function is not visible by itself, do we need to try
+// to load the file named in m_file then find and define the function?
+// Is it an error if that fails?  Or should this job always be
+// deferred until the handle is used?
+
+bool base_nested_fcn_handle::save_ascii (std::ostream& os)
+{
+  unimplemented ("save", "text");
+
+  octave_unused_parameter (os);
+
+  return true;
+}
+
+bool base_nested_fcn_handle::load_ascii (std::istream& is)
+{
+  unimplemented ("load", "text");
+
+  octave_unused_parameter (is);
+
+  return true;
+}
+
+bool base_nested_fcn_handle::save_binary (std::ostream& os,
+    bool save_as_floats)
+{
+  unimplemented ("save", "binary");
+
+  octave_unused_parameter (os);
+  octave_unused_parameter (save_as_floats);
+
+  return true;
+}
+
+bool base_nested_fcn_handle::load_binary (std::istream& is, bool swap,
+    mach_info::float_format fmt)
+{
+  unimplemented ("load", "binary");
+
+  octave_unused_parameter (is);
+  octave_unused_parameter (swap);
+  octave_unused_parameter (fmt);
+
+  return true;
+}
+
+bool base_nested_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
+                                        const char *name, bool)
+{
 #if defined (HAVE_HDF5)
 
-    unimplemented ("save", "hdf5");
-
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    return true;
+  unimplemented ("save", "hdf5");
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  return true;
+
+#else
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  warn_save ("hdf5");
+
+  return false;
+
+#endif
+}
+
+bool base_nested_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
+                                        octave_hdf5_id& space_hid,
+                                        octave_hdf5_id& type_hid)
+{
+#if defined (HAVE_HDF5)
+
+  unimplemented ("load", "hdf5");
+
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return true;
 
 #else
 
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-
-    warn_save ("hdf5");
-
-    return false;
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return false;
 
 #endif
-  }
-
-  bool class_simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
-                                           octave_hdf5_id& space_hid,
-                                           octave_hdf5_id& type_hid)
-  {
+}
+
+void base_nested_fcn_handle::print_raw (std::ostream& os,
+                                        bool pr_as_read_syntax,
+                                        int current_print_indent_level) const
+{
+  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
+                         current_print_indent_level);
+}
+
+octave_value nested_fcn_handle::make_weak_nested_handle (void) const
+{
+  return octave_value (new octave_fcn_handle
+                       (new weak_nested_fcn_handle (*this)));
+}
+
+octave_value_list
+nested_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  tree_evaluator& tw = __get_evaluator__ ();
+
+  octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
+
+  tw.push_stack_frame (oct_usr_fcn, m_stack_context);
+
+  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
+
+  return oct_usr_fcn->execute (tw, nargout, args);
+}
+
+octave_value nested_fcn_handle::workspace (void) const
+{
+  return m_stack_context->workspace ();
+}
+
+bool is_equal_to (const nested_fcn_handle& fh1, const nested_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+octave_value_list
+weak_nested_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  tree_evaluator& tw = __get_evaluator__ ();
+
+  octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
+
+  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
+
+  tw.push_stack_frame (oct_usr_fcn, frames);
+
+  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
+
+  return oct_usr_fcn->execute (tw, nargout, args);
+}
+
+octave_value weak_nested_fcn_handle::workspace (void) const
+{
+  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
+
+  return frames ? frames->workspace () : octave_value ();
+}
+
+bool is_equal_to (const weak_nested_fcn_handle& fh1,
+                  const weak_nested_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+class_simple_fcn_handle::class_simple_fcn_handle (const std::string& class_nm,
+    const std::string& meth_nm)
+  : base_fcn_handle (meth_nm), m_obj (), m_fcn (),
+    m_dispatch_class (class_nm)
+{ }
+
+class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& fcn,
+    const std::string& class_nm,
+    const std::string& meth_nm)
+  : base_fcn_handle (meth_nm), m_obj (), m_fcn (fcn),
+    m_dispatch_class (class_nm)
+{ }
+
+class_simple_fcn_handle::class_simple_fcn_handle (const octave_value& obj,
+    const octave_value& fcn,
+    const std::string& class_nm,
+    const std::string& meth_nm)
+  : base_fcn_handle (meth_nm), m_obj (obj), m_fcn (fcn),
+    m_dispatch_class (class_nm)
+{ }
+
+octave_value_list
+class_simple_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  interpreter& interp = __get_interpreter__ ();
+
+  if (m_obj.is_defined ())
+    {
+      octave_value_list tmp_args = args;
+      tmp_args.prepend (m_obj);
+
+      return interp.feval (m_fcn, tmp_args, nargout);
+    }
+
+  // FIXME: is this the best approach?  Should we be saving current
+  // dispatch class and restoring that value instead of
+  // unconditionally setting it to "" when we return from this
+  // function?
+
+  tree_evaluator& tw = interp.get_evaluator ();
+
+  unwind_action act ([&tw] () { tw.set_dispatch_class (""); });
+
+  tw.set_dispatch_class (m_dispatch_class);
+
+  if (m_fcn.is_defined ())
+    return interp.feval (m_fcn, args, nargout);
+
+  return interp.feval (fcn_name (), args, nargout);
+}
+
+octave_scalar_map class_simple_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  m.setfield ("function", fcn_name ());
+  m.setfield ("type", type ());
+  m.setfield ("file", "");
+  m.setfield ("class", dispatch_class ());
+
+  return m;
+}
+
+// FIXME: Since a class method is not visible by itself, do we need to
+// try to load the file named in m_file then find and define the
+// function?  Is it an error if that fails?  Or should this job always
+// be deferred until the handle is used?
+
+bool class_simple_fcn_handle::save_ascii (std::ostream& os)
+{
+  unimplemented ("save", "text");
+
+  octave_unused_parameter (os);
+
+  return true;
+}
+
+bool class_simple_fcn_handle::load_ascii (std::istream& is)
+{
+  unimplemented ("load", "text");
+
+  octave_unused_parameter (is);
+
+  return true;
+}
+
+bool class_simple_fcn_handle::save_binary (std::ostream& os,
+    bool save_as_floats)
+{
+  unimplemented ("save", "binary");
+
+  octave_unused_parameter (os);
+  octave_unused_parameter (save_as_floats);
+
+  return true;
+}
+
+bool class_simple_fcn_handle::load_binary (std::istream& is, bool swap,
+    mach_info::float_format fmt)
+{
+  unimplemented ("load", "binary");
+
+  octave_unused_parameter (is);
+  octave_unused_parameter (swap);
+  octave_unused_parameter (fmt);
+
+  return true;
+}
+
+bool class_simple_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
+    const char *name, bool)
+{
 #if defined (HAVE_HDF5)
 
-    unimplemented ("load", "hdf5");
-
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return true;
+  unimplemented ("save", "hdf5");
+
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  return true;
 
 #else
 
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return false;
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+
+  warn_save ("hdf5");
+
+  return false;
+
+#endif
+}
+
+bool class_simple_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
+    octave_hdf5_id& space_hid,
+    octave_hdf5_id& type_hid)
+{
+#if defined (HAVE_HDF5)
+
+  unimplemented ("load", "hdf5");
+
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return true;
+
+#else
+
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return false;
 
 #endif
-  }
-
-  void class_simple_fcn_handle::print_raw (std::ostream& os,
-                                           bool pr_as_read_syntax,
-                                           int current_print_indent_level) const
-  {
-    octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
-                           current_print_indent_level);
-  }
-
-  bool is_equal_to (const class_simple_fcn_handle& fh1,
-                    const class_simple_fcn_handle& fh2)
-  {
-    // FIXME: Also need to check object values are equivalent?
-
-    if (fh1.m_name == fh2.m_name
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  const std::string base_anonymous_fcn_handle::anonymous ("@<anonymous>");
-
-  octave_scalar_map base_anonymous_fcn_handle::info (void)
-  {
-    octave_scalar_map m;
-
-    std::ostringstream buf;
-    print_raw (buf, true, 0);
-    m.setfield ("function", buf.str ());
-
-    m.setfield ("type", type ());
-    m.setfield ("file", "");
-    m.setfield ("workspace", workspace ());
-    m.setfield ("within_file_path", "");
-
-    return m;
-  }
-
-  bool base_anonymous_fcn_handle::save_ascii (std::ostream& os)
-  {
-    // FIXME: can we ensure that m_fcn is always defined?
-
-    if (m_fcn.is_undefined ())
-      return false;
-
-    os << m_name << "\n";
-
-    print_raw (os, true, 0);
-    os << "\n";
-
-    std::size_t varlen = m_local_vars.size ();
-
-    if (varlen > 0)
-      {
-        os << "# length: " << varlen << "\n";
-
-        for (const auto& nm_val : m_local_vars)
-          {
-            if (! save_text_data (os, nm_val.second, nm_val.first, false, 0))
-              return ! os.fail ();
-          }
-      }
-
-    return true;
-  }
-
-  bool base_anonymous_fcn_handle::load_ascii (std::istream& is)
-  {
-    octave::skip_preceeding_newline (is);
-
-    std::string buf;
-
-    if (is)
-      {
-        // Get a line of text whitespace characters included, leaving
-        // newline in the stream.
-
-        buf = octave::read_until_newline (is, true);
-      }
-
-    std::streampos pos = is.tellg ();
-
-    // Set up temporary scope to use for evaluating the text that
-    // defines the anonymous function.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    tree_evaluator& tw = interp.get_evaluator ();
-
-    tw.push_dummy_scope (buf);
-    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
-
-    octave_idx_type len = 0;
-
-    if (extract_keyword (is, "length", len, true) && len >= 0)
-      {
-        if (len > 0)
-          {
-            for (octave_idx_type i = 0; i < len; i++)
-              {
-                octave_value t2;
-                bool dummy;
-
-                std::string name = read_text_data (is, "", dummy, t2, i);
-
-                if (! is)
-                  error ("load: failed to load anonymous function handle");
-
-                m_local_vars[name] = t2;
-              }
-          }
-      }
-    else
-      {
-        is.seekg (pos);
-        is.clear ();
-      }
-
-    if (is)
-      return parse (buf);
-
+}
+
+void class_simple_fcn_handle::print_raw (std::ostream& os,
+    bool pr_as_read_syntax,
+    int current_print_indent_level) const
+{
+  octave_print_internal (os, '@' + m_name, pr_as_read_syntax,
+                         current_print_indent_level);
+}
+
+bool is_equal_to (const class_simple_fcn_handle& fh1,
+                  const class_simple_fcn_handle& fh2)
+{
+  // FIXME: Also need to check object values are equivalent?
+
+  if (fh1.m_name == fh2.m_name
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+const std::string base_anonymous_fcn_handle::anonymous ("@<anonymous>");
+
+octave_scalar_map base_anonymous_fcn_handle::info (void)
+{
+  octave_scalar_map m;
+
+  std::ostringstream buf;
+  print_raw (buf, true, 0);
+  m.setfield ("function", buf.str ());
+
+  m.setfield ("type", type ());
+  m.setfield ("file", "");
+  m.setfield ("workspace", workspace ());
+  m.setfield ("within_file_path", "");
+
+  return m;
+}
+
+bool base_anonymous_fcn_handle::save_ascii (std::ostream& os)
+{
+  // FIXME: can we ensure that m_fcn is always defined?
+
+  if (m_fcn.is_undefined ())
     return false;
-  }
-
-  bool base_anonymous_fcn_handle::save_binary (std::ostream& os,
-                                               bool save_as_floats)
-  {
-    // FIXME: can we ensure that m_fcn is always defined?
-
-    if (m_fcn.is_undefined ())
+
+  os << m_name << "\n";
+
+  print_raw (os, true, 0);
+  os << "\n";
+
+  std::size_t varlen = m_local_vars.size ();
+
+  if (varlen > 0)
+    {
+      os << "# length: " << varlen << "\n";
+
+      for (const auto& nm_val : m_local_vars)
+        {
+          if (! save_text_data (os, nm_val.second, nm_val.first, false, 0))
+            return ! os.fail ();
+        }
+    }
+
+  return true;
+}
+
+bool base_anonymous_fcn_handle::load_ascii (std::istream& is)
+{
+  octave::skip_preceeding_newline (is);
+
+  std::string buf;
+
+  if (is)
+    {
+      // Get a line of text whitespace characters included, leaving
+      // newline in the stream.
+
+      buf = octave::read_until_newline (is, true);
+    }
+
+  std::streampos pos = is.tellg ();
+
+  // Set up temporary scope to use for evaluating the text that
+  // defines the anonymous function.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.push_dummy_scope (buf);
+  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
+
+  octave_idx_type len = 0;
+
+  if (extract_keyword (is, "length", len, true) && len >= 0)
+    {
+      if (len > 0)
+        {
+          for (octave_idx_type i = 0; i < len; i++)
+            {
+              octave_value t2;
+              bool dummy;
+
+              std::string name = read_text_data (is, "", dummy, t2, i);
+
+              if (! is)
+                error ("load: failed to load anonymous function handle");
+
+              m_local_vars[name] = t2;
+            }
+        }
+    }
+  else
+    {
+      is.seekg (pos);
+      is.clear ();
+    }
+
+  if (is)
+    return parse (buf);
+
+  return false;
+}
+
+bool base_anonymous_fcn_handle::save_binary (std::ostream& os,
+    bool save_as_floats)
+{
+  // FIXME: can we ensure that m_fcn is always defined?
+
+  if (m_fcn.is_undefined ())
+    return false;
+
+  std::ostringstream nmbuf;
+
+  std::size_t varlen = m_local_vars.size ();
+
+  nmbuf << anonymous;
+  if (varlen > 0)
+    nmbuf << ' ' << varlen;
+
+  std::string buf_str = nmbuf.str ();
+  int32_t tmp = buf_str.length ();
+  os.write (reinterpret_cast<char *> (&tmp), 4);
+  os.write (buf_str.c_str (), buf_str.length ());
+
+  std::ostringstream buf;
+  print_raw (buf, true, 0);
+  std::string stmp = buf.str ();
+  tmp = stmp.length ();
+  os.write (reinterpret_cast<char *> (&tmp), 4);
+  os.write (stmp.c_str (), stmp.length ());
+
+  if (varlen > 0)
+    {
+      for (const auto& nm_val : m_local_vars)
+        {
+          if (! save_binary_data (os, nm_val.second, nm_val.first,
+                                  "", 0, save_as_floats))
+            return ! os.fail ();
+        }
+    }
+
+  return true;
+}
+
+bool base_anonymous_fcn_handle::load_binary (std::istream& is, bool swap,
+    mach_info::float_format fmt)
+{
+  // Read extra characters in m_name as the number of local variable
+  // values in this anonymous function.
+
+  octave_idx_type len = 0;
+  std::size_t anl = anonymous.length ();
+  if (m_name.length () > anl)
+    {
+      std::istringstream nm_is (m_name.substr (anl));
+      nm_is >> len;
+
+      // Anonymous functions don't have names.  We just used this
+      // string as temporary storage to pass the number of local
+      // variable values.
+
+      m_name = "";
+    }
+
+  int32_t tmp;
+
+  if (! is.read (reinterpret_cast<char *> (&tmp), 4))
+    return false;
+  if (swap)
+    swap_bytes<4> (&tmp);
+
+  OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
+  // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though
+  // effectively not reading over file end
+  is.read (ctmp2, tmp);
+  ctmp2[tmp] = 0;
+
+  // Set up temporary scope to use for evaluating the text that
+  // defines the anonymous function.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.push_dummy_scope (ctmp2);
+  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
+
+  if (len > 0)
+    {
+      for (octave_idx_type i = 0; i < len; i++)
+        {
+          octave_value t2;
+          bool dummy;
+          std::string doc;
+
+          std::string name
+            = read_binary_data (is, swap, fmt, "", dummy, t2, doc);
+
+          if (! is)
+            error ("load: failed to load anonymous function handle");
+
+          m_local_vars[name] = t2;
+        }
+    }
+
+  if (is)
+    return parse (ctmp2);
+
+  return false;
+}
+
+bool base_anonymous_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
+    const char *name,
+    bool save_as_floats)
+{
+#if defined (HAVE_HDF5)
+
+  bool retval = true;
+
+  octave_hdf5_id group_hid = -1;
+#if defined (HAVE_HDF5_18)
+  group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                         octave_H5P_DEFAULT);
+#else
+  group_hid = H5Gcreate (loc_id, name, 0);
+#endif
+  if (group_hid < 0)
+    return false;
+
+  octave_hdf5_id space_hid, data_hid, type_hid;
+  space_hid = data_hid = type_hid = -1;
+
+  // attach the type of the variable
+  type_hid = H5Tcopy (H5T_C_S1);
+  H5Tset_size (type_hid, m_name.length () + 1);
+  if (type_hid < 0)
+    {
+      H5Gclose (group_hid);
       return false;
-
-    std::ostringstream nmbuf;
-
-    std::size_t varlen = m_local_vars.size ();
-
-    nmbuf << anonymous;
-    if (varlen > 0)
-      nmbuf << ' ' << varlen;
-
-    std::string buf_str = nmbuf.str ();
-    int32_t tmp = buf_str.length ();
-    os.write (reinterpret_cast<char *> (&tmp), 4);
-    os.write (buf_str.c_str (), buf_str.length ());
-
-    std::ostringstream buf;
-    print_raw (buf, true, 0);
-    std::string stmp = buf.str ();
-    tmp = stmp.length ();
-    os.write (reinterpret_cast<char *> (&tmp), 4);
-    os.write (stmp.c_str (), stmp.length ());
-
-    if (varlen > 0)
-      {
-        for (const auto& nm_val : m_local_vars)
-          {
-            if (! save_binary_data (os, nm_val.second, nm_val.first,
-                                    "", 0, save_as_floats))
-              return ! os.fail ();
-          }
-      }
-
-    return true;
-  }
-
-  bool base_anonymous_fcn_handle::load_binary (std::istream& is, bool swap,
-                                               mach_info::float_format fmt)
-  {
-    // Read extra characters in m_name as the number of local variable
-    // values in this anonymous function.
-
-    octave_idx_type len = 0;
-    std::size_t anl = anonymous.length ();
-    if (m_name.length () > anl)
-      {
-        std::istringstream nm_is (m_name.substr (anl));
-        nm_is >> len;
-
-        // Anonymous functions don't have names.  We just used this
-        // string as temporary storage to pass the number of local
-        // variable values.
-
-        m_name = "";
-      }
-
-    int32_t tmp;
-
-    if (! is.read (reinterpret_cast<char *> (&tmp), 4))
+    }
+
+  OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
+  hdims[0] = 0;
+  hdims[1] = 0;
+  space_hid = H5Screate_simple (0, hdims, nullptr);
+  if (space_hid < 0)
+    {
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
       return false;
-    if (swap)
-      swap_bytes<4> (&tmp);
-
-    OCTAVE_LOCAL_BUFFER (char, ctmp2, tmp+1);
-    // is.get (ctmp2, tmp+1, 0); caused is.eof () to be true though
-    // effectively not reading over file end
-    is.read (ctmp2, tmp);
-    ctmp2[tmp] = 0;
-
-    // Set up temporary scope to use for evaluating the text that
-    // defines the anonymous function.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    tree_evaluator& tw = interp.get_evaluator ();
-
-    tw.push_dummy_scope (ctmp2);
-    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
-
-    if (len > 0)
-      {
-        for (octave_idx_type i = 0; i < len; i++)
-          {
-            octave_value t2;
-            bool dummy;
-            std::string doc;
-
-            std::string name
-              = read_binary_data (is, swap, fmt, "", dummy, t2, doc);
-
-            if (! is)
-              error ("load: failed to load anonymous function handle");
-
-            m_local_vars[name] = t2;
-          }
-      }
-
-    if (is)
-      return parse (ctmp2);
-
-    return false;
-  }
-
-  bool base_anonymous_fcn_handle::save_hdf5 (octave_hdf5_id loc_id,
-                                             const char *name,
-                                             bool save_as_floats)
-  {
-#if defined (HAVE_HDF5)
-
-    bool retval = true;
-
-    octave_hdf5_id group_hid = -1;
+    }
 #if defined (HAVE_HDF5_18)
-    group_hid = H5Gcreate (loc_id, name, octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                           octave_H5P_DEFAULT);
+  data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
+                        octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                        octave_H5P_DEFAULT);
 #else
-    group_hid = H5Gcreate (loc_id, name, 0);
+  data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
+                        octave_H5P_DEFAULT);
 #endif
-    if (group_hid < 0)
+  if (data_hid < 0
+      || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
+                   octave_H5P_DEFAULT, m_name.c_str ()) < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
       return false;
-
-    octave_hdf5_id space_hid, data_hid, type_hid;
-    space_hid = data_hid = type_hid = -1;
-
-    // attach the type of the variable
-    type_hid = H5Tcopy (H5T_C_S1);
-    H5Tset_size (type_hid, m_name.length () + 1);
-    if (type_hid < 0)
-      {
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    OCTAVE_LOCAL_BUFFER (hsize_t, hdims, 2);
-    hdims[0] = 0;
-    hdims[1] = 0;
-    space_hid = H5Screate_simple (0, hdims, nullptr);
-    if (space_hid < 0)
-      {
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-#if defined (HAVE_HDF5_18)
-    data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
-                          octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                          octave_H5P_DEFAULT);
-#else
-    data_hid = H5Dcreate (group_hid, "nm",  type_hid, space_hid,
-                          octave_H5P_DEFAULT);
-#endif
-    if (data_hid < 0
-        || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
-                     octave_H5P_DEFAULT, m_name.c_str ()) < 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-    H5Dclose (data_hid);
-
-    std::ostringstream buf;
-    print_raw (buf, true, 0);
-    std::string stmp = buf.str ();
-
-    // attach the type of the variable
-    H5Tset_size (type_hid, stmp.length () + 1);
-    if (type_hid < 0)
-      {
-        H5Sclose (space_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
+    }
+  H5Dclose (data_hid);
+
+  std::ostringstream buf;
+  print_raw (buf, true, 0);
+  std::string stmp = buf.str ();
+
+  // attach the type of the variable
+  H5Tset_size (type_hid, stmp.length () + 1);
+  if (type_hid < 0)
+    {
+      H5Sclose (space_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
 
 #if defined (HAVE_HDF5_18)
-    data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
-                          octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                          octave_H5P_DEFAULT);
+  data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
+                        octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                        octave_H5P_DEFAULT);
 #else
-    data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
-                          octave_H5P_DEFAULT);
+  data_hid = H5Dcreate (group_hid, "fcn",  type_hid, space_hid,
+                        octave_H5P_DEFAULT);
 #endif
-    if (data_hid < 0
-        || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
-                     octave_H5P_DEFAULT, stmp.c_str ()) < 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Dclose (data_hid);
-
-    std::size_t varlen = m_local_vars.size ();
-
-    if (varlen > 0)
-      {
-        octave_hdf5_id as_id = H5Screate (H5S_SCALAR);
-
-        if (as_id >= 0)
-          {
-            octave_hdf5_id a_id;
+  if (data_hid < 0
+      || H5Dwrite (data_hid, type_hid, octave_H5S_ALL, octave_H5S_ALL,
+                   octave_H5P_DEFAULT, stmp.c_str ()) < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Dclose (data_hid);
+
+  std::size_t varlen = m_local_vars.size ();
+
+  if (varlen > 0)
+    {
+      octave_hdf5_id as_id = H5Screate (H5S_SCALAR);
+
+      if (as_id >= 0)
+        {
+          octave_hdf5_id a_id;
 #if defined (HAVE_HDF5_18)
-            a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
-                              octave_H5P_DEFAULT, octave_H5P_DEFAULT);
+          a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
+                            octave_H5P_DEFAULT, octave_H5P_DEFAULT);
 
 #else
-            a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
-                              octave_H5P_DEFAULT);
+          a_id = H5Acreate (group_hid, "SYMBOL_TABLE", H5T_NATIVE_IDX, as_id,
+                            octave_H5P_DEFAULT);
 #endif
 
-            if (a_id >= 0)
-              {
-                retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
-
-                H5Aclose (a_id);
-              }
-            else
-              retval = false;
-
-            H5Sclose (as_id);
-          }
-        else
-          retval = false;
+          if (a_id >= 0)
+            {
+              retval = (H5Awrite (a_id, H5T_NATIVE_IDX, &varlen) >= 0);
+
+              H5Aclose (a_id);
+            }
+          else
+            retval = false;
+
+          H5Sclose (as_id);
+        }
+      else
+        retval = false;
 #if defined (HAVE_HDF5_18)
-        data_hid = H5Gcreate (group_hid, "symbol table",
-                              octave_H5P_DEFAULT, octave_H5P_DEFAULT,
-                              octave_H5P_DEFAULT);
+      data_hid = H5Gcreate (group_hid, "symbol table",
+                            octave_H5P_DEFAULT, octave_H5P_DEFAULT,
+                            octave_H5P_DEFAULT);
 #else
-        data_hid = H5Gcreate (group_hid, "symbol table", 0);
+      data_hid = H5Gcreate (group_hid, "symbol table", 0);
 #endif
-        if (data_hid < 0)
-          {
-            H5Sclose (space_hid);
-            H5Tclose (type_hid);
-            H5Gclose (group_hid);
-            return false;
-          }
-
-        for (const auto& nm_val : m_local_vars)
-          {
-            if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first,
-                                 "", false, save_as_floats))
-              break;
-          }
-
-        H5Gclose (data_hid);
-      }
-
-    H5Sclose (space_hid);
-    H5Tclose (type_hid);
-    H5Gclose (group_hid);
-
-    return retval;
+      if (data_hid < 0)
+        {
+          H5Sclose (space_hid);
+          H5Tclose (type_hid);
+          H5Gclose (group_hid);
+          return false;
+        }
+
+      for (const auto& nm_val : m_local_vars)
+        {
+          if (! add_hdf5_data (data_hid, nm_val.second, nm_val.first,
+                               "", false, save_as_floats))
+            break;
+        }
+
+      H5Gclose (data_hid);
+    }
+
+  H5Sclose (space_hid);
+  H5Tclose (type_hid);
+  H5Gclose (group_hid);
+
+  return retval;
 
 #else
 
-    octave_unused_parameter (loc_id);
-    octave_unused_parameter (name);
-    octave_unused_parameter (save_as_floats);
-
-    warn_save ("hdf5");
-
-    return false;
+  octave_unused_parameter (loc_id);
+  octave_unused_parameter (name);
+  octave_unused_parameter (save_as_floats);
+
+  warn_save ("hdf5");
+
+  return false;
 
 #endif
-  }
-
-  bool base_anonymous_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
-                                             octave_hdf5_id& space_hid,
-                                             octave_hdf5_id& type_hid)
-  {
+}
+
+bool base_anonymous_fcn_handle::load_hdf5 (octave_hdf5_id& group_hid,
+    octave_hdf5_id& space_hid,
+    octave_hdf5_id& type_hid)
+{
 #if defined (HAVE_HDF5)
 
-    bool success = true;
+  bool success = true;
 
 #if defined (HAVE_HDF5_18)
-    octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT);
+  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn", octave_H5P_DEFAULT);
 #else
-    octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn");
+  octave_hdf5_id data_hid = H5Dopen (group_hid, "fcn");
 #endif
 
-    if (data_hid < 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Tclose (type_hid);
-    type_hid = H5Dget_type (data_hid);
-    octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
-
-    if (type_class_hid != H5T_STRING)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Dclose (data_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    H5Sclose (space_hid);
-    space_hid = H5Dget_space (data_hid);
-    hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
-
-    if (rank != 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Dclose (data_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    int slen = H5Tget_size (type_hid);
-    if (slen < 0)
-      {
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Dclose (data_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-
-    OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen);
-
-    // create datatype for (null-terminated) string to read into:
-    octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
-    H5Tset_size (st_id, slen);
-
-    if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
-                 octave_H5P_DEFAULT, fcn_tmp)
-        < 0)
-      {
-        H5Tclose (st_id);
-        H5Sclose (space_hid);
-        H5Tclose (type_hid);
-        H5Dclose (data_hid);
-        H5Gclose (group_hid);
-        return false;
-      }
-    H5Tclose (st_id);
-    H5Dclose (data_hid);
-
-    octave_idx_type len = 0;
-
-    // we have to pull some shenanigans here to make sure
-    // HDF5 doesn't print out all sorts of error messages if we
-    // call H5Aopen for a non-existing attribute
-
-    H5E_auto_t err_fcn;
-    void *err_fcn_data;
-
-    // turn off error reporting temporarily, but save the error
-    // reporting function:
+  if (data_hid < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Tclose (type_hid);
+  type_hid = H5Dget_type (data_hid);
+  octave_hdf5_id type_class_hid = H5Tget_class (type_hid);
+
+  if (type_class_hid != H5T_STRING)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Dclose (data_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  H5Sclose (space_hid);
+  space_hid = H5Dget_space (data_hid);
+  hsize_t rank = H5Sget_simple_extent_ndims (space_hid);
+
+  if (rank != 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Dclose (data_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  int slen = H5Tget_size (type_hid);
+  if (slen < 0)
+    {
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Dclose (data_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+
+  OCTAVE_LOCAL_BUFFER (char, fcn_tmp, slen);
+
+  // create datatype for (null-terminated) string to read into:
+  octave_hdf5_id st_id = H5Tcopy (H5T_C_S1);
+  H5Tset_size (st_id, slen);
+
+  if (H5Dread (data_hid, st_id, octave_H5S_ALL, octave_H5S_ALL,
+               octave_H5P_DEFAULT, fcn_tmp)
+      < 0)
+    {
+      H5Tclose (st_id);
+      H5Sclose (space_hid);
+      H5Tclose (type_hid);
+      H5Dclose (data_hid);
+      H5Gclose (group_hid);
+      return false;
+    }
+  H5Tclose (st_id);
+  H5Dclose (data_hid);
+
+  octave_idx_type len = 0;
+
+  // we have to pull some shenanigans here to make sure
+  // HDF5 doesn't print out all sorts of error messages if we
+  // call H5Aopen for a non-existing attribute
+
+  H5E_auto_t err_fcn;
+  void *err_fcn_data;
+
+  // turn off error reporting temporarily, but save the error
+  // reporting function:
 #if defined (HAVE_HDF5_18)
-    H5Eget_auto (octave_H5E_DEFAULT, &err_fcn, &err_fcn_data);
-    H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
+  H5Eget_auto (octave_H5E_DEFAULT, &err_fcn, &err_fcn_data);
+  H5Eset_auto (octave_H5E_DEFAULT, nullptr, nullptr);
 #else
-    H5Eget_auto (&err_fcn, &err_fcn_data);
-    H5Eset_auto (nullptr, nullptr);
+  H5Eget_auto (&err_fcn, &err_fcn_data);
+  H5Eset_auto (nullptr, nullptr);
 #endif
 
-    octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
-
-    if (attr_id >= 0)
-      {
-        if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
-          success = false;
-
-        H5Aclose (attr_id);
-      }
-
-    // restore error reporting:
+  octave_hdf5_id attr_id = H5Aopen_name (group_hid, "SYMBOL_TABLE");
+
+  if (attr_id >= 0)
+    {
+      if (H5Aread (attr_id, H5T_NATIVE_IDX, &len) < 0)
+        success = false;
+
+      H5Aclose (attr_id);
+    }
+
+  // restore error reporting:
 #if defined (HAVE_HDF5_18)
-    H5Eset_auto (octave_H5E_DEFAULT, err_fcn, err_fcn_data);
+  H5Eset_auto (octave_H5E_DEFAULT, err_fcn, err_fcn_data);
 #else
-    H5Eset_auto (err_fcn, err_fcn_data);
+  H5Eset_auto (err_fcn, err_fcn_data);
 #endif
 
-    // Set up temporary scope to use for evaluating the text that
-    // defines the anonymous function.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    tree_evaluator& tw = interp.get_evaluator ();
-
-    tw.push_dummy_scope (fcn_tmp);
-    unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
-
-    if (len > 0 && success)
-      {
-        hsize_t num_obj = 0;
+  // Set up temporary scope to use for evaluating the text that
+  // defines the anonymous function.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  tree_evaluator& tw = interp.get_evaluator ();
+
+  tw.push_dummy_scope (fcn_tmp);
+  unwind_action_safe restore_scope (&tree_evaluator::pop_scope, &tw);
+
+  if (len > 0 && success)
+    {
+      hsize_t num_obj = 0;
 #if defined (HAVE_HDF5_18)
-        data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT);
+      data_hid = H5Gopen (group_hid, "symbol table", octave_H5P_DEFAULT);
 #else
-        data_hid = H5Gopen (group_hid, "symbol table");
+      data_hid = H5Gopen (group_hid, "symbol table");
 #endif
-        H5Gget_num_objs (data_hid, &num_obj);
-        H5Gclose (data_hid);
-
-        if (num_obj != static_cast<hsize_t> (len))
-          error ("load: failed to load anonymous function handle");
-
-        hdf5_callback_data dsub;
-        int current_item = 0;
-        for (octave_idx_type i = 0; i < len; i++)
-          {
-            if (hdf5_h5g_iterate (group_hid, "symbol table", &current_item,
-                                  &dsub) <= 0)
-              error ("load: failed to load anonymous function handle");
-
-            m_local_vars[dsub.name] = dsub.tc;
-          }
-      }
-
-    if (success)
-      return parse (fcn_tmp);
-
-    return false;
+      H5Gget_num_objs (data_hid, &num_obj);
+      H5Gclose (data_hid);
+
+      if (num_obj != static_cast<hsize_t> (len))
+        error ("load: failed to load anonymous function handle");
+
+      hdf5_callback_data dsub;
+      int current_item = 0;
+      for (octave_idx_type i = 0; i < len; i++)
+        {
+          if (hdf5_h5g_iterate (group_hid, "symbol table", &current_item,
+                                &dsub) <= 0)
+            error ("load: failed to load anonymous function handle");
+
+          m_local_vars[dsub.name] = dsub.tc;
+        }
+    }
+
+  if (success)
+    return parse (fcn_tmp);
+
+  return false;
 
 #else
 
-    octave_unused_parameter (group_hid);
-    octave_unused_parameter (space_hid);
-    octave_unused_parameter (type_hid);
-
-    return false;
+  octave_unused_parameter (group_hid);
+  octave_unused_parameter (space_hid);
+  octave_unused_parameter (type_hid);
+
+  return false;
 
 #endif
-  }
-
-  void base_anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const
-  {
-    tree_print_code tpc (os);
-
-    octave_user_function *f = m_fcn.user_function_value ();
-
-    if (! f)
-      error ("invalid anonymous function handle");
-
-    os << "@";
-
-    // The parameter list should always be valid for anonymous
-    // functions, so we should always call accept for it, and it will
-    // print the parens for us.
-
-    tree_parameter_list *p = f->parameter_list ();
-
-    if (p)
-      p->accept (tpc);
-
-    os << " ";
-
-    tree_statement_list *b = f->body ();
-
-    panic_if (b->length () != 1);
-
-    tree_statement *s = b->front ();
-
-    if (! s)
-      error ("invalid anonymous function handle");
-
-    panic_unless (s->is_expression ());
-
-    tree_expression *e = s->expression ();
-
-    if (! e)
-      error ("invalid anonymous function handle");
-
-    tpc.print_fcn_handle_body (e);
-  }
-
-  bool base_anonymous_fcn_handle::parse (const std::string& fcn_text)
-  {
-    // FIXME: If evaluation of the string gives us an anonymous function
-    // handle object, then why extract the function and create a new
-    // anonymous function object?  Why not just attach the workspace
-    // values to the object returned by eval_string?  This code is also is
-    // duplicated in read_mat5_binary_element in ls-mat5.cc.
-
-    interpreter& interp = __get_interpreter__ ();
-
-    // Set up temporary scope to use for evaluating the text that defines
-    // the anonymous function so that we don't pick up values of random
-    // variables that might be in the current scope.
-
-    tree_evaluator& tw = interp.get_evaluator ();
-    tw.push_dummy_scope ("read_mat5_binary_element");
-
-    unwind_action act ([&tw] () { tw.pop_scope (); });
-
-    int parse_status;
-    octave_value anonymous_fcn_hdl
-      = interp.eval_string (fcn_text, true, parse_status);
-
-    if (parse_status != 0)
-      return false;
-
-    octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value ();
-
-    if (! fh)
-      return false;
-
-    m_fcn = fh->fcn_val ();
-
-    octave_user_function *uf = m_fcn.user_function_value (true);
-
-    if (uf)
-      {
-        symbol_scope uf_scope = uf->scope ();
-
-        if (uf_scope)
-          uf_scope.cache_name (m_name);
-      }
-
-    return true;
-  }
-
-  anonymous_fcn_handle::anonymous_fcn_handle (const octave_value& fcn,
-                                              const stack_frame::local_vars_map& local_vars,
-                                              const std::shared_ptr<stack_frame>& stack_context)
-    : base_anonymous_fcn_handle (fcn, local_vars),
-      m_stack_context (stack_context)
-  {
-    if (m_stack_context)
-      m_stack_context->mark_closure_context ();
-  }
-
-  octave_value anonymous_fcn_handle::make_weak_anonymous_handle (void) const
-  {
-    return octave_value (new octave_fcn_handle
-                         (new weak_anonymous_fcn_handle (*this)));
-  }
-
-  octave_value_list
-  anonymous_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    tree_evaluator& tw = __get_evaluator__ ();
-
-    octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
-
-    tw.push_stack_frame (oct_usr_fcn, m_local_vars, m_stack_context);
-
-    unwind_action act ([&tw] () { tw.pop_stack_frame (); });
-
-    return oct_usr_fcn->execute (tw, nargout, args);
-  }
-
-  octave_value anonymous_fcn_handle::workspace (void) const
-  {
-    octave_scalar_map local_vars_map;
-
-    for (const auto& nm_val : m_local_vars)
-      local_vars_map.assign (nm_val.first, nm_val.second);
-
-    // FIXME: it would be more convenient if stack_frame::workspace
-    // returned a Cell object directly instead of a Cell in an
-    // octave_value object.
-
-    Cell cell_frames;
-
-    if (m_stack_context)
-      {
-        octave_value ov_frames = m_stack_context->workspace ();
-        cell_frames = ov_frames.cell_value ();
-      }
-
-    octave_idx_type num_frames = cell_frames.numel ();
-    // FIXME: It seems there should be a simple way to concatenate cells...
-    Cell retval = Cell (num_frames+1, 1);
-    retval(0) = m_local_vars;
-    for (octave_idx_type i = 0; i < num_frames; i++)
-      retval(i+1) = cell_frames(i);
-
-    return retval;
-  }
-
-  bool is_equal_to (const anonymous_fcn_handle& fh1,
-                    const anonymous_fcn_handle& fh2)
-  {
-    if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
-
-  octave_value_list
-  weak_anonymous_fcn_handle::call (int nargout, const octave_value_list& args)
-  {
-    tree_evaluator& tw = __get_evaluator__ ();
-
-    octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
-
-    std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
-
-    tw.push_stack_frame (oct_usr_fcn, m_local_vars, frames);
-
-    unwind_action act ([&tw] () { tw.pop_stack_frame (); });
-
-    return oct_usr_fcn->execute (tw, nargout, args);
-  }
-
-  octave_value weak_anonymous_fcn_handle::workspace (void) const
-  {
-    octave_scalar_map local_vars_map;
-
-    for (const auto& nm_val : m_local_vars)
-      local_vars_map.assign (nm_val.first, nm_val.second);
-
-    // FIXME: it would be more convenient if stack_frame::workspace
-    // returned a Cell object directly instead of a Cell in an
-    // octave_value object.
-
-    std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
-
-    Cell cell_frames;
-
-    if (frames)
-      {
-        octave_value ov_frames = frames->workspace ();
-        cell_frames = ov_frames.cell_value ();
-      }
-
-    octave_idx_type num_frames = cell_frames.numel ();
-
-    // FIXME: It seems there should be a simple way to concatenate
-    // cells...
-    Cell retval = Cell (num_frames+1, 1);
-    retval(0) = m_local_vars;
-    for (octave_idx_type i = 0; i < num_frames; i++)
-      retval(i+1) = cell_frames(i);
-
-    return retval;
-  }
-
-  bool is_equal_to (const weak_anonymous_fcn_handle& fh1,
-                    const weak_anonymous_fcn_handle& fh2)
-  {
-    if (fh1.m_name == fh2.m_name
-        && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
-      return fh1.m_fcn.is_copy_of (fh2.m_fcn);
-    else
-      return false;
-  }
+}
+
+void base_anonymous_fcn_handle::print_raw (std::ostream& os, bool, int) const
+{
+  tree_print_code tpc (os);
+
+  octave_user_function *f = m_fcn.user_function_value ();
+
+  if (! f)
+    error ("invalid anonymous function handle");
+
+  os << "@";
+
+  // The parameter list should always be valid for anonymous
+  // functions, so we should always call accept for it, and it will
+  // print the parens for us.
+
+  tree_parameter_list *p = f->parameter_list ();
+
+  if (p)
+    p->accept (tpc);
+
+  os << " ";
+
+  tree_statement_list *b = f->body ();
+
+  panic_if (b->length () != 1);
+
+  tree_statement *s = b->front ();
+
+  if (! s)
+    error ("invalid anonymous function handle");
+
+  panic_unless (s->is_expression ());
+
+  tree_expression *e = s->expression ();
+
+  if (! e)
+    error ("invalid anonymous function handle");
+
+  tpc.print_fcn_handle_body (e);
+}
+
+bool base_anonymous_fcn_handle::parse (const std::string& fcn_text)
+{
+  // FIXME: If evaluation of the string gives us an anonymous function
+  // handle object, then why extract the function and create a new
+  // anonymous function object?  Why not just attach the workspace
+  // values to the object returned by eval_string?  This code is also is
+  // duplicated in read_mat5_binary_element in ls-mat5.cc.
+
+  interpreter& interp = __get_interpreter__ ();
+
+  // Set up temporary scope to use for evaluating the text that defines
+  // the anonymous function so that we don't pick up values of random
+  // variables that might be in the current scope.
+
+  tree_evaluator& tw = interp.get_evaluator ();
+  tw.push_dummy_scope ("read_mat5_binary_element");
+
+  unwind_action act ([&tw] () { tw.pop_scope (); });
+
+  int parse_status;
+  octave_value anonymous_fcn_hdl
+    = interp.eval_string (fcn_text, true, parse_status);
+
+  if (parse_status != 0)
+    return false;
+
+  octave_fcn_handle *fh = anonymous_fcn_hdl.fcn_handle_value ();
+
+  if (! fh)
+    return false;
+
+  m_fcn = fh->fcn_val ();
+
+  octave_user_function *uf = m_fcn.user_function_value (true);
+
+  if (uf)
+    {
+      symbol_scope uf_scope = uf->scope ();
+
+      if (uf_scope)
+        uf_scope.cache_name (m_name);
+    }
+
+  return true;
+}
+
+anonymous_fcn_handle::anonymous_fcn_handle (const octave_value& fcn,
+    const stack_frame::local_vars_map& local_vars,
+    const std::shared_ptr<stack_frame>& stack_context)
+  : base_anonymous_fcn_handle (fcn, local_vars),
+    m_stack_context (stack_context)
+{
+  if (m_stack_context)
+    m_stack_context->mark_closure_context ();
+}
+
+octave_value anonymous_fcn_handle::make_weak_anonymous_handle (void) const
+{
+  return octave_value (new octave_fcn_handle
+                       (new weak_anonymous_fcn_handle (*this)));
+}
+
+octave_value_list
+anonymous_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  tree_evaluator& tw = __get_evaluator__ ();
+
+  octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
+
+  tw.push_stack_frame (oct_usr_fcn, m_local_vars, m_stack_context);
+
+  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
+
+  return oct_usr_fcn->execute (tw, nargout, args);
+}
+
+octave_value anonymous_fcn_handle::workspace (void) const
+{
+  octave_scalar_map local_vars_map;
+
+  for (const auto& nm_val : m_local_vars)
+    local_vars_map.assign (nm_val.first, nm_val.second);
+
+  // FIXME: it would be more convenient if stack_frame::workspace
+  // returned a Cell object directly instead of a Cell in an
+  // octave_value object.
+
+  Cell cell_frames;
+
+  if (m_stack_context)
+    {
+      octave_value ov_frames = m_stack_context->workspace ();
+      cell_frames = ov_frames.cell_value ();
+    }
+
+  octave_idx_type num_frames = cell_frames.numel ();
+  // FIXME: It seems there should be a simple way to concatenate cells...
+  Cell retval = Cell (num_frames+1, 1);
+  retval(0) = m_local_vars;
+  for (octave_idx_type i = 0; i < num_frames; i++)
+    retval(i+1) = cell_frames(i);
+
+  return retval;
+}
+
+bool is_equal_to (const anonymous_fcn_handle& fh1,
+                  const anonymous_fcn_handle& fh2)
+{
+  if (fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
+
+octave_value_list
+weak_anonymous_fcn_handle::call (int nargout, const octave_value_list& args)
+{
+  tree_evaluator& tw = __get_evaluator__ ();
+
+  octave_user_function *oct_usr_fcn = m_fcn.user_function_value ();
+
+  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
+
+  tw.push_stack_frame (oct_usr_fcn, m_local_vars, frames);
+
+  unwind_action act ([&tw] () { tw.pop_stack_frame (); });
+
+  return oct_usr_fcn->execute (tw, nargout, args);
+}
+
+octave_value weak_anonymous_fcn_handle::workspace (void) const
+{
+  octave_scalar_map local_vars_map;
+
+  for (const auto& nm_val : m_local_vars)
+    local_vars_map.assign (nm_val.first, nm_val.second);
+
+  // FIXME: it would be more convenient if stack_frame::workspace
+  // returned a Cell object directly instead of a Cell in an
+  // octave_value object.
+
+  std::shared_ptr<stack_frame> frames = m_stack_context.lock ();
+
+  Cell cell_frames;
+
+  if (frames)
+    {
+      octave_value ov_frames = frames->workspace ();
+      cell_frames = ov_frames.cell_value ();
+    }
+
+  octave_idx_type num_frames = cell_frames.numel ();
+
+  // FIXME: It seems there should be a simple way to concatenate
+  // cells...
+  Cell retval = Cell (num_frames+1, 1);
+  retval(0) = m_local_vars;
+  for (octave_idx_type i = 0; i < num_frames; i++)
+    retval(i+1) = cell_frames(i);
+
+  return retval;
+}
+
+bool is_equal_to (const weak_anonymous_fcn_handle& fh1,
+                  const weak_anonymous_fcn_handle& fh2)
+{
+  if (fh1.m_name == fh2.m_name
+      && fh1.m_fcn.is_defined () && fh2.m_fcn.is_defined ())
+    return fh1.m_fcn.is_copy_of (fh2.m_fcn);
+  else
+    return false;
+}
 
 OCTAVE_END_NAMESPACE(octave)
 
@@ -2957,7 +2957,7 @@
           is >> name;
 
           new_rep.reset (new octave::simple_fcn_handle (name, fpath,
-                                                        octaveroot));
+                         octaveroot));
         }
       else if (subtype == "scopedfunction")
         {
@@ -2965,7 +2965,7 @@
           is >> name;
 
           new_rep.reset (new octave::scoped_fcn_handle (name, fpath,
-                                                        octaveroot));
+                         octaveroot));
         }
       else if (subtype == "anonymous")
         new_rep.reset (new octave::anonymous_fcn_handle ());
@@ -2975,7 +2975,7 @@
           is >> name;
 
           new_rep.reset (new octave::nested_fcn_handle (name, fpath,
-                                                        octaveroot));
+                         octaveroot));
         }
       else if (subtype == "classsimple")
         {
@@ -2983,7 +2983,7 @@
           is >> name;
 
           new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
-                                                              octaveroot));
+                         octaveroot));
         }
     }
 
@@ -3084,7 +3084,7 @@
         new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
       else if (subtype == "classsimple")
         new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
-                                                            octaveroot));
+                       octaveroot));
     }
 
   if (! new_rep)
@@ -3238,7 +3238,7 @@
         new_rep.reset (new octave::nested_fcn_handle (name, fpath, octaveroot));
       else if (subtype == "classsimple")
         new_rep.reset (new octave::class_simple_fcn_handle (name, fpath,
-                                                            octaveroot));
+                       octaveroot));
     }
 
   bool status = false;
@@ -3459,7 +3459,8 @@
   if (args.length () != 1)
     print_usage ();
 
-  octave_fcn_handle *fh = args(0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object");
+  octave_fcn_handle *fh = args(
+                            0).xfcn_handle_value ("functions: FCN_HANDLE argument must be a function handle object");
 
   return ovl (fh->info ());
 }
@@ -3475,7 +3476,8 @@
   if (args.length () != 1)
     print_usage ();
 
-  octave_fcn_handle *fh = args(0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object");
+  octave_fcn_handle *fh = args(
+                            0).xfcn_handle_value ("func2str: FCN_HANDLE argument must be a function handle object");
 
   if (! fh)
     error ("func2str: FCN_HANDLE must be a valid function handle");