bugGNU Octave - Bugs: bug #59304, exist() does not find a class...

 
 

bug #59304: exist() does not find a class inside @class directory

Submitter:  Ray Zimmerman <rdzman>
Submitted:  Mon 19 Oct 2020 05:06:43 PM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Matlab Compatibility
Status:  Fixed Assigned to:  None
Originator Name:  Open/Closed:  * Closed
Release:  * 6.0.90 Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Thu 05 Nov 2020 11:45:16 PM UTC, comment #19: 

I added a few tests, pushed the change on stable and merged with default:

http://hg.savannah.gnu.org/hgweb/octave/rev/2cbfd91aafb9

John W. Eaton <jwe>
Group administrator
Thu 05 Nov 2020 10:10:12 PM UTC, comment #18: 

Tested the new patch and it works for the final case of "ftp.m".  I think it is ready to go.

Rik <rik5>
Group administrator
Thu 05 Nov 2020 09:43:18 PM UTC, comment #17: 

I'm attaching another version of the patch that should allow


exist ("ftp.m")


to work.  If you agree that this one is OK, I'll add a commit message and a couple of tests and push to stable for the 6.1 release.

(file #50212)

John W. Eaton <jwe>
Group administrator
Sat 31 Oct 2020 01:04:06 AM UTC, comment #16: 


>> exist ('myclass.m')

ans =

     2


Ray Zimmerman <rdzman>
Fri 30 Oct 2020 08:08:13 PM UTC, comment #15: 

Per some of the earlier comments, I think jwe's patch is an improvement on the current situation and should be applied.

Last compatibility check for Ray, what does this return?


exist ('myclass.m')


The test should be set up as before with myclass.m inside the directory @myclass.

Rik <rik5>
Group administrator
Fri 30 Oct 2020 04:07:08 PM UTC, comment #14: 

We don't need to probe too deeply into Matlab's own functions.  I just thought that some simple which/exist/methods/properties calls could tell what type of object we were looking at.  I really don't know how to tell for sure whether something is a classdef object or a legacy class object.  Plus, some of these objects could be implemented internally and just look like classdef or legacy objects.

In any case, I'll try to write a script with some tests to see if we can at least get the basics right.

And yes, exist is much more complicated now than it was back in the days when there were variables, functions in .m files, directories, and plain old files with no packages, subfunctions, local functions, nested functions, legacy classes, classdef classes, java objects, etc.

John W. Eaton <jwe>
Group administrator
Fri 30 Oct 2020 03:50:14 PM UTC, comment #13: 

Actually, in Matlab, that ftp m-file is a simple wrapper function, not a classdef.

Ray Zimmerman <rdzman>
Fri 30 Oct 2020 03:09:24 PM UTC, comment #12: 

@jwe: Yes, I had already tried "which ftp" and that points to an m-file in Matlab which is not, itself, in an @class directory.  Maybe that is enough to definitively say ftp is now a classdef object because I believe old-style classes required the directory name to be the name of the class with '@' prepended.

Rik <rik5>
Group administrator
Fri 30 Oct 2020 03:07:20 PM UTC, comment #11: 

Thank you Ray for testing.

The exist function has a really complicated hierarchy for which value it returns when something matches multiple categories.  In this case, it would appear that higher number return values are prioritized over lower ones.  So a return value of 2 which indicates NAME is a file takes precedence over a return value of 8 which indicates NAME is a class.  Only when you specify that you want to restrict testing to a specific type ("class") does it ignore the file return code and return 8.

Rik <rik5>
Group administrator
Fri 30 Oct 2020 01:41:39 PM UTC, comment #10: 

From MATLAB:

>> exist('myclass')

ans =

     2

>> exist('myclass', 'class')

ans =

     8

>> exist('@myclass/myclass.m')

ans =

     2


Ray Zimmerman <rdzman>
Fri 30 Oct 2020 01:15:38 AM UTC, comment #9: 

Rik:  You could also look at the output of methods for an ftp object and "which ftp" and see if that gives any indication.

Ray:  Thanks, I lost track.

If "exist ('myclass')" returns 2 (meaning there is a myclass.m file) then in what cases does it return 8 (the argument to exist names a class)?

Weird.  Maybe I can come up with a set of tests to run.

John W. Eaton <jwe>
Group administrator
Thu 29 Oct 2020 10:35:02 PM UTC, comment #8: 

Matlab seems to allow creating an ftp object and calling properties on it, but I'm not sure the "properties" test is definitive.

Per the original post, Matlab returns 2, not 8, for classdef code that is within a .m file.

But, that still leaves open the question of what this returns


exist ('myclass', 'class')


And what this returns


exist ('@myclass/myclass.m')



Rik <rik5>
Group administrator
Thu 29 Oct 2020 10:07:37 PM UTC, comment #7: 

If I understand your question, @jwe, Matlab returns 2. See the example in my original post.

Ray Zimmerman <rdzman>
Thu 29 Oct 2020 09:57:10 PM UTC, comment #6: 

What I meant by that is the @ftp directory containing ftp.m is not included in the list of directories in the path, but the one containing the @ftp directory is.

In Octave, the ftp object is a legacy class thing, as I believe it originally was in Matlab.  But has Matlab's ftp object been rewritten to use classdef?  You could possibly tell by doing something like


obj = ftp ('ftp.gnu.org')
properties (obj)


as I don't think properties works for legacy classes?

Classdef classes can also be defined in @ directories.

https://www.mathworks.com/help/matlab/matlab_oop/organizing-classes-in-folders.html

Finding functions in package directories looks like another bug in the exist function.  You should be able to check for  containers.Map with


exist ('containers.Map')


I'm also curious to know whether Matlab's exist function returns 2 or 8 for classdef files defined in .m files.  If it returns 8 (indicating a class file) then I don't see how it can do that without examining the contents of the file (at least to see whether it begins with a classdef keyword, not necessarily parsing the whole file).  But the Matlab docs claim that it doesn't look at the contents of the file.

John W. Eaton <jwe>
Group administrator
Thu 29 Oct 2020 09:30:57 PM UTC, comment #5: 

Interesting, I would have said ftp.m is on the path.  Maybe we could get someone with Matlab access to test what exist returns for an old-style class.  Alternatively, we could ignore it as old-stlye classes are legacy code these days so there isn't much point in spending a lot of time on the subject.

I also think testing with Matlab would be required to untangle how classdef versus regular functions are handled.  I would be surprised if subfunctions or nested functions are returned by either exist or which.

Are files in private workspaces on the path?  In Octave, the scripts directory is on the path and that directory contains +containers.  Inside +containers is the file Map.m.  I can create a Map object with


x = containers.Map


But I can't find it with exist


exist Map
ans = 0
exist +containers/Map
ans = 0



Rik <rik5>
Group administrator
Thu 29 Oct 2020 06:56:43 PM UTC, comment #4: 

Right, but ftp.m is not directly on the path.

The solution used by "which" is to attempt to load the function and then check whether that was successful.  But then that fails with an error if the file has syntax errors, which I believe is incorrect given the Matlab docs say that does not examine the contents or internal structure of a file and relies solely on the file extension for classification.

But what does that mean (in Matlab) for something like


exist foo class


if there is a file foo.m in the path?  Does it check to see whether it is a classdef file?

If file contents are not examined, then I suppose exist can't find subfunctions, local functions, nested functions, or class methods defined in classdef files (except constructors, which I guess aren't really methods).

John W. Eaton <jwe>
Group administrator
Thu 29 Oct 2020 05:26:05 PM UTC, comment #3: 

Tested the patch and it works for 'ftp', '@ftp/ftp', and '@ftp/ftp.m'.  It does not work for 'ftp.m'.  It seems like it should because other m-files on the path do work.  For example,


exist sind.m
ans = 2



Rik <rik5>
Group administrator
Tue 27 Oct 2020 09:26:23 PM UTC, comment #2: 

I'm attaching a possible fix.  Ultimately, some refactoring to make which, exist, and general function lookups more consistent and possibly share more code probably wouldn't be a bad idea.



(file #50142)

John W. Eaton <jwe>
Group administrator
Mon 19 Oct 2020 09:28:13 PM UTC, comment #1: 

Confirmed.

A simpler example is just to use the @ftp class which is shipped with Octave.


which ftp
'ftp' is a function from the file /home/rik/wip/Projects_Mine/octave-dev/scripts/@ftp/ftp.m

exist ('ftp')
ans = 0

exist ('@ftp/ftp')
ans = 2


Re-titling to be a bit more general, and noting that this affects all operating systems.

Rik <rik5>
Group administrator
Mon 19 Oct 2020 05:06:43 PM UTC, original submission:  

Suppose I have in a directory on my Octave path, a subdirectory named @myclass containing myclass.m with the following content:

classdef myclass < handle
end


In both, MATLAB and Octave the class works just fine. But exist('myclass') returns 2 in MATLAB and 0 in Octave. On the other hand, exist('@myclass/myclass') returns 2 on both.

MATLAB output:

>> obj = myclass

obj =

  myclass with no properties.

>> exist('myclass')

ans =

     2

>> exist('@myclass/myclass')

ans =

     2


Octave output:

octave:1> obj = myclass
obj =

  myclass object with properties:


octave:2> exist('myclass')
ans = 0
octave:3> exist('@myclass/myclass')
ans = 2


Ray Zimmerman <rdzman>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #50212:  exist-diffs-v2.txt added by jwe (3KiB - text/plain)
file #50142:  exist-diffs.txt added by jwe (2KiB - text/plain)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by siko1056 (Updated the item)
  • -email is unavailable- added by jwe (Updated the item)
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by rdzman (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 10 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2020-11-09 jwe StatusReady For Test Fixed
        Open/ClosedOpen Closed
    2020-11-05 jwe StatusPatch Reviewed Ready For Test
    2020-11-05 jwe Attached File- Added exist-diffs-v2.txt, #50212
    2020-10-30 rik5 StatusPatch Submitted Patch Reviewed
    2020-10-29 siko1056 StatusConfirmed Patch Submitted
    2020-10-27 jwe Attached File- Added exist-diffs.txt, #50142
    2020-10-19 rik5 StatusNone Confirmed
        Operating SystemMac OS Any
        Summaryexist() does not find myclass inside @myclass directory exist() does not find a class inside @class directory

    Back to the top

    Powered by Savane 3.13-758e.
    Corresponding source code