bugGNU Octave - Bugs: bug #60723, subsagn raise error on .-indexing...

 
 

bug #60723: subsagn raise error on .-indexing for table with subsref/subsasgn defined

Submitter:  Andrew Janke <apjanke>
Submitted:  Thu 03 Jun 2021 12:51:10 AM UTC
   
 
Category:  Classdef Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Unexpected Error or Warning
Status:  None Assigned to:  None
Originator Name:  Open/Closed:  * Open
Release:  * 6.2.0 Operating System:  * Mac OS
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Sat 05 Jun 2021 04:27:48 PM UTC, comment #8: 

Yes, I think this issue could be left open, but let's octave maintainers decide.

Fernando <tutissanalio>
Sat 05 Jun 2021 08:23:12 AM UTC, comment #7: 

Oh yeah, I could just remove numel.

I agree that supporting numArgumentsFromSubscript in Octave is probably the best approach. Want to leave this issue open as a placeholder for doing so?

Andrew Janke <apjanke>
Sat 05 Jun 2021 08:17:07 AM UTC, comment #6: 

I also think that a possible solution could be to redefine numel, or simply removing the definition of numel in your class, so that 1 is always returned.

A better long term solution would be to make octave compatible with Matlab in that aspect, by implementing and making use of function numArgumentsFromSubscript. Maybe jwe or another octave developer would like to have a go with it.

Fernando <tutissanalio>
Sat 05 Jun 2021 07:37:52 AM UTC, comment #5: 

Ah, nice find, Fernando! Thanks for the quick response.

I wonder what's a good way to handle this? I was thinking that I could have `numel` call `dbstack` to see who's calling it, and return 1 if it's being called implicitly by the Octave interpreter in a subsref/subasgn context, and return the normal table size otherwise. But that doesn't seem feasible: dbstack() from within an implicit numel call looks just like a call to numel(table) from the base workspace; just the one stack frame.

numel is not very useful for tables, except for compatibility with generic or polymorphic functions, and I've never seen it used in the wild. Dot-referencing table variables/columns for assignment is really common, though. I guess I'll just define table.numel to always return 1, until I can think of something better. I've done preliminary testing on that, and it seems to work.

Andrew Janke <apjanke>
Fri 04 Jun 2021 05:13:41 PM UTC, comment #4: 

Here is the reference for Matlab's numArgumentsFromSubscript

https://www.mathworks.com/help/matlab/ref/numargumentsfromsubscript.html

Fernando <tutissanalio>
Fri 04 Jun 2021 05:04:13 PM UTC, comment #3: 

The problem is caused by the user-defined 'numel' function, and the different way Matlab and octave treat that function.

I have checked that the issue can be reproduced with this simple class definition:


classdef bug60723 < handle
  properties
    c = 3;
  end
  methods
    function n = numel (this)
      n =6;
    end
  end
end


In Matlab:

>> x=bug60723();
>> x.c=20;
>> x.c
ans =
    20


While in octave (current development version):

>> x=bug60723();
>> x.c=20;
error: invalid dot name structure assignment because the structure array is empty.  Specify a subscript on the structure array to resolve.
>> x.c
ans = 3


In a statement like "x.c=20", both Matlab and octave have to check that x.c evaluates to a single "object" or left-value. If, e.g. x were a struct array:

>> x=struct("c",{1,2,3});

Then the sentence "x.c=20" would be incorrect (both in Matlab and octave), because x.c evaluates to a list of 3 different left-values.

To check the number of left-values corresponding to x.c, octave calls the function numel on the object x. This should return 1, but because it has been redefined it returns 6, which causes the error.

To do the same thing, Matlab does not call numel, but uses the function numArgumentsFromSubscript instead, which can also be redefined by the user.

Fernando <tutissanalio>
Thu 03 Jun 2021 08:53:59 AM UTC, comment #2: 

Ayup, that sure smells similar.

I do not think I am defining an `end` method; I didn't even know that was a thing. But the behavior described there looks awful similar to what I'm experiencing here.

I'll read through that in detail and play around with what they're describing when I get a chance.

Thanks!

Andrew Janke <apjanke>
Thu 03 Jun 2021 08:48:16 AM UTC, comment #1: 

Do you think it could be somehow related to bug #55856?

Guillaume <gyom>
Thu 03 Jun 2021 12:51:10 AM UTC, original submission:  

Hi folks. In my Tablicious package (https://github.com/apjanke/octave-tablicious) I have defined a `table` class using a classdef (https://github.com/apjanke/octave-tablicious/blob/3b905b4d190d4869bb6cde2baa37b9273a61822b/inst/table.m), and given it subsref and subsasgn methods, plus a lot of other structure-and-size-related overridden methods. For .-indexing with these, the intent is for you to be able to index a variable (aka "column") by name, and either get the entire variable out, or assign a new array to the whole thing.

Reading the variables out works:


>> t = table([11;22;33], {'uno';'dos';'tres'}, 'VariableNames', {'X','S'});
>> t.X
ans =
   11
   22
   33


But attempting to assign to them errors out:


>> t.X = [1;2;3];
error: invalid dot name structure assignment because the structure array is empty.  Specify a subscript on the structure array to resolve.
>> t.foobar = [1;2;3]
error: invalid dot name structure assignment because the structure array is empty.  Specify a subscript on the structure array to resolve.


The error appears to be happening in the Octave interpreter before my subsasgn method ever gets called: If I put a `keyboard` statement as the first line in my table.subsasgn implementation, it never gets hit in this case.

Am I doing something wrong here? Or could this be an issue in the Octave interpreter's handling of subsasgn/subsref on existing objects, maybe in regards to how it interacts with numel or other size-related methods? Maybe it's implicitly calling one of the size-related methods to get some info about the assignment target and not happy with what it's hearing?

I've tried to come up with a minimal reproducible example, but haven't been able to trigger this behavior with a simpler classdef. (See attached shtable.m file.)

Original bug in the Tablicious project: https://github.com/apjanke/octave-tablicious/issues/80

Andrew Janke <apjanke>

 

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

Attach Files:
   
   
Comment:
   

Attached Files
file #51510:  shtable.m added by apjanke (6KiB - application/octet-stream)

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by mmuetzel (Updated the item)
  • -email is unavailable- added by tutissanalio (Posted a comment)
  • -email is unavailable- added by gyom (Posted a comment)
  • -email is unavailable- added by apjanke (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 2 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2024-01-23 mmuetzel CategoryInterpreter Classdef
    2021-06-03 apjanke Attached File- Added shtable.m, #51510

    Back to the top

    Powered by Savane 3.13-4448.
    Corresponding source code