Unexpected results when adding & removing fields to empty structs

View: New views
10 Messages — Rating Filter:   Alert me  

Unexpected results when adding & removing fields to empty structs

by Philip Nienhuis :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

<Apologies if the issues below are just ignorance or stupidity on my part)

<System: Octave 3.2.3 MingW (sourceforge binary), Windows XP SP3>

Adding fields to empty structs doesn't seem to work:

octave-3.2.3.exe: #1 > aa = struct("field1", {})
aa =
{
   0x0 struct array containing the fields:

     field1
}

octave-3.2.3.exe: #2 > [aa.field2] = {}
aa =
{
   0x0 struct array containing the fields:

     field1
}

===> No field2 to be seen in struct aa
(This works OK on Matlab r2007a, if that's any reference :-) )

.....while.....

octave-3.2.3.exe: #3 > cc = struct("field1", {})
cc =
{
   0x0 struct array containing the fields:

     field1
}

octave-3.2.3.exe: #4 > [cc(1).field2]= {}
cc =
{
   field1 = [](0x0)
   field2 = {}(0x0)
}

but now the fields contain (empty) values. Note that field1 has been
"extended" with [] rather than {}.
I suppose this last example is intended behavior as adding elements to
all fields in a struct (extending the "field size") always goes like (at
least on my box)
          struct(size(struct, 2) + 1).a_field = {anything}
where field1 was initially empty (zero size) but an (empty) element was
added implicitly due to the operation of adding another field.

But:

octave-3.2.3.exe: #5 > [cc.field3]= {}
cc =
{
   field1 = [](0x0)
   field2 = {}(0x0)
field3 = {}(0x0)
}

octave-3.2.3.exe: #7 > [cc(1).field4]= {}
cc =
{
   field1 = [](0x0)
   field2 = {}(0x0)
field3 = {}(0x0)
field4 = {}(0x0)
}

where the layout seems to be mixed up.
Furthermore, continuing with cc:

octave-3.2.3.exe: #8 > rmfield(cc, "field3")
ans =
{
   field1 = [](0x0)
   field2 = {}(0x0)
field4 = {}(0x0)
}

octave-3.2.3.exe: #9 > rmfield(cc, "field2")
ans =
{
   field1 = [](0x0)
   field3 = {}(0x0)
field4 = {}(0x0)
}

octave-3.2.3.exe: #10 > rmfield(cc, "field3")
ans =
{
   field1 = [](0x0)
   field2 = {}(0x0)
field4 = {}(0x0)
}
where "field3" and "field2" magically but unintendedly reappear.


On a related note (empty lines skipped for brevity):

octave-3.2.3.exe: #93 > AA = struct()
AA =
{
}
octave-3.2.3.exe: #94 > size (AA)
ans =
    1   1                             ## ??
octave-3.2.3.exe: #95 > isempty (AA)
ans = 0                              ## !! but in line with size(aa)

    === while ====

octave-3.2.3.exe: #96 > BB = struct("field1", {})
BB =
{
   0x0 struct array containing the fields:
     field1
}
octave-3.2.3.exe: #97 > size (BB)
ans =
    0   0                             ## !?
octave-3.2.3.exe: #98 > isempty (BB)
ans =  1                             ## ?! again in line with size(bb)

The results of size() and isempty() on AA and BB are IMO contrary to
expectation. (But... fully Matlab r2007a-compatible!)

Is this somehow logical (but beyond my sense for logic) or is it too far
pursued Matlab compatibility?


Thank you,

Philip
_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:

> <Apologies if the issues below are just ignorance or stupidity on my part)
>
> <System: Octave 3.2.3 MingW (sourceforge binary), Windows XP SP3>
>
> Adding fields to empty structs doesn't seem to work:
>
> octave-3.2.3.exe: #1 > aa = struct("field1", {})
> aa =
> {
>   0x0 struct array containing the fields:
>
>     field1
> }
>
> octave-3.2.3.exe: #2 > [aa.field2] = {}
> aa =
> {
>   0x0 struct array containing the fields:
>
>     field1
> }
>
> ===> No field2 to be seen in struct aa
> (This works OK on Matlab r2007a, if that's any reference :-) )
>

[aa.field2] when aa is sempty resolves to an empty cs-list, so there's
nothing to assign (excess rhs values are discarded). Apparently Matlab
carries out the empty assignments for possible side effects, while
Octave simply skips them. For compatibility, here's a patch:

> .....while.....
>
> octave-3.2.3.exe: #3 > cc = struct("field1", {})
> cc =
> {
>   0x0 struct array containing the fields:
>
>     field1
> }
>
> octave-3.2.3.exe: #4 > [cc(1).field2]= {}
> cc =
> {
>   field1 = [](0x0)
>   field2 = {}(0x0)
> }
>
> but now the fields contain (empty) values. Note that field1 has been
> "extended" with [] rather than {}.
> I suppose this last example is intended behavior as adding elements to
> all fields in a struct (extending the "field size") always goes like (at
> least on my box)
>          struct(size(struct, 2) + 1).a_field = {anything}
> where field1 was initially empty (zero size) but an (empty) element was
> added implicitly due to the operation of adding another field.
>

Yep, that is correct.

> But:
>
> octave-3.2.3.exe: #5 > [cc.field3]= {}
> cc =
> {
>   field1 = [](0x0)
>   field2 = {}(0x0)
> field3 = {}(0x0)
> }
>
> octave-3.2.3.exe: #7 > [cc(1).field4]= {}
> cc =
> {
>   field1 = [](0x0)
>   field2 = {}(0x0)
> field3 = {}(0x0)
> field4 = {}(0x0)
> }
>
> where the layout seems to be mixed up.

Another bug.
See


> Furthermore, continuing with cc:
>
> octave-3.2.3.exe: #8 > rmfield(cc, "field3")
> ans =
> {
>   field1 = [](0x0)
>   field2 = {}(0x0)
> field4 = {}(0x0)
> }
>
> octave-3.2.3.exe: #9 > rmfield(cc, "field2")
> ans =
> {
>   field1 = [](0x0)
>   field3 = {}(0x0)
> field4 = {}(0x0)
> }
>
> octave-3.2.3.exe: #10 > rmfield(cc, "field3")
> ans =
> {
>   field1 = [](0x0)
>   field2 = {}(0x0)
> field4 = {}(0x0)
> }
> where "field3" and "field2" magically but unintendedly reappear.
>

This is a mix-up of the "your ignorance" case and Octave's sometimes
too succint documentation. While the docstring for rmfield might give
you the impression that
rmfield(cc, "field3")
removes the field3 from cc, but this is not true. Remember (and this
is written in the manual) that Octave functions, be them built-in or
user scripts, *never* alter their arguments. There is no passing by
reference. When you pass a variable as a function argument, it behaves
*as if* a copy was made for all the values (in reality it's a lazy
copy). This very simple and natural scheme frees the Matlab language
of the object ownership problems seen, for instance, in Python or C#,
at the cost of sometimes sacrificing memory efficiency.

rmfield does, in fact take a copy of the argument, remove the named
field from that copy and return the result, so
cc = rmfield (cc, "field3");
is what you want. In the docstrings this is often not emphasized
because it's assumed to be a general principle.

>
> On a related note (empty lines skipped for brevity):
>
> octave-3.2.3.exe: #93 > AA = struct()
> AA =
> {
> }
> octave-3.2.3.exe: #94 > size (AA)
> ans =
>    1   1                             ## ??
> octave-3.2.3.exe: #95 > isempty (AA)
> ans = 0                              ## !! but in line with size(aa)
>
>    === while ====
>
> octave-3.2.3.exe: #96 > BB = struct("field1", {})
> BB =
> {
>   0x0 struct array containing the fields:
>     field1
> }
> octave-3.2.3.exe: #97 > size (BB)
> ans =
>    0   0                             ## !?
> octave-3.2.3.exe: #98 > isempty (BB)
> ans =  1                             ## ?! again in line with size(bb)
>
> The results of size() and isempty() on AA and BB are IMO contrary to
> expectation. (But... fully Matlab r2007a-compatible!)
>
> Is this somehow logical (but beyond my sense for logic) or is it too far
> pursued Matlab compatibility?
>

It's logical. isempty simply tests whether any dimension is zero; it
doesn't test for the number of fields. Structs with no fields are not
much useful anyway, so I'd expect them to be very rare.

>
> Thank you,
>
> Philip
> _______________________________________________
> Bug-octave mailing list
> Bug-octave@...
> https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave
>



--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Nov 6, 2009 at 10:31 AM, Jaroslav Hajek <highegg@...> wrote:

> On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>> <Apologies if the issues below are just ignorance or stupidity on my part)
>>
>> <System: Octave 3.2.3 MingW (sourceforge binary), Windows XP SP3>
>>
>> Adding fields to empty structs doesn't seem to work:
>>
>> octave-3.2.3.exe: #1 > aa = struct("field1", {})
>> aa =
>> {
>>   0x0 struct array containing the fields:
>>
>>     field1
>> }
>>
>> octave-3.2.3.exe: #2 > [aa.field2] = {}
>> aa =
>> {
>>   0x0 struct array containing the fields:
>>
>>     field1
>> }
>>
>> ===> No field2 to be seen in struct aa
>> (This works OK on Matlab r2007a, if that's any reference :-) )
>>
>
> [aa.field2] when aa is sempty resolves to an empty cs-list, so there's
> nothing to assign (excess rhs values are discarded). Apparently Matlab
> carries out the empty assignments for possible side effects, while
> Octave simply skips them. For compatibility, here's a patch:
>
>> .....while.....
>>
>> octave-3.2.3.exe: #3 > cc = struct("field1", {})
>> cc =
>> {
>>   0x0 struct array containing the fields:
>>
>>     field1
>> }
>>
>> octave-3.2.3.exe: #4 > [cc(1).field2]= {}
>> cc =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> }
>>
>> but now the fields contain (empty) values. Note that field1 has been
>> "extended" with [] rather than {}.
>> I suppose this last example is intended behavior as adding elements to
>> all fields in a struct (extending the "field size") always goes like (at
>> least on my box)
>>          struct(size(struct, 2) + 1).a_field = {anything}
>> where field1 was initially empty (zero size) but an (empty) element was
>> added implicitly due to the operation of adding another field.
>>
>
> Yep, that is correct.
>
>> But:
>>
>> octave-3.2.3.exe: #5 > [cc.field3]= {}
>> cc =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> field3 = {}(0x0)
>> }
>>
>> octave-3.2.3.exe: #7 > [cc(1).field4]= {}
>> cc =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> field3 = {}(0x0)
>> field4 = {}(0x0)
>> }
>>
>> where the layout seems to be mixed up.
>
> Another bug.
> See
>
>
>> Furthermore, continuing with cc:
>>
>> octave-3.2.3.exe: #8 > rmfield(cc, "field3")
>> ans =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> field4 = {}(0x0)
>> }
>>
>> octave-3.2.3.exe: #9 > rmfield(cc, "field2")
>> ans =
>> {
>>   field1 = [](0x0)
>>   field3 = {}(0x0)
>> field4 = {}(0x0)
>> }
>>
>> octave-3.2.3.exe: #10 > rmfield(cc, "field3")
>> ans =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> field4 = {}(0x0)
>> }
>> where "field3" and "field2" magically but unintendedly reappear.
>>
>
> This is a mix-up of the "your ignorance" case and Octave's sometimes
> too succint documentation. While the docstring for rmfield might give
> you the impression that
> rmfield(cc, "field3")
> removes the field3 from cc, but this is not true. Remember (and this
> is written in the manual) that Octave functions, be them built-in or
> user scripts, *never* alter their arguments. There is no passing by
> reference. When you pass a variable as a function argument, it behaves
> *as if* a copy was made for all the values (in reality it's a lazy
> copy). This very simple and natural scheme frees the Matlab language
> of the object ownership problems seen, for instance, in Python or C#,
> at the cost of sometimes sacrificing memory efficiency.
>
> rmfield does, in fact take a copy of the argument, remove the named
> field from that copy and return the result, so
> cc = rmfield (cc, "field3");
> is what you want. In the docstrings this is often not emphasized
> because it's assumed to be a general principle.
>
>>
>> On a related note (empty lines skipped for brevity):
>>
>> octave-3.2.3.exe: #93 > AA = struct()
>> AA =
>> {
>> }
>> octave-3.2.3.exe: #94 > size (AA)
>> ans =
>>    1   1                             ## ??
>> octave-3.2.3.exe: #95 > isempty (AA)
>> ans = 0                              ## !! but in line with size(aa)
>>
>>    === while ====
>>
>> octave-3.2.3.exe: #96 > BB = struct("field1", {})
>> BB =
>> {
>>   0x0 struct array containing the fields:
>>     field1
>> }
>> octave-3.2.3.exe: #97 > size (BB)
>> ans =
>>    0   0                             ## !?
>> octave-3.2.3.exe: #98 > isempty (BB)
>> ans =  1                             ## ?! again in line with size(bb)
>>
>> The results of size() and isempty() on AA and BB are IMO contrary to
>> expectation. (But... fully Matlab r2007a-compatible!)
>>
>> Is this somehow logical (but beyond my sense for logic) or is it too far
>> pursued Matlab compatibility?
>>
>
> It's logical. isempty simply tests whether any dimension is zero; it
> doesn't test for the number of fields. Structs with no fields are not
> much useful anyway, so I'd expect them to be very rare.
>
>>
>> Thank you,
>>
>> Philip
>> _______________________________________________
>> Bug-octave mailing list
>> Bug-octave@...
>> https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave
>>
>
>
>
> --
> RNDr. Jaroslav Hajek
> computing expert & GNU Octave developer
> Aeronautical Research and Test Institute (VZLU)
> Prague, Czech Republic
> url: www.highegg.matfyz.cz
>

Oops, I forgot to hyperlink the patches:
http://hg.savannah.gnu.org/hgweb/octave/rev/eead00a7df05
http://hg.savannah.gnu.org/hgweb/octave/rev/ea88eece12f5

regards

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Philip Nienhuis :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jaroslav Hajek wrote:
> On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>> <Apologies if the issues below are just ignorance or stupidity on my part)
>>
>> <System: Octave 3.2.3 MingW (sourceforge binary), Windows XP SP3>
>>
>> Adding fields to empty structs doesn't seem to work:
>>
>> octave-3.2.3.exe: #1 > aa = struct("field1", {})
 >> aa =
 >> {
 >>   0x0 struct array containing the fields:
 >>
 >>     field1
 >> }
 >>
 >> octave-3.2.3.exe: #2 > [aa.field2] = {}
 >> aa =
 >> {
 >>   0x0 struct array containing the fields:
 >>
 >>     field1
 >> }
 >>
 >> ===> No field2 to be seen in struct aa
:
<snip>
:
> [aa.field2] when aa is sempty resolves to an empty cs-list, so there's
> nothing to assign (excess rhs values are discarded). Apparently Matlab
> carries out the empty assignments for possible side effects, while
> Octave simply skips them. For compatibility, here's a patch:

Thank you.

<snip>
:

>> octave-3.2.3.exe: #9 > rmfield(cc, "field2")
>> ans =
>> {
>>   field1 = [](0x0)
>>   field3 = {}(0x0)
>> field4 = {}(0x0)
>> }
>>
>> octave-3.2.3.exe: #10 > rmfield(cc, "field3")
>> ans =
>> {
>>   field1 = [](0x0)
>>   field2 = {}(0x0)
>> field4 = {}(0x0)
>> }
>> where "field3" and "field2" magically but unintendedly reappear.
>>
>
> This is a mix-up of the "your ignorance" case and Octave's sometimes
> too succint documentation. While the docstring for rmfield might give
> you the impression that
> rmfield(cc, "field3")
> removes the field3 from cc, but this is not true. Remember (and this
> is written in the manual) that Octave functions, be them built-in or
> user scripts, *never* alter their arguments. There is no passing by
> reference. When you pass a variable as a function argument, it behaves
> *as if* a copy was made for all the values (in reality it's a lazy
> copy). This very simple and natural scheme frees the Matlab language
> of the object ownership problems seen, for instance, in Python or C#,
> at the cost of sometimes sacrificing memory efficiency.
>
> rmfield does, in fact take a copy of the argument, remove the named
> field from that copy and return the result, so
> cc = rmfield (cc, "field3");
> is what you want. In the docstrings this is often not emphasized
> because it's assumed to be a general principle.

<blush> Yeah I should have realized this, sorry.
I might have been distracted because removing fields from structures
works through a function rmfield(), while adding fields only works
through assignment
      [struct(:).newfield] = deal({cells}{:})
which does change the original.
Part of my original bug report was motivated by all kind of corner cases
with empty structs. To avoid having to repeatedly beware & take care of
such cases I've created a script around this for my own use, because
invoking something like:

    new_s = addfield (old_s, "nfield", [optional values])

is IMO a little more obvious than the assignment syntax above + variants
for exceptions.

BTW if anyone thinks such a script is useful for other octave users I'll
happily contribute it (here or for octave-forge)

>
>> On a related note (empty lines skipped for brevity):
>>
>> octave-3.2.3.exe: #93 > AA = struct()
>> AA =
>> {
>> }
>> octave-3.2.3.exe: #96 > BB = struct("field1", {})
:
<snip>
>> BB =
>> {
>>   0x0 struct array containing the fields:
>>     field1
>> }
:
<snip>

>> The results of size() and isempty() on AA and BB are IMO contrary to
>> expectation. (But... fully Matlab r2007a-compatible!)
>>
>> Is this somehow logical (but beyond my sense for logic) or is it too far
>> pursued Matlab compatibility?
>>
>
> It's logical. isempty simply tests whether any dimension is zero; it
> doesn't test for the number of fields. Structs with no fields are not
> much useful anyway, so I'd expect them to be very rare.

(How does size()work in such a case? that one seems to convey the wrong
info to isempty) )
Well, it's logical in the sense of "how octave works internally". Still
I think it's a bit inconsistent from a user's point of view. A struct
with no fields has "no dimensions" to test at all so should be reported
"empty" with size 0. IMO, of course :-)

Indeed such structs may not be that useful per se, but I can think of
automated scripts that could generate them and use them later on; I
think from an efficiency perspective such scripts should be saved from
having to test for too many corner cases, especially far-fetched ones.
To that end, behavior of operations like size() and isempty() should be
as consistent as reasonably possible.
But assigning extra burden to very-often-used functions for the sake of
some rarely encountered cases might not be very sensible either.

And -again- Matlab (used preferrably at my employer's office) doesn't do
any better in this case.

Anyway, thank you for your answer & patches.
As I'm not in core octave development I suppose I'll have to wait until
a next stable binary :-( (but I'm glad some stuff is solved already).

Philip
_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Fri, Nov 6, 2009 at 9:56 PM, Philip Nienhuis <pr.nienhuis@...> wrote:

> Jaroslav Hajek wrote:
>> On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>>> <Apologies if the issues below are just ignorance or stupidity on my part)
>>>
>>> <System: Octave 3.2.3 MingW (sourceforge binary), Windows XP SP3>
>>>
>>> Adding fields to empty structs doesn't seem to work:
>>>
>>> octave-3.2.3.exe: #1 > aa = struct("field1", {})
>  >> aa =
>  >> {
>  >>   0x0 struct array containing the fields:
>  >>
>  >>     field1
>  >> }
>  >>
>  >> octave-3.2.3.exe: #2 > [aa.field2] = {}
>  >> aa =
>  >> {
>  >>   0x0 struct array containing the fields:
>  >>
>  >>     field1
>  >> }
>  >>
>  >> ===> No field2 to be seen in struct aa
> :
> <snip>
> :
>> [aa.field2] when aa is sempty resolves to an empty cs-list, so there's
>> nothing to assign (excess rhs values are discarded). Apparently Matlab
>> carries out the empty assignments for possible side effects, while
>> Octave simply skips them. For compatibility, here's a patch:
>
> Thank you.
>
> <snip>
> :
>>> octave-3.2.3.exe: #9 > rmfield(cc, "field2")
>>> ans =
>>> {
>>>   field1 = [](0x0)
>>>   field3 = {}(0x0)
>>> field4 = {}(0x0)
>>> }
>>>
>>> octave-3.2.3.exe: #10 > rmfield(cc, "field3")
>>> ans =
>>> {
>>>   field1 = [](0x0)
>>>   field2 = {}(0x0)
>>> field4 = {}(0x0)
>>> }
>>> where "field3" and "field2" magically but unintendedly reappear.
>>>
>>
>> This is a mix-up of the "your ignorance" case and Octave's sometimes
>> too succint documentation. While the docstring for rmfield might give
>> you the impression that
>> rmfield(cc, "field3")
>> removes the field3 from cc, but this is not true. Remember (and this
>> is written in the manual) that Octave functions, be them built-in or
>> user scripts, *never* alter their arguments. There is no passing by
>> reference. When you pass a variable as a function argument, it behaves
>> *as if* a copy was made for all the values (in reality it's a lazy
>> copy). This very simple and natural scheme frees the Matlab language
>> of the object ownership problems seen, for instance, in Python or C#,
>> at the cost of sometimes sacrificing memory efficiency.
>>
>> rmfield does, in fact take a copy of the argument, remove the named
>> field from that copy and return the result, so
>> cc = rmfield (cc, "field3");
>> is what you want. In the docstrings this is often not emphasized
>> because it's assumed to be a general principle.
>
> <blush> Yeah I should have realized this, sorry.
> I might have been distracted because removing fields from structures
> works through a function rmfield(), while adding fields only works
> through assignment
>      [struct(:).newfield] = deal({cells}{:})
> which does change the original.
> Part of my original bug report was motivated by all kind of corner cases
> with empty structs. To avoid having to repeatedly beware & take care of
> such cases I've created a script around this for my own use, because
> invoking something like:
>
>    new_s = addfield (old_s, "nfield", [optional values])
>
> is IMO a little more obvious than the assignment syntax above + variants
> for exceptions.
>

How would that differ from setfield?

> BTW if anyone thinks such a script is useful for other octave users I'll
> happily contribute it (here or for octave-forge)
>
>>
>>> On a related note (empty lines skipped for brevity):
>>>
>>> octave-3.2.3.exe: #93 > AA = struct()
>>> AA =
>>> {
>>> }
>>> octave-3.2.3.exe: #96 > BB = struct("field1", {})
> :
> <snip>
>>> BB =
>>> {
>>>   0x0 struct array containing the fields:
>>>     field1
>>> }
> :
> <snip>
>>> The results of size() and isempty() on AA and BB are IMO contrary to
>>> expectation. (But... fully Matlab r2007a-compatible!)
>>>
>>> Is this somehow logical (but beyond my sense for logic) or is it too far
>>> pursued Matlab compatibility?
>>>
>>
>> It's logical. isempty simply tests whether any dimension is zero; it
>> doesn't test for the number of fields. Structs with no fields are not
>> much useful anyway, so I'd expect them to be very rare.
>
> (How does size()work in such a case? that one seems to convey the wrong
> info to isempty) )
> Well, it's logical in the sense of "how octave works internally". Still
> I think it's a bit inconsistent from a user's point of view. A struct
> with no fields has "no dimensions" to test at all so should be reported
> "empty" with size 0. IMO, of course :-)
>

No, that is not true. The number of fields is simply an independent
property of the structure. You may also think of it as an extra
dimension. You can have structs with no fields but arbitrary
dimensions. Admittedly, what is really missing is a function to query
the number of fields, say, nfields (s). Currently one needs length
(fieldnames (s)).

> Indeed such structs may not be that useful per se, but I can think of
> automated scripts that could generate them and use them later on; I
> think from an efficiency perspective such scripts should be saved from
> having to test for too many corner cases, especially far-fetched ones.
> To that end, behavior of operations like size() and isempty() should be
> as consistent as reasonably possible.

Agreed. I think right now, it's quite consistent.

> But assigning extra burden to very-often-used functions for the sake of
> some rarely encountered cases might not be very sensible either.
>
> And -again- Matlab (used preferrably at my employer's office) doesn't do
> any better in this case.
>
> Anyway, thank you for your answer & patches.
> As I'm not in core octave development I suppose I'll have to wait until
> a next stable binary :-( (but I'm glad some stuff is solved already).
>

Surely you don't *have to* wait - you can download the sources right
now and build Octave from them.
http://hg.savannah.gnu.org/hgweb/octave

Honestly, setting up the build with all dependency libs is a
non-trivial task (at least if you want full functionality), but once
done, you can get new patches included very easily.

best regards

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Philip Nienhuis :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

(sorry for late response, my provider's email server was down for some days)

Jaroslav Hajek wrote:
> On Fri, Nov 6, 2009 at 9:56 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>> Jaroslav Hajek wrote:
>>> On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>>>> <Apologies if the issues below are just ignorance or stupidity on my part)
:
<long snip>

>>> This is a mix-up of the "your ignorance" case and Octave's sometimes
>>> too succint documentation. While the docstring for rmfield might give
>>> you the impression that
>>> rmfield(cc, "field3")
>>> removes the field3 from cc, but this is not true. Remember (and this
>>> is written in the manual) that Octave functions, be them built-in or
>>> user scripts, *never* alter their arguments. There is no passing by
>>> reference. When you pass a variable as a function argument, it behaves
>>> *as if* a copy was made for all the values (in reality it's a lazy
>>> copy). This very simple and natural scheme frees the Matlab language
>>> of the object ownership problems seen, for instance, in Python or C#,
>>> at the cost of sometimes sacrificing memory efficiency.
>>>
>>> rmfield does, in fact take a copy of the argument, remove the named
>>> field from that copy and return the result, so
>>> cc = rmfield (cc, "field3");
>>> is what you want. In the docstrings this is often not emphasized
>>> because it's assumed to be a general principle.
>> <blush> Yeah I should have realized this, sorry.
>> I might have been distracted because removing fields from structures
>> works through a function rmfield(), while adding fields only works
>> through assignment
>>      [struct(:).newfield] = deal({cells}{:})
>> which does change the original.
>> Part of my original bug report was motivated by all kind of corner cases
>> with empty structs. To avoid having to repeatedly beware & take care of
>> such cases I've created a script around this for my own use, because
>> invoking something like:
>>
>>    new_s = addfield (old_s, "nfield", [optional values])
>>
>> is IMO a little more obvious than the assignment syntax above + variants
>> for exceptions.
>>
>
> How would that differ from setfield?

* AFAICS & test, setfield() seems intended for assigning a value to
individual field elements, but only one element at a time (= per call).
Unless of course I again overlooked something. This becomes cumbersome
if one wants to add a somewhat larger array to all field elements in a
struct.

* (A wrapper script around) [s.f] = deal({cell_values}) assigns values
to all elements of a field in one swoop and can add fields too. But yes,
some fine-grainedness might be lost.

* And I think setfield's syntax isn't that obvious either; that is, the
help text could be more helpful.
A suggestion for an IMO more easily comprehensible example is attached -
just fit it in between the function call description and the example.
If you'd prefer I can send setfield.m with improved help section.

(You're right about sometimes too succinct octave docs. Admittedly only
after checking out Matlab's helpdesk it occurred to me how setfield
works. Hopefully my little addition may help others to avoid such a
surrender.)

<snip>

>>>> On a related note (empty lines skipped for brevity):
>>>>
>>>> octave-3.2.3.exe: #93 > AA = struct()
>>>> AA =
>>>> {
>>>> }
>>>> octave-3.2.3.exe: #96 > BB = struct("field1", {})
>> :
>> <snip>
>>>> BB =
>>>> {
>>>>   0x0 struct array containing the fields:
>>>>     field1
>>>> }
>> :
>> <snip>
>>>> The results of size() and isempty() on AA and BB are IMO contrary to
>>>> expectation. (But... fully Matlab r2007a-compatible!)
>>>>
>>>> Is this somehow logical (but beyond my sense for logic) or is it too far
>>>> pursued Matlab compatibility?
>>>>
>>> It's logical. isempty simply tests whether any dimension is zero; it
>>> doesn't test for the number of fields. Structs with no fields are not
>>> much useful anyway, so I'd expect them to be very rare.
>> (How does size()work in such a case? that one seems to convey the wrong
>> info to isempty) )

?

>> Well, it's logical in the sense of "how octave works internally". Still
>> I think it's a bit inconsistent from a user's point of view. A struct
>> with no fields has "no dimensions" to test at all so should be reported
>> "empty" with size 0. IMO, of course :-)
>>
>
> No, that is not true. The number of fields is simply an independent
> property of the structure. You may also think of it as an extra
> dimension. You can have structs with no fields but arbitrary
> dimensions. Admittedly, what is really missing is a function to query
> the number of fields, say, nfields (s). Currently one needs length
> (fieldnames (s)).

I was thinking more of size(s) yielding misleading info about empty
structs - perhaps because size(s) itself gets confused there.
Again, matlab does the same so why worry...

<snip>

>> As I'm not in core octave development I suppose I'll have to wait until
>> a next stable binary :-( (but I'm glad some stuff is solved already).
>>
>
> Surely you don't *have to* wait - you can download the sources right
> now and build Octave from them.
> http://hg.savannah.gnu.org/hgweb/octave
>
> Honestly, setting up the build with all dependency libs is a
> non-trivial task (at least if you want full functionality), but once
> done, you can get new patches included very easily.

Sure, I've done that for some time several years ago under linux and cygwin.

However nowadays I'm mostly confined to Windows so I would need a
MingW development setup first, and from what I've read so far that's
still a bit too challenging for me.

However my first priority is to get octave involved in procedures we'd
otherwise do with Matlab. That replacement-attempt doesn't quite go
without the odd fairly involved hitch. IOW it's non-trivial either :-)

Thanks,

Philip


_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On Wed, Nov 11, 2009 at 10:43 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
(sorry for late response, my provider's email server was down for some days)

Jaroslav Hajek wrote:
> On Fri, Nov 6, 2009 at 9:56 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>> Jaroslav Hajek wrote:
>>> On Thu, Nov 5, 2009 at 11:22 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
>>>> <Apologies if the issues below are just ignorance or stupidity on my part)
:
<long snip>
>>> This is a mix-up of the "your ignorance" case and Octave's sometimes
>>> too succint documentation. While the docstring for rmfield might give
>>> you the impression that
>>> rmfield(cc, "field3")
>>> removes the field3 from cc, but this is not true. Remember (and this
>>> is written in the manual) that Octave functions, be them built-in or
>>> user scripts, *never* alter their arguments. There is no passing by
>>> reference. When you pass a variable as a function argument, it behaves
>>> *as if* a copy was made for all the values (in reality it's a lazy
>>> copy). This very simple and natural scheme frees the Matlab language
>>> of the object ownership problems seen, for instance, in Python or C#,
>>> at the cost of sometimes sacrificing memory efficiency.
>>>
>>> rmfield does, in fact take a copy of the argument, remove the named
>>> field from that copy and return the result, so
>>> cc = rmfield (cc, "field3");
>>> is what you want. In the docstrings this is often not emphasized
>>> because it's assumed to be a general principle.
>> <blush> Yeah I should have realized this, sorry.
>> I might have been distracted because removing fields from structures
>> works through a function rmfield(), while adding fields only works
>> through assignment
>>      [struct(:).newfield] = deal({cells}{:})
>> which does change the original.
>> Part of my original bug report was motivated by all kind of corner cases
>> with empty structs. To avoid having to repeatedly beware & take care of
>> such cases I've created a script around this for my own use, because
>> invoking something like:
>>
>>    new_s = addfield (old_s, "nfield", [optional values])
>>
>> is IMO a little more obvious than the assignment syntax above + variants
>> for exceptions.
>>
>
> How would that differ from setfield?

* AFAICS & test, setfield() seems intended for assigning a value to
individual field elements, but only one element at a time (= per call).
Unless of course I again overlooked something. This becomes cumbersome
if one wants to add a somewhat larger array to all field elements in a
struct.

It seems you're right. Gosh, what a useless function.
 

* (A wrapper script around) [s.f] = deal({cell_values}) assigns values
to all elements of a field in one swoop and can add fields too. But yes,
some fine-grainedness might be lost.


Yes, that is the preferred way. You can even bypass deal and just do
[s.f] = c{:}
where c is a cell array.
 
* And I think setfield's syntax isn't that obvious either; that is, the
help text could be more helpful.
A suggestion for an IMO more easily comprehensible example is attached -
just fit it in between the function call description and the example.
If you'd prefer I can send setfield.m with improved help section.


Sorry, no attachment arrived.
 
(You're right about sometimes too succinct octave docs. Admittedly only
after checking out Matlab's helpdesk it occurred to me how setfield
works. Hopefully my little addition may help others to avoid such a
surrender.)

<snip>
>>>> On a related note (empty lines skipped for brevity):
>>>>
>>>> octave-3.2.3.exe: #93 > AA = struct()
>>>> AA =
>>>> {
>>>> }
>>>> octave-3.2.3.exe: #96 > BB = struct("field1", {})
>> :
>> <snip>
>>>> BB =
>>>> {
>>>>   0x0 struct array containing the fields:
>>>>     field1
>>>> }
>> :
>> <snip>
>>>> The results of size() and isempty() on AA and BB are IMO contrary to
>>>> expectation. (But... fully Matlab r2007a-compatible!)
>>>>
>>>> Is this somehow logical (but beyond my sense for logic) or is it too far
>>>> pursued Matlab compatibility?
>>>>
>>> It's logical. isempty simply tests whether any dimension is zero; it
>>> doesn't test for the number of fields. Structs with no fields are not
>>> much useful anyway, so I'd expect them to be very rare.
>> (How does size()work in such a case? that one seems to convey the wrong
>> info to isempty) )

?

>> Well, it's logical in the sense of "how octave works internally". Still
>> I think it's a bit inconsistent from a user's point of view. A struct
>> with no fields has "no dimensions" to test at all so should be reported
>> "empty" with size 0. IMO, of course :-)
>>
>
> No, that is not true. The number of fields is simply an independent
> property of the structure. You may also think of it as an extra
> dimension. You can have structs with no fields but arbitrary
> dimensions. Admittedly, what is really missing is a function to query
> the number of fields, say, nfields (s). Currently one needs length
> (fieldnames (s)).

I was thinking more of size(s) yielding misleading info about empty
structs - perhaps because size(s) itself gets confused there.

I don't know what you mean. size is not confused in any way - it just returns the correct dimensions. End of story.
Number of fields is not a dimension. FWIW, I added a nfields () function to Octave that can be used to get the number of fields.
 
Again, matlab does the same so why worry...

<snip>

>> As I'm not in core octave development I suppose I'll have to wait until
>> a next stable binary :-( (but I'm glad some stuff is solved already).
>>
>
> Surely you don't *have to* wait - you can download the sources right
> now and build Octave from them.
> http://hg.savannah.gnu.org/hgweb/octave
>
> Honestly, setting up the build with all dependency libs is a
> non-trivial task (at least if you want full functionality), but once
> done, you can get new patches included very easily.

Sure, I've done that for some time several years ago under linux and cygwin.

However nowadays I'm mostly confined to Windows so I would need a
MingW development setup first, and from what I've read so far that's
still a bit too challenging for me.

However my first priority is to get octave involved in procedures we'd
otherwise do with Matlab. That replacement-attempt doesn't quite go
without the odd fairly involved hitch. IOW it's non-trivial either :-)

Thanks,

Philip

Yes, the benefits must outweigh the costs for you. That's up to you to decide.

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Philip Nienhuis :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Jaroslav Hajek wrote:
>
>
> On Wed, Nov 11, 2009 at 10:43 PM, Philip Nienhuis <pr.nienhuis@...
> <mailto:pr.nienhuis@...>> wrote:
:
<snip>
:

>      >> invoking something like:
>      >>
>      >>    new_s = addfield (old_s, "nfield", [optional values])
>      >>
>      >> is IMO a little more obvious than the assignment syntax above +
>     variants
>      >> for exceptions.
>      >>
>      >
>      > How would that differ from setfield?
>
>     * AFAICS & test, setfield() seems intended for assigning a value to
>     individual field elements, but only one element at a time (= per call).
>     Unless of course I again overlooked something. This becomes cumbersome
>     if one wants to add a somewhat larger array to all field elements in a
>     struct.
>
> It seems you're right. Gosh, what a useless function.
If so, getfield() may also be superfluous.
But I'll hold my breath, perhaps both ARE useful for corner cases.
And, uhm, Matlab compatibility of course (is that a corner case?)

>     * (A wrapper script around) [s.f] = deal({cell_values}) assigns values
>     to all elements of a field in one swoop and can add fields too. But yes,
>     some fine-grainedness might be lost.
>
>
> Yes, that is the preferred way. You can even bypass deal and just do
> [s.f] = c{:}
> where c is a cell array.

... but I found that doesn't always work. Apart from deal() I sometimes
also needed (:) to the left of "=" like in [s(:).f] = deal(c{:})

To find out how to add fields to large structs & fill them
simultaneously I experimented a lot; the above syntax is what always
seemed to work OK - except for 1x1 and some empty structs. Which
provoked my original posting.

>     * And I think setfield's syntax isn't that obvious either; that is, the
>     help text could be more helpful.
>     A suggestion for an IMO more easily comprehensible example is attached -
>     just fit it in between the function call description and the example.
>     If you'd prefer I can send setfield.m with improved help section.
>
>
> Sorry, no attachment arrived.

Yes. sorry for that. Another try then.
I also attached some additional help text for rmfield() (that may also
benefit from additional info). As rmfield is built-in, I cannot adapt it
myself.

Philip


##
## Note: to remove fields in nested structs, specify the substruct at
## both sides of the "=" sign, e.g.:
## @example
## a.b.c = rmfield (a.b.c, "oldfld");
## @end example

## @example
## pp = struct ("f1", @{"a", 3@});
## pp = setfield (pp, @{1, 2@}, "f2", (8));
## pp.f2
## => ans = [](0x0)
##    ans =  8
## (which adds a field f2 to struct pp and assigns value 8
##  to the second element of pp.f2. The other elements of
##  pp.f2 will be filled with empty values)
## @end example
##
## Note: to add fields in nested structs, specify the substruct at
## both sides of the "=" sign, e.g.:
## @example
## a.b.c = setfield (a.b.c, @{2, 3@}, "nwfld", []);
## @end example
##
## A more complicated example:

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by Jaroslav Hajek-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message



On Thu, Nov 12, 2009 at 10:37 PM, Philip Nienhuis <pr.nienhuis@...> wrote:
Jaroslav Hajek wrote:


On Wed, Nov 11, 2009 at 10:43 PM, Philip Nienhuis <pr.nienhuis@... <mailto:pr.nienhuis@...>> wrote:
:
<snip>

:
    >> invoking something like:
    >>
    >>    new_s = addfield (old_s, "nfield", [optional values])
    >>
    >> is IMO a little more obvious than the assignment syntax above +
   variants
    >> for exceptions.
    >>
    >
    > How would that differ from setfield?

   * AFAICS & test, setfield() seems intended for assigning a value to
   individual field elements, but only one element at a time (= per call).
   Unless of course I again overlooked something. This becomes cumbersome
   if one wants to add a somewhat larger array to all field elements in a
   struct.

It seems you're right. Gosh, what a useless function.

If so, getfield() may also be superfluous.
But I'll hold my breath, perhaps both ARE useful for corner cases.
And, uhm, Matlab compatibility of course (is that a corner case?)


   * (A wrapper script around) [s.f] = deal({cell_values}) assigns values
   to all elements of a field in one swoop and can add fields too. But yes,
   some fine-grainedness might be lost.


Yes, that is the preferred way. You can even bypass deal and just do
[s.f] = c{:}
where c is a cell array.

... but I found that doesn't always work. Apart from deal() I sometimes also needed (:) to the left of "=" like in [s(:).f] = deal(c{:})


Sorry, but such comments (that something sometimes doesn't work) are virtually useless. Show me where it doesn't work and I'll either try to fix that or explain why it is so.
 
To find out how to add fields to large structs & fill them simultaneously I experimented a lot; the above syntax is what always seemed to work OK - except for 1x1 and some empty structs. Which provoked my original posting.


example? where it doesn't work?
 

   * And I think setfield's syntax isn't that obvious either; that is, the
   help text could be more helpful.
   A suggestion for an IMO more easily comprehensible example is attached -
   just fit it in between the function call description and the example.
   If you'd prefer I can send setfield.m with improved help section.


Sorry, no attachment arrived.

Yes. sorry for that. Another try then.
I also attached some additional help text for rmfield() (that may also benefit from additional info). As rmfield is built-in, I cannot adapt it myself.

Philip


##
## Note: to remove fields in nested structs, specify the substruct at
## both sides of the "=" sign, e.g.:
## @example
## a.b.c = rmfield (a.b.c, "oldfld");
## @end example

## @example
## pp = struct ("f1", @{"a", 3@});
## pp = setfield (pp, @{1, 2@}, "f2", (8));
## pp.f2
## => ans = [](0x0)
##    ans =  8
## (which adds a field f2 to struct pp and assigns value 8
##  to the second element of pp.f2. The other elements of
##  pp.f2 will be filled with empty values)
## @end example
##
## Note: to add fields in nested structs, specify the substruct at
## both sides of the "=" sign, e.g.:
## @example
## a.b.c = setfield (a.b.c, @{2, 3@}, "nwfld", []);
## @end example
##
## A more complicated example:

thanks.

--
RNDr. Jaroslav Hajek
computing expert & GNU Octave developer
Aeronautical Research and Test Institute (VZLU)
Prague, Czech Republic
url: www.highegg.matfyz.cz

_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave

Re: Unexpected results when adding & removing fields to empty structs

by John W. Eaton-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On 12-Nov-2009, Philip Nienhuis wrote:

| Jaroslav Hajek wrote:
| >
| > On Wed, Nov 11, 2009 at 10:43 PM, Philip Nienhuis <pr.nienhuis@...
| > <mailto:pr.nienhuis@...>> wrote:
| >
| >     * AFAICS & test, setfield() seems intended for assigning a value to
| >     individual field elements, but only one element at a time (= per call).
| >     Unless of course I again overlooked something. This becomes cumbersome
| >     if one wants to add a somewhat larger array to all field elements in a
| >     struct.
| >
| > It seems you're right. Gosh, what a useless function.
|
| If so, getfield() may also be superfluous.
| But I'll hold my breath, perhaps both ARE useful for corner cases.
| And, uhm, Matlab compatibility of course (is that a corner case?)

Before dynamic field name indexing was implemented in Matlab, setfield
and getfield were provided to allow structure fields to be accessed
without using eval when the field name is stored in a variable.  I
don't think they are really needed now, but are provided to avoid
breaking existing code that uses them.

jwe
_______________________________________________
Bug-octave mailing list
Bug-octave@...
https://www-old.cae.wisc.edu/mailman/listinfo/bug-octave