bugGNU Octave - Bugs: bug #67255, containers.Map reports error when...

 
 

bug #67255: containers.Map reports error when creating empty string key

Submitter:  None
Submitted:  Sat 28 Jun 2025 02:16:52 AM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Regression
Status:  Fixed Assigned to:  None
Originator Name:  Nathan Thern Originator Email:  -email is unavailable-
Open/Closed:  * Closed Release:  * 7.1.0
Release:  Operating System:  * Any
Fixed Release:  None Planned Release:  10.3.0 (current stable)
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Sat 12 Jul 2025 07:19:38 PM UTC, comment #13: 

Verified change.  Marking Bug as Fixed and closing report.

Rik <rik5>
Group administrator
Wed 09 Jul 2025 02:06:19 PM UTC, comment #12: 

Thank you for your patches.

Given that it is already possible in Octave to create structures with fields with the empty string as their name, it is fair that this should also be possible using other functions that construct structures.

Both your changes look good to me. The first one doesn't introduce fundamentally new features. It "just" brings `struct` in line with creating fields with the `.()`-index-operator. So, I think it is fine to go on the stable branch.
With that in place, the second branch fixes a regression since Octave 6.3.0 without affecting existing code. So, I think it is also fine for the stable branch.

I pushed both patches to the stable branch:
https://hg.savannah.gnu.org/hgweb/octave/rev/bb0346fc83de
https://hg.savannah.gnu.org/hgweb/octave/rev/287bfec002f5

They should be part of Octave 10.3.0 when it will be released.

Marking as ready for test.

Markus Mützel <mmuetzel>
Group administrator
Sun 06 Jul 2025 08:48:37 AM UTC, comment #11: 

I found another related problem using multi-row char arrays as Map keys. I filed bug #67283.

Fernando <tutissanalio>
Sat 05 Jul 2025 04:59:18 PM UTC, comment #10: 

I agree with @natethern that Matlab documentation considers that any char array, and in particular '', is a valid Map key.

I attach two patches to make Map support empty char arrays as keys:
- bug67255-1.cset: allows empty field names in struct and cell2struct functions.
- bug67255-2.cset: allows empty char arrays as keys of Maps.

I also added some BISTs.

(file #57365, file #57366)

Fernando <tutissanalio>
Mon 30 Jun 2025 07:34:11 PM UTC, comment #9: 

I did not think I would learn so much by submitting a bug report ... thanks gurus.

The following is not to teach, but just document what I learned (My Matlab version is R2023b):

Matlab strings and character vectors are not the same.

>> class("test")
ans =
    'string'
>> class('test')
ans =
    'char'
>> size("")
ans =
     1     1
>> size('')
ans =
     0     0


Google AI says the following when asked "matlab is empty string a valid character vector"

In MATLAB, an empty string is NOT a valid character vector, in the traditional sense of a 1-by- n array of characters. While an empty string, specified by "", contains zero characters, it is a 1-by-1 string scalar.
Here's a breakdown:

    Character Vector (''): A character vector (often denoted as a char array) is defined as a 1-by-n array of characters, where n is the number of characters. An empty character vector ('') is a 0-by-0 character array, meaning it has zero rows and zero columns. When you use isempty(''), it returns true because it is an empty array.
    Empty String (""): An empty string is a string scalar that contains zero characters. Although it has no characters, it still has a size of 1-by-1. Therefore, when you use isempty(""), it returns false because it is not an empty array.

In summary:

    Empty character vector (''): A 0-by-0 array, considered empty by isempty.
    Empty string (""): A 1-by-1 string scalar with no characters, not considered empty by isempty.


Beware the source, but it appears to be correct.

It's not explicitly stated so in the documentation, but containers.Map keys must all be the same type

>> myMap = containers.Map({ 'x', 'y', 22 }, {1,2,3}, 'UniformValues', false)
Error using containers.Map
The specified keys must all be of the same data type.
>>


The valid key types ARE documented

'char' (default) | 'double' | 'single' | 'int32' | 'uint32' | 'int64' | 'uint64'


So, '' is a 0-by-0 character vector which Matlab allows as a valid key to containers.Map
Not sure if that gets any closer to @philipnienhuis' "properly and officially documented behavior" or not.


Nate Thern <natethern>
Mon 30 Jun 2025 05:00:34 PM UTC, comment #8: 

@Philip:
In Matlab's documentation, I haven't found any reference to empty strings (or char arrays) being used as Map keys, but I don't see why they should not be valid. A different matter is using an empty string as a struct field name.

Fernando <tutissanalio>
Mon 30 Jun 2025 04:45:48 PM UTC, comment #7: 

It turns out that Matlab is much more restrictive that Octave, as far as struct field names are concerned. According to https://www.mathworks.com/help/releases/R2024b/matlab/ref/struct.html:

"Field names can contain ASCII letters (A–Z, a–z), digits (0–9), and underscores, and must begin with a letter. The maximum length of a field name is namelengthmax."

In Octave, pretty much anything can be a struct field name, and current Map implementation takes advantage of that. If we are happy with that, then we can just solve the (hopefully small) problems we have with empty strings as struct field names. I am having a look at it.

Fernando <tutissanalio>
Mon 30 Jun 2025 03:38:24 PM UTC, comment #6: 

(accidentally changed field "Operating system").

@Markus:
The question as to whether it (= using empty string as key in 'containers.Map') is documented Matlab behavior is still open, right?
I no longer have access to Matlab so I can't check.

Philip Nienhuis <philipnienhuis>
Group Member
Mon 30 Jun 2025 08:39:00 AM UTC, comment #5: 

Fwiw, in MATLAB R2025a:

>> myMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
>> myMap('') = 'hello'

myMap =

  Map with properties:

        Count: 1
      KeyType: char
    ValueType: any

>>


So, even if structs with empty field names aren't supported, using the empty string as a key in `containers.Map` is valid in Matlab.
Potentially, they aren't using structures to store the data for maps. So, if one fails, it doesn't necessarily mean that the other also fails.

Octave on the other hand uses structures internally to store the data for `containers.Map`.
If we'd like to support empty strings as the key, we might need to review that design decision for the implementation in Octave.

Markus Mützel <mmuetzel>
Group administrator
Mon 30 Jun 2025 08:29:10 AM UTC, comment #4: 


> ... some legacy Matlab code which relies on this behavior (being able to create a map key that is an empty string)

Is or was that behavior you refer to documented for Matlab?
Indeed, one of the Octave goals is Matlab compatibility but only for properly and officially documented behavior. If Octave happens to be compatible with undocumented Matlab behavior, that is usually by mere coincidence.

AFAIU the last lines of comment #2, 'this behavior' isn't allowed in recent Matlab anyway.

Philip Nienhuis <philipnienhuis>
Group Member
Sun 29 Jun 2025 07:02:03 PM UTC, comment #3: 

I have some legacy Matlab code which relies on this behavior (being able to create a map key that is an empty string). It creates trees of association lists where, if the desired key is not found in an outer branch then the '' key contains an inner-level containers.Map to search.

I agree that, in general, empty strings as map or struct keys is not a good idea. I am going to re-write the code because it's not an extensive fix and also because I want it to work in existing Octave installs. I submitted the bug report because I know that Matlab compatibility is a goal of Octave.


Nate Thern <natethern>
Sat 28 Jun 2025 04:49:09 PM UTC, comment #2: 

I can confirm this with current dev.

Looking at Map.m, I see the Map object stores the information internally as a struct, where the field names are the Map keys. Thus, an empty-string key results in a struct with an empty field name, which is strange, and causes problems when constructing the struct, or reconstructing it after reordering. In particular, cell2struct does not work with empty field names, e.g.:


octave:21> cell2struct({3},{''})
error: cell2struct: FIELDS must be a cell array of strings or a scalar string


This is easy to fix:


diff -r da698895c3bc libinterp/octave-value/ov-struct.cc
--- a/libinterp/octave-value/ov-struct.cc       Tue Jun 24 16:17:35 2025 -0400
+++ b/libinterp/octave-value/ov-struct.cc       Sat Jun 28 18:41:54 2025 +0200
@@ -2085,7 +2085,7 @@
         {
           const octave_value val = c(i);

-          if (! val.is_string () || val.rows () != 1)
+          if (! val.is_string () || val.rows () > 1)
             invalid_cell2struct_fields_error ();

           retval(i) = c(i).string_value ();


but using empty field names for structs is still strange, and I'm not sure if it should be allowed. E.g. you cannot create such a struct with the struct function:


octave:22> struct('',{3})
error: struct: second argument should be a cell array of field names


You can create it this way

octave:24> x.('')=3
x =
  scalar structure containing the fields:
     = 3


Matlab (R2024b) does not allow to construct structs with empty field names.


>> x.('')=3
Invalid field name: ''.


Fernando <tutissanalio>
Sat 28 Jun 2025 03:00:59 PM UTC, comment #1: 

I'm the author of this bug report. I have now created an account.

Nate Thern <natethern>
Sat 28 Jun 2025 02:16:52 AM UTC, original submission:  

I get the correct behavior when using Octave version 6.4.0:


octave:1> myMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
octave:2> myMap('') = 'hello'
myMap =

  containers.Map object with properties:

    Count     : 1
    KeyType   : char
    ValueType : any


octave:3>


However, when using Octave version 7.1.0 (and 8.4.0 which I have on another computer) I get an error:


octave:1> myMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
octave:2> myMap('') = 'hello'
error: cell2struct: FIELDS must be a cell array of strings or a scalar string
error: called from
    orderfields at line 158 column 8
    sort_keys at line 566 column 16
    subsasgn at line 474 column 18
octave:3>


The error also occurs when invoking the constructor with initial values:


octave:1> myMap = containers.Map({ 'x', 'y', '' }, {1,2,3}, 'UniformValues', false)
error: cell2struct: FIELDS must be a cell array of strings or a scalar string
error: called from
    Map at line 217 column 18
octave:1>


Interestingly, a second attempt to create an empty string key will succeed for a pre-existing containers.Map object:


octave:1> myMap = containers.Map('KeyType', 'char', 'ValueType', 'any');
octave:2> myMap('') = 'hello'
error: cell2struct: FIELDS must be a cell array of strings or a scalar string
error: called from
    orderfields at line 158 column 8
    sort_keys at line 566 column 16
    subsasgn at line 474 column 18
octave:3> myMap('') = 'hello'
myMap =

  containers.Map object with properties:

    Count     : 1
    KeyType   : char
    ValueType : any


octave:4>


Anonymous

 

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

Attach Files:
   
   
Comment:
   

Attached Files
file #57365:  bug67255-1.cset added by tutissanalio (3KiB - application/octet-stream)
file #57366:  bug67255-2.cset added by tutissanalio (2KiB - 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 rik5 (Posted a comment)
  • -email is unavailable- added by mmuetzel (Posted a comment)
  • -email is unavailable- added by philipnienhuis (Posted a comment)
  • -email is unavailable- added by tutissanalio (Posted a comment)
  • -email is unavailable- added by natethern (Posted a comment)
  • -email is unavailable- added by None (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
    19:19 rik5 StatusReady For Test Fixed
        Open/ClosedOpen Closed
    2025-07-09 mmuetzel StatusNone Ready For Test
        Planned ReleaseNone 10.3.0 (current stable)
    2025-07-05 tutissanalio Attached File- Added bug67255-1.cset, #57365
        Attached File- Added bug67255-2.cset, #57366
    2025-06-30 philipnienhuis Operating SystemGNU/Linux Any
    2025-06-30 philipnienhuis StatusConfirmed None
        Operating SystemAny GNU/Linux
    2025-06-30 mmuetzel StatusNone Confirmed
        Operating SystemGNU/Linux Any

    Back to the top

    Powered by Savane 3.15-e6e5.
    Corresponding source code