octave-bug-tracker
[Top][All Lists]
Advanced

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

[Octave-bug-tracker] [bug #59602] incorrect "not a direct superclass" er


From: Rik
Subject: [Octave-bug-tracker] [bug #59602] incorrect "not a direct superclass" error
Date: Thu, 3 Dec 2020 13:19:54 -0500 (EST)
User-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36

Update of bug #59602 (project octave):

                Priority:              5 - Normal => 7 - High               
              Item Group: Unexpected Error or Warning => Regression           
 
                  Status:               Need Info => Confirmed              

    _______________________________________________________

Follow-up Comment #5:

Marking as confirmed, and noting that this is a regression and hence of more
importance than the average bug.  I'm adding jwe to the CC list as he may have
some ideas about what is going on.

I have done a bunch of line-by-line debuggging with gdb and I've somewhat
localized the problem, but it has been very tedious as the classdef code is
not simple and not my area of expertise.

The error "'classB' is not a direct superclass of 'classA'" originates in
ov-classdef.cc in this function which I quote.


octave_value_list
octave_classdef_superclass_ref::execute (octave::tree_evaluator& tw,
                                         int nargout,
                                         const octave_value_list& idx)
{
  octave_value_list retval;

  std::string meth_name;
  bool in_constructor;
  octave::cdef_class ctx;

  ctx = octave::get_class_context (meth_name, in_constructor);

  if (! ctx.ok ())
    error ("superclass calls can only occur in methods or constructors");

  std::string mname = m_method_name;
  std::string cname = m_class_name;

  // CLS is the superclass.  The lookup_class function handles
  // pkg.class names.

  octave::cdef_class cls = octave::lookup_class (cname);

  if (in_constructor)
    {
      if (! is_direct_superclass (cls, ctx))
        error ("'%s' is not a direct superclass of '%s'",
               cname.c_str (), ctx.get_name ().c_str ());



When I check the values of meth_name ("classA") and use ctx.get_name()
("classA") I can see that Octave is executing the constructor for classA.

If I check the values of m_method_name ("obj") and m_class_name ("classB") it
is clear that the interpreter has reached the line


obj@classB();


The next bit of code finds the specified superclass


  octave::cdef_class cls = octave::lookup_class (cname);


I verified with cls.get_name() that this is "classB".  Finally, Octave goes to
verify the superclass relationship with


      if (! is_direct_superclass (cls, ctx))


The next set of functions are in the file cdef-utils.cc.  The first function
is


  bool
  is_direct_superclass (const cdef_class& clsa, const cdef_class& clsb)
  {
    return is_superclass (clsa, clsb, false, 1);
  }


and the function is_superclass is defined as


  bool
  is_superclass (const cdef_class& clsa, const cdef_class& clsb,
                 bool allow_equal, int max_depth)
  {
    bool retval = false;

    if (allow_equal && clsa == clsb)
      retval = true;
    else if (max_depth != 0)
      {
        Cell c = clsb.get ("SuperClasses").cell_value ();

        for (int i = 0; ! retval && i < c.numel (); i++)
          {
            cdef_class cls = lookup_class (c(i));

            retval = is_superclass (clsa, cls, true,
                                    max_depth < 0 ? max_depth : max_depth-1);
          }
      }

    return retval;
  }


What is supposed to happen is that is_direct_superclass should call
is_superclass with a depth of 1 so that only direct parent classes are found.

The first time in to the function is_superclass allow_equal is false so
execution goes to the else branch where it gets the list of all SuperClasses
in a cell array of strings.  It then iterates over each SuperClass by
recursively calling is_superclass().  I verified that there is only one
SuperClass and using cls.get_name() that its name is "classB".

When the code works, the cdef_class variable from the lookup() call in
ov-classdef.cc and the cdef_class variable from the lookup() call in
cdef-utils.cc are the same.  They are the same as determined by the operator
overload "==" for cdef_class objects which compares the internal rep
pointers.

When it fails, the two cdef_class objects superficially look the same---I
called obj.get_name() and they both return "classB"---but the rep pointers are
to different areas of memory.

The function prototype for lookup_class is


  extern cdef_class
  lookup_class (const std::string& name, bool error_if_not_found = true,
                bool load_if_not_found = true);


For the moment, this is as far as I have been able to localize the problem. 
If I had to make a stab in the dark, I think that having the property "a =
@classB" might be parsed, but the new Octave behavior is to leave the function
handle reference dangling until it is used, at which point a search of the
symbol table is done and the correct function is run.  This "lazy" evaluation
of function handles is done for Matlab compatibility, but it may be that this
leaves the class or classdef object in a not fully constructed state.  I know
a cdef_object has functions for is_constructed() and
is_partially_constructed_for().  It is possible that the lookup_class()
function is avoiding partially constructed classes and when it doesn't find
classB, it creates a new instance in the class_manager because
load_if_not_found = true is the default.  This might also explain the
observation that the minimum working example succeeds if you create an object
of classB before creating an object of classA.

    _______________________________________________________

Reply to this item at:

  <https://savannah.gnu.org/bugs/?59602>

_______________________________________________
  Message sent via Savannah
  https://savannah.gnu.org/




reply via email to

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