octave-maintainers
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Derived Objects and OOP


From: Robert T. Short
Subject: Derived Objects and OOP
Date: Sat, 14 Mar 2009 10:51:42 -0700
User-agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.19) Gecko/20081204 SeaMonkey/1.1.14

Attached is a changeset and some associated tests and commentary for a partial implementation of derived classes.

There are some "FIXME" comments in the code (2) for things I really don't know how to do.

The attached tgz file include "NotesOnClasses" that describes what I have done and why. Also in the tgz file is a test script "ClassTest.m". There is still one major thing that has to be done before this is really useful. Assigning the result of a method in a parent class to the derived class doesn't work. See the test script "ClassTest.m" for examples. As yet I have not figured enough of this code out to have any idea how to do this. In the "NotesOnClasses" file are other issues that have to be resolved, but mostly they are secondary in the sense that it will be possible to write useful scripts without the change.

Comments are solicited:

1. I am not sure I am really using mercurial correctly. I made my changes, then

> hg commit
> hg export changesetid > changeset

2.  I tried to emulate the coding style, but probably missed.

3.  Maybe this is all nonsense and there is a better way?

This should certainly not be included in 3.2 since it is incomplete and since the number of files touched is small, I am not sure the patches should even be applied yet, but I would really like comments.

Finally, if the person that wrote the original code has sample scripts and classes that could be shared, then I can run regression tests and eventually build a good integrated test suite.


Bob
--
Robert T. Short
PhaseLocked Systems
# HG changeset patch
# User address@hidden
# Date 1237051272 25200
# Node ID 2e94632e5f7a2e02b59f529adeb9a85de05de458
# Parent  2e9af33636694e611a08e4f00c70c13491d180b7
Partial implementation of derived classes using the old form with "@" files.

diff -r 2e9af3363669 -r 2e94632e5f7a src/load-path.cc
--- a/src/load-path.cc  Fri Mar 13 16:47:50 2009 +0100
+++ b/src/load-path.cc  Sat Mar 14 10:21:12 2009 -0700
@@ -512,6 +512,7 @@
   fcn_map.clear ();
   private_fcn_map.clear ();
   method_map.clear ();
+  parent_map.clear ();
 
   do_append (".", false);
 }
@@ -1016,7 +1017,23 @@
 
       const_fcn_map_iterator p = m.find (meth);
 
-      if (p != m.end ())
+      if (p == m.end ())   // Look in parent classes.
+       {
+         const_parent_map_iterator r = parent_map.find (class_name);
+
+         if ( r != parent_map.end () )
+           {
+             std::list<std::string> plist = r->second;
+             std::list<std::string>::iterator it = plist.begin();
+             while ( it != plist.end() )
+               {
+                 retval = do_find_method(*it, meth, dir_name, type);
+                 if (retval != "") break;
+                 it++;
+               }
+           }
+       }
+      else
        {
          const file_info_list_type& file_info_list = p->second;
 
@@ -1764,6 +1781,12 @@
   execute_pkg_add_or_del (dir, "PKG_DEL");
 }
 
+void load_path::do_add_to_parent_map (std::string classname, 
+                                     std::list<std::string> parent_list)
+{
+  parent_map[classname] = parent_list;
+}
+
 DEFUN (genpath, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} genpath (@var{dir})\n\
diff -r 2e9af3363669 -r 2e94632e5f7a src/load-path.h
--- a/src/load-path.h   Fri Mar 13 16:47:50 2009 +0100
+++ b/src/load-path.h   Sat Mar 14 10:21:12 2009 -0700
@@ -37,7 +37,7 @@
 {
 protected:
 
-  load_path (void) : dir_info_list (), fcn_map (), method_map () { }
+  load_path (void) : dir_info_list (), fcn_map (), method_map (), parent_map 
() { }
 
 public:
 
@@ -228,6 +228,12 @@
     return instance_ok () ? instance->do_system_path () : std::string ();
   }
 
+  static void add_to_parent_map (std::string classname, std::list<std::string> 
parent_list)
+  {
+    if ( instance_ok () )
+       instance->do_add_to_parent_map (classname, parent_list);
+  }
+
 private:
 
   static const int M_FILE = 1;
@@ -386,6 +392,12 @@
 
   typedef method_map_type::const_iterator const_method_map_iterator;
   typedef method_map_type::iterator method_map_iterator;
+ 
+  // <CLASS_NAME, PARENT_LIST>>
+  typedef std::map<std::string, std::list<std::string> > parent_map_type;
+
+  typedef parent_map_type::const_iterator const_parent_map_iterator;
+  typedef parent_map_type::iterator parent_map_iterator;
 
   mutable dir_info_list_type dir_info_list;
 
@@ -394,6 +406,8 @@
   mutable private_fcn_map_type private_fcn_map;
 
   mutable method_map_type method_map;
+
+  mutable parent_map_type parent_map;
 
   static load_path *instance;
 
@@ -493,6 +507,8 @@
 
   std::string do_get_command_line_path (void) const { return 
command_line_path; }
 
+  void do_add_to_parent_map (std::string classname, std::list<std::string> 
parent_list);
+
   void add_to_fcn_map (const dir_info& di, bool at_end) const;
 
   void add_to_private_fcn_map (const dir_info& di) const;
diff -r 2e9af3363669 -r 2e94632e5f7a src/ov-base.h
--- a/src/ov-base.h     Fri Mar 13 16:47:50 2009 +0100
+++ b/src/ov-base.h     Sat Mar 14 10:21:12 2009 -0700
@@ -128,6 +128,12 @@
   octave_base_value (const octave_base_value&) { }
 
   virtual ~octave_base_value (void) { }
+
+  virtual std::list<std::string> get_parent_list (void) const
+             { return std::list<std::string>(); }
+  // FIXME: should gripe_something even though this "can't happen"?
+  virtual octave_base_value* find_parent_class(const std::string)
+             { return 0; }
 
   virtual octave_base_value *
   clone (void) const { return new octave_base_value (*this); }
diff -r 2e9af3363669 -r 2e94632e5f7a src/ov-class.cc
--- a/src/ov-class.cc   Fri Mar 13 16:47:50 2009 +0100
+++ b/src/ov-class.cc   Sat Mar 14 10:21:12 2009 -0700
@@ -62,6 +62,68 @@
     (octave_class::t_name, "<unknown>", octave_value (new octave_class ()));
 }
 
+octave_class::octave_class (const Octave_map& m, const std::string& id, 
+                octave_value_list& prnts)
+    : octave_base_value (), map (m), c_name (id)
+{
+  for(int idx=0; idx<prnts.length(); idx++)
+    {
+      if (! prnts(idx).is_object() )
+       error ("parents must be objects");
+      else
+       {
+         parent_list.push_back ( prnts(idx).class_name() );
+         map.assign (prnts(idx).class_name(), prnts(idx));
+       }
+    }
+  load_path::add_to_parent_map(id, parent_list);
+}
+
+octave_base_value*
+octave_class::find_parent_class(const std::string parent_class_name)
+{
+  octave_base_value* retval = 0;
+  std::string dbg_clsnm = class_name();
+  for(std::list<std::string>::iterator it=parent_list.begin();
+      it != parent_list.end();
+      it++)
+    {
+      std::string dbg_prnt = *it;
+    }
+
+  if ( parent_class_name == class_name() )
+    retval = this;
+  else
+    {
+      //  First look in the immediate parents.
+      std::list<std::string>::iterator 
+       p = find(parent_list.begin(), parent_list.end(), parent_class_name);
+      if (p!=parent_list.end())
+       {
+         std::string dbg_prnt = *p;
+         Octave_map::const_iterator pmap = map.seek (parent_class_name);
+         if (pmap != map.end())  //  Don't really need this check.
+           {
+             retval = map.contents(pmap)(0,0).internal_rep();
+           }
+       }
+      else  // Now look in the ancestor tree.
+       {
+         for(std::list<std::string>::iterator pit=parent_list.begin();
+             pit != parent_list.end();
+             pit++)
+           {
+             std::string dbg_prnt = *pit;
+             Octave_map::const_iterator smap = map.seek (*pit);
+             octave_base_value* obvp = map.contents(smap)(0,0).internal_rep();
+             retval = obvp->find_parent_class(parent_class_name);
+             if (retval != 0) break;
+           }
+       }
+    }
+  return retval;
+}
+
 Cell
 octave_class::dotref (const octave_value_list& idx)
 {
@@ -69,12 +131,29 @@
 
   assert (idx.length () == 1);
 
+  // FIXME:  Is there a "proper" way to do this?
+  octave_function* fcn = octave_call_stack::current();
+  std::string my_dir = fcn->dir_name();
+  int ipos = my_dir.find_last_of("@");
+  std::string method_class = my_dir.substr(ipos+1);
+
+  // Find the class in which this method resides before attempting to access
+  // the requested field.
+
+  octave_base_value* obvp = find_parent_class(method_class);
+
+  Octave_map my_map;
+  if (obvp!=0)
+    my_map = obvp->map_value();
+  else
+    my_map = map;
+
   std::string nm = idx(0).string_value ();
 
-  Octave_map::const_iterator p = map.seek (nm);
+  Octave_map::const_iterator p = my_map.seek (nm);
 
-  if (p != map.end ())
-    retval = map.contents (p);
+  if (p != my_map.end ())
+    retval = my_map.contents (p);
   else
     error ("class has no member `%s'", nm.c_str ());
 
@@ -1167,19 +1246,24 @@
 DEFUN (class, args, ,
   "-*- texinfo -*-\n\
 @deftypefn {Built-in Function} {} class (@var{expr})\n\
+Return the class of the expression @var{expr}.\n\
 @deftypefnx {Built-in Function} {} class (@var{s}, @var{id})\n\
+Create a base class with fields from structure @var{s} and name (string) 
@var{id}.\n\
address@hidden {Built-in Function} {} class (@var{s}, @var{id}, @var{p}, 
@dots{})\n\
+Create a class derived from parent classes @var{p} with fields from @var{s} 
and name @var{id}\n\
 \n\
-Return the class of the expression @var{expr}, as a string or\n\
-create a class object from the structure @var{s} with name @var{id}.\n\
 @end deftypefn")
 {
   octave_value retval;
 
   int nargin = args.length ();
 
+  if (nargin == 0)
+    print_usage ();
+
   if (nargin == 1)
     retval = args(0).class_name ();
-  else if (nargin == 2)
+  else
     {
       Octave_map m = args(0).map_value ();
 
@@ -1192,7 +1276,13 @@
              octave_function *fcn = octave_call_stack::caller ();
 
              if (fcn && fcn->is_class_constructor ())
-               retval = octave_value (new octave_class (m, id));
+               if (nargin==2)
+                 retval = octave_value (new octave_class (m, id));
+               else
+                 {
+                   octave_value_list prnts = args.slice(2,args.length()-2);
+                   retval = octave_value (new octave_class (m, id, prnts));
+                 }
              else
                error ("class: invalid call from outside class constructor");
            }
@@ -1202,8 +1292,6 @@
       else
        error ("class: expecting structure as first argument");
     }
-  else
-    print_usage ();
 
   return retval;
 }
diff -r 2e9af3363669 -r 2e94632e5f7a src/ov-class.h
--- a/src/ov-class.h    Fri Mar 13 16:47:50 2009 +0100
+++ b/src/ov-class.h    Sat Mar 14 10:21:12 2009 -0700
@@ -55,9 +55,14 @@
     : octave_base_value (), map (m), c_name (id) { }
 
   octave_class (const octave_class& s)
-    : octave_base_value (s), map (s.map), c_name (s.c_name) { }
+    : octave_base_value (s), map (s.map), c_name (s.c_name), parent_list 
(s.parent_list) { }
+
+  octave_class (const Octave_map& m, const std::string& id, 
+                octave_value_list& prnts);
 
   ~octave_class (void) { }
+
+  virtual octave_base_value* find_parent_class (std::string);
 
   octave_base_value *clone (void) const { return new octave_class (*this); }
 
@@ -165,6 +170,7 @@
 
   static const std::string t_name;
   std::string c_name;
+  std::list<std::string> parent_list;
 
   bool in_class_method (void) const;
 };

Attachment: octaveTest.tgz
Description: application/compressed-tar


reply via email to

[Prev in Thread] Current Thread [Next in Thread]