bugGNU Octave - Bugs: bug #50893, for loop index variable not...

 
 

bug #50893: for loop index variable not initialized unless loop is entered

Submitter:  Ceral Paquet <octavebugs>
Submitted:  Fri 28 Apr 2017 06:19:28 PM UTC
   
 
Category:  Interpreter Severity:  2 - Minor
Priority:  3 - Low Item Group:  WTF, Matlab?!?
Status:  Fixed Assigned to:  None
Originator Name:  Open/Closed:  * Closed
Release:  * 4.2.1 Operating System:  * GNU/Linux
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Mon 22 May 2017 02:34:16 AM UTC, comment #11: 

I checked in the changeset on the development branch here (http://hg.savannah.gnu.org/hgweb/octave/rev/fd7a16594614).

Rik <rik5>
Group administrator
Thu 18 May 2017 04:46:08 AM UTC, comment #10: 

Try the attached changeset.  It does not execute the loop body if the command expression is empty.  That resolves point #1.  Even though the loop body is not executed, the loop variable is still initialized to an empty value of the same class as the command expression (for example, uint32 or cell or double).

(file #40730)

Rik <rik5>
Group administrator
Sun 30 Apr 2017 03:42:05 AM UTC, comment #9: 

Item 3 seems like a side effect of Matlab's internal implementation and it doesn't look critical to copy that.

However, I could easily see items #1 and #2 being a problem.

In the first case, code might calculate a collection which is then iterated over.  If the collection happened to be empty, but with multiple columns, then Octave would actually execute the loop body.  This would be terribly hard to debug because most of the time the script would get the same answer in Octave or Matlab, but occasionally you would get different results based on the peculiarities of the input data.

It would be slightly harder, but not that much harder, to get the same behavior from case #2.


for k = COLLECTION
  if (special_condition)
    break;
  end
  ... other code ...
end  % end for loop

if (k != COLLECTION(end))
  % code to do something when special case was hit
end


If COLLECTION happened to be empty then Octave would not initialize k and the test on if (k ...) would produce a parse error since the variable is not defined.  Again, most of the time the script would work but for occasional data patterns you would get parse errors.

It does seem logical to me that if the expression to iterate over is empty that you don't execute the loop.  The initialization of the loop variable seems arbitrary, but we should be able to copy that.


Rik <rik5>
Group administrator
Sat 29 Apr 2017 09:16:50 AM UTC, comment #8: 

I can't find any documentation about it. Yes it does look rather ad hoc. Looks like Rik found a genuine bug tho rather that this little WTF.

For me, it would help to just leave a 0x0 double in the workspace (or any class, it doesn't matter). It would be just to make things like this work in Octave when n=0:


a = rand(n,1);

for k = 1:n
   if a(k)>0.5; break; end
end

b = a(k);


Ceral Paquet <octavebugs>
Fri 28 Apr 2017 09:06:00 PM UTC, comment #7: 

These seem almost like some kind of accident of implementation rather than conscious decisions about how things should work.  But who knows, right?  Is this Matlab behavior documented anywhere?

John W. Eaton <jwe>
Group administrator
Fri 28 Apr 2017 08:46:23 PM UTC, comment #6: 

Trying to summarize.  It appears there are three incompatibilities.

1) When an object has columns, but no rows, Octave iterates over the columns while Matlab does not iterate.  Sample code


for k = zeros (0,3)
  disp ('Hello');
end
Hello
Hello
Hello


2) When an object has rows, but no columns, Octave skips loop variable assignment entirely.  Matlab assigns to the loop variable, but does not execute the loop.  An object with no columns can be an empty range (3:0) or a directly created object like zeros (3, 0).  Sample code


clear k;
for k = zeros (3, 0)
  disp ('Hello');
end
whos k


3) In case 2 above, Matlab always creates a 0x0 double initialization for the loop variable even when the object was a different type

clear k;
for k = zeros (3, 0, 'int32')
  disp ('Hello');
end
whos k

I think it is enough to fix items 1 and 2, but skip 3.


Rik <rik5>
Group administrator
Fri 28 Apr 2017 06:57:57 PM UTC, comment #5: 

A few more cases. The scalar index seems well behaved, the array index not so much.


>> clear; for k = zeros (3,0,'int32'); disp(k); end; whos
  Name      Size            Bytes  Class     Attributes

  k         0x0                 0  double

>> clear; for k = zeros (0,3,'int32'); disp(k); end; whos
  Name      Size            Bytes  Class    Attributes

  k         0x1                 0  int32

>> clear; for k = zeros (0,3); disp(k); end; whos
  Name      Size            Bytes  Class     Attributes

  k         0x1                 0  double

>> clear; for k = zeros (3,3); disp(k); end; whos
     0
     0
     0

     0
     0
     0

     0
     0
     0

  Name      Size            Bytes  Class     Attributes

  k         3x1                24  double



Ceral Paquet <octavebugs>
Fri 28 Apr 2017 06:51:45 PM UTC, comment #4: 


>> clear
>> xd = zeros (1, 0);
xi = zeros (1, 0, 'int32');
for kd = xd; end
for ki = xi; end
whos
  Name      Size            Bytes  Class     Attributes

  kd        0x0                 0  double
  ki        0x0                 0  double
  xd        1x0                 0  double
  xi        1x0                 0  int32

>>




>> clear
>> for k = zeros (0,3)
  disp (k);
end
>> whos
  Name      Size            Bytes  Class     Attributes

  k         0x1                 0  double



Ceral Paquet <octavebugs>
Fri 28 Apr 2017 06:45:15 PM UTC, comment #3: 

More clues that this is specific to the range operator which is optimized for space storage in Octave, but not Matlab.  If I disable Octave's efficient range implementation then the behavior is Matlab compatible.


octave:1> disable_range (true)
octave:2> disable_range
ans = 1
octave:3> for k = 1:0
> disp (k);
> end
octave:4> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        ans         1x1                          1  logical

Total is 1 element using 1 byte

octave:5> clear k
octave:6> disable_range (false)
octave:7> for k = 1:0
> disp (k);
> end
octave:8> whos
Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        ans         1x1                          1  logical

Total is 1 element using 1 byte



Rik <rik5>
Group administrator
Fri 28 Apr 2017 06:32:11 PM UTC, comment #2: 

Confirmed.  And as a clue to tracking this down, it appears to happen only with ranges.  For example, this works despite the


for k = zeros (0,3)
  disp (k);
end
[](0x1)
[](0x1)
[](0x1)

whos k

Variables in the current scope:

   Attr Name        Size                     Bytes  Class
   ==== ====        ====                     =====  =====
        k           0x1                          0  double

Total is 0 elements using 0 bytes


Could you run the sample code above in Matlab to see what it does?  They may check whether the loop body is empty before executing anything.  In that case, I would expect that k would be of size 0x3 and no loop body would be executed.


Rik <rik5>
Group administrator
Fri 28 Apr 2017 06:28:27 PM UTC, comment #1: 

Is it always initialized as double, or is the type set to the type of the loop range?  Is there a difference between the following two loops?


xd = zeros (1, 0);
xi = zeros (1, 0, 'int32');
for kd = xd; end
for ki = xi; end
whos


John W. Eaton <jwe>
Group administrator
Fri 28 Apr 2017 06:19:28 PM UTC, original submission:  

I ran into a little inconsistency between MATLAB and Octave. MATLAB initializes the loop index variable as empty if the loop is not entered.

MATLAB

>> clear
>> for k=1:0;end
>> whos
  Name      Size            Bytes  Class     Attributes

  k         0x0                 0  double


Octave

>> clear
>> for k=1:0;end
>> whos
>>


Ceral Paquet <octavebugs>

 

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

Attach Files:
   
   
Comment:
   

Attached Files
file #40730:  bug50893.cset added by rik5 (2KiB - application/octet-stream)

 

Depends on the following items: None found

Digest:
   bug dependencies.

 

Carbon-Copy List
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by jwe (Posted a comment)
  • -email is unavailable- added by octavebugs (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 11 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2017-08-18 mtmiller Dependencies- bugs #51785 is dependent
    2017-05-22 rik5 StatusPatch Submitted Fixed
        Open/ClosedOpen Closed
    2017-05-18 rik5 Attached File- Added bug50893.cset, #40730
        StatusConfirmed Patch Submitted
    2017-04-28 jwe Item GroupMatlab Compatibility WTF, Matlab?!?
    2017-04-28 rik5 CategoryNone Interpreter
        Severity3 - Normal 2 - Minor
        Priority5 - Normal 3 - Low
        Item GroupNone Matlab Compatibility
        StatusNone Confirmed

    Back to the top

    Powered by Savane 3.13-f8d8.
    Corresponding source code