diff --git a/doc/ref/types.xml b/doc/ref/types.xml index 4367548ec1..c9671fc32e 100644 --- a/doc/ref/types.xml +++ b/doc/ref/types.xml @@ -485,7 +485,7 @@ except if the attribute had been specially constructed as mutable attribute.

It depends on the representation of an object (see ) -which attribute values it stores. An object in the representation +which attribute values it stores. An immutable object in the representation IsAttributeStoringRep stores all attribute values once they are computed. Moreover, for an object in this representation, subsequent calls to an attribute will return the same object; this is achieved @@ -496,6 +496,13 @@ value. (These methods are called the system setter and the system getter of the attribute, respectively.)system gettersystem setter

+Mutable objects in IsAttributeStoringRep are allowed, but +attribute values are not automatically stored in them. Such objects +are useful because values can be stored by explicitly calling the +relevant setter, and because they may later be made immutable using +, at which point they will start storing +all attribute values. +

Note also that it is impossible to get rid of a stored attribute value because the system may have drawn conclusions from the old attribute value, and just removing the value might leave the data @@ -568,7 +575,8 @@ of the object obj is known. For an attribute attr, Setter(attr) is called automatically when the attribute value has been -computed for the first time. +computed for an immutable object which does not already have a +value stored for attr. One can also call the setter explicitly, for example, Setter( Size )( obj, val ) sets val as size of the diff --git a/lib/sgpres.gi b/lib/sgpres.gi index abd8ed4c24..caadebe932 100644 --- a/lib/sgpres.gi +++ b/lib/sgpres.gi @@ -1081,6 +1081,9 @@ InstallGlobalFunction( PresentationAugmentedCosetTable, # group generators. SetPrimaryGeneratorWords(T,aug.primaryGeneratorWords); + # Since T is mutable, we must set this attribite "manually" + SetTzOptions(T, TzOptions(T)); + # handle relators of length 1 or 2, but do not eliminate any primary # generators. TzOptions(T).protected := tree[TR_PRIMARY]; diff --git a/lib/tietze.gi b/lib/tietze.gi index 60ab54795b..9489cdf7e2 100644 --- a/lib/tietze.gi +++ b/lib/tietze.gi @@ -381,6 +381,9 @@ InstallGlobalFunction( PresentationFpGroup, function ( arg ) SetOne(T,Identity( F )); T!.identity:=Identity( F ); + # since T is mutable, we must set this attribute "manually" + SetTzOptions(T,TzOptions(T)); + # initialize some Tietze options TzOptions(T).protected := 0; TzOptions(T).printLevel:=printlevel; diff --git a/src/opers.c b/src/opers.c index 299b7caa53..e392309cb3 100644 --- a/src/opers.c +++ b/src/opers.c @@ -2420,7 +2420,7 @@ Obj DoAttribute ( val = CopyObj( val, 0 ); /* set the value (but not for internal objects) */ - if ( ENABLED_ATTR( self ) == 1 ) { + if ( ENABLED_ATTR( self ) == 1 && !IS_MUTABLE_OBJ( obj ) ) { switch ( TNUM_OBJ( obj ) ) { case T_COMOBJ: case T_POSOBJ: @@ -2471,7 +2471,7 @@ static Obj DoVerboseAttribute(Obj self, Obj obj) val = CopyObj( val, 0 ); /* set the value (but not for internal objects) */ - if ( ENABLED_ATTR( self ) == 1 ) { + if ( ENABLED_ATTR( self ) == 1 && !IS_MUTABLE_OBJ( obj ) ) { switch ( TNUM_OBJ( obj ) ) { case T_COMOBJ: case T_POSOBJ: @@ -2516,7 +2516,7 @@ static Obj DoMutableAttribute(Obj self, Obj obj) val = DoOperation1Args( self, obj ); /* set the value (but not for internal objects) */ - if ( ENABLED_ATTR( self ) == 1 ) { + if ( ENABLED_ATTR( self ) == 1 && !IS_MUTABLE_OBJ( obj ) ) { switch ( TNUM_OBJ( obj ) ) { case T_COMOBJ: case T_POSOBJ: @@ -2561,7 +2561,7 @@ static Obj DoVerboseMutableAttribute(Obj self, Obj obj) val = DoVerboseOperation1Args( self, obj ); /* set the value (but not for internal objects) */ - if ( ENABLED_ATTR( self ) == 1 ) { + if ( ENABLED_ATTR( self ) == 1 && !IS_MUTABLE_OBJ( obj ) ) { switch ( TNUM_OBJ( obj ) ) { case T_COMOBJ: case T_POSOBJ: diff --git a/tst/testinstall/attribute.tst b/tst/testinstall/attribute.tst index bda3d76c02..bc88fd2dcf 100644 --- a/tst/testinstall/attribute.tst +++ b/tst/testinstall/attribute.tst @@ -44,6 +44,31 @@ gap> NewAttribute("IsBanana", IsGroup, true, 15); gap> NewAttribute("IsBanana", IsGroup, "mutable", 15, "Hello, world"); Error, Usage: NewAttribute( , [, ][, ] ) - -# +gap> DeclareAttribute("FavouriteFruit", IsObject); +gap> foo := rec();; +gap> fam := NewFamily("FruitFamily"); + +gap> Objectify(NewType(fam, IsMutable and IsAttributeStoringRep), foo); + +gap> InstallMethod(FavouriteFruit, [IsObject], x-> "apple"); +gap> FavouriteFruit(foo); +"apple" +gap> HasFavouriteFruit(foo); +false +gap> SetSize(foo, 17); +gap> HasSize(foo); +true +gap> Size(foo); +17 +gap> InstallMethod(FavouriteFruit, [HasSize], x-> "pear"); +gap> FavouriteFruit(foo); +"pear" +#@if not IsHPCGAP +gap> MakeImmutable(foo); + +gap> FavouriteFruit(foo); +"pear" +gap> HasFavouriteFruit(foo); +true +#@fi gap> STOP_TEST("attribute.tst", 1);