-
Notifications
You must be signed in to change notification settings - Fork 160
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add Info
statement triggered when re-assigning already assigned attributes and the info level InfoAttributes
is at least 3
#3628
Conversation
I'd be interested in seeing this run over the packages, to see if anything fails. |
e5dc9a2
to
3c2968f
Compare
Codecov Report
@@ Coverage Diff @@
## master #3628 +/- ##
===========================================
- Coverage 84.59% 61.59% -23%
===========================================
Files 698 637 -61
Lines 345602 288240 -57362
===========================================
- Hits 292362 177553 -114809
- Misses 53240 110687 +57447
|
I'm looking at the instances where this is failing (there are a bunch of such cases, I am looking into special casing, or removing, them. |
I like the idea, but having it on assertion level 2 might be too aggressive, as test files using But on level 2, this definitely shouldn't be merged before GAP 4.11 is branched |
lib/oper1.g
Outdated
if not IsBound(obj!.(name)) then | ||
ErrorNoReturn("Attribute ", name, " of ", obj, " is marked as assigned, but it has no value"); | ||
elif obj!.(name) <> val then | ||
ErrorNoReturn(name, " of ", obj, " already set to ", obj!.(name), ", cannot be changed to ", val); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wouldn't print the old and new values: doing so can lead to errors itself; and it can also simply flood the screen, or cause all kinds of other problems. Inspecting these values if desired is what we have the break loop for. I'd instead give the relevant values suggestive names and indicate them in the error message, e.g. like so:
ErrorNoReturn(name, " of ", obj, " already set to ", obj!.(name), ", cannot be changed to ", val); | |
ErrorNoReturn("Attribute ", name, " of <obj> already set to <oldval>, cannot be changed to <val>); |
Then of course a local variable oldval
should be added and set to obj!.(name)
.
(I'd also add the "Attribute ",
lead to the message, to match the other message)
This certainly shouldn't go in 4.11. I'm currently further investigating when this is being hit -- in some cases (like ParentAttr), we explictly say in the documentation it can be set multiple times, and late calls will be ignored, and that then happens in several places. I'm thinking this might have to be weakened to an Info level, at least initially. |
500e38f
to
609885a
Compare
lib/attr.gi
Outdated
CHECK_REPEATED_ATTRIBUTE_SET := function(obj, name, val) | ||
if not IsBound(obj!.(name)) then | ||
Info(InfoAttributes + InfoWarning, 3, "Attribute ", name, " of ", obj, " is marked as assigned, but it has no value"); | ||
elif obj!.(name) <> val then |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that checking for equality can potentially be very expensive or even run into an infinite loop. So we should be careful to only check this if we are going to print a message anyway!
I.e., this function should probably at the very start check if the info level is right, and if not, return immediately.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is a serious problem, which I will fix.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Of course we could also just check for identity, using IsIdenticalObj
, but then there might be more false warnings... hm
lib/attr.gi
Outdated
if not IsBound(obj!.(name)) then | ||
Info(InfoAttributes + InfoWarning, 3, "Attribute ", name, " of ", obj, " is marked as assigned, but it has no value"); | ||
elif obj!.(name) <> val then | ||
Info(InfoAttributes + InfoWarning, 3, name, " of ", obj, " already set to ", obj!.(name), ", cannot be changed to ", val); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am somewhat wary about printing obj
as well as the old/new value here. This can lead to pages of output, or trigger errors of its own, or even recursively run into this very same info message.
Which in turn makes me wonder if this should be an info message at all; perhaps it should be a call to Error
instead (only called if the assertion level is higher than some threshold, and/or controlled by info levels as it is right now). Because thinking about how I'd deal with my code triggering these warning, the first thing I'd do is to edit this function to replace Info
by Error
, so that I get a backtrace to find out where the issue actually happened; in contrast, in my experience the printed object or value usually won't be helpful for me.
I guess in the end, it depends a bit on "where do we want to go with this"? Is our goal to stop people from setting non-mutable attributes to new, different values? Then wouldn't an Error (only at high enough level) be the way to go?
This reminds me of my idea of adding a "strict" mode in which all kinds of checks are stricter (see #1191)...
Anyway: please don't get me wrong, I don't want to hold back this PR over some bike shedding, and in the end, I am fine with this PR as it is as well (well, with the performance concern above addressed); I just wonder what the rationale for Info messages vs. Errors is, as naively, I'd expect the Error to be more useful -- but unlike you, I have not yet actually tried this PR, so my naive thoughts here might be totally offbase!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I originally used Error in this PR, but there are lots of places where we do try to change attributes to different values. There are places (Like ?SetParent) where we document that trying to assign a different value will be ignored, and it is done in a bunch of places, so we can't just forbid it. Therefore, it can't really be put at any (reasonable) assertion level, as it is valid and (reasonably) common behaviour to do these reassignments.
However, there are cases where looking at this uncovers bugs (I already reported one, which was fixed), and we could consider moving towards forbidding / reducing how many occur eventually.
I'd also prefer an error, but I'd have to make up a new kind of thing (like a Strict mode as you mentioned), so I thought an Info was better than nothing, and at least means we know in future where we have to "hook" to get more useful information about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BTW, I actually thought that we do document that calling an attribute setter again always has no effect (which of course is contradicted by your leading example). I can't find this in the manual now, though, but I thought that e.g. HPC-GAP relies on this principle in some parts -- but then perhaps this is simply different in HPC-GAP?
Hmmm.. but actually, I cannot reproduce your example at all. I get this:
gap> g := Group(());
Group(())
gap> SetTransitivity(g, 4);
gap> Transitivity(g);
4
gap> SetTransitivity(g, 3);
gap> Transitivity(g);
4
which is in line with what I thought was happening.
Now I wonder why you see something different?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ChrisJefferson can you explain the discrepancy between the leading example in this PR versus what I observe instead on master?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The example at the top was a terrible typo, which went against the whole point :)
There are some setters which document you can try reassigning and it will be ignored (SetParent). Some setters have an explicit check already to see if the user tries to set the value to something different and error if that happens (SetSize). Also properties never let you set them the other way (but you can assign the same value multiple times):
gap> g := Group(());
Group(())
gap> SetIsAbelian(g, true);
gap> SetIsAbelian(g, true);
gap> SetIsAbelian(g, false);
Error, property is already set the other way
not in any function at *stdin*:8
type 'quit;' to quit to outer loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that Parent
is not an attribute, so SetParent
is not a good example.
Oh, and one more thing: I believe that in HPC-GAP, we kind of rely on being allowed to set an attribute twice, in case two threads race for computing the value of an attribute. Of course that should mean that the threads end up setting the attribute to "equal" values; but that also means that for HPC-GAP we'd have to be careful about turning these new checks on by default, as we'd then add those (possibly expensive) equality tests. Well, unless we can come up with a way to distinguish these "N threads raced for a computation" cases from others? |
ce7834a
to
343b94d
Compare
246ff51
to
3d0c16e
Compare
Just to say (here at the bottom), my personal prefered long-term goal for attributes is:
But, it turns out we are further from (3) than I thought, and furthermore even document the current behaviour in some places. |
548daa2
to
c6dd80f
Compare
I think investigating these is worthwhile. I believe I spotted already at least one actual bug using this PR. I'll report tomorrow, after some sleep :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could be merged, though perhaps also adjust SetDimension
? See comments on the PR.
c6dd80f
to
504c55b
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me!
Info
statement triggered when re-assigning already assigned attributes
Info
statement triggered when re-assigning already assigned attributesInfo
statement triggered when re-assigning already assigned attributes and the info level InfoAttributes
is at least 3
An occasional source of subtle GAP bugs is that assignments to attributes are silently ignored, after they are assigned:
Now, for properties this is checked always, and for specifically
Size
this is checked when the assertionlevel is high. However, it isn't checked in general.This PR adds checking when the AssertionLevel is 2. I don't add it in general because it could be the case someone assigns an attribute to a value which is the same, but where = is not implemented, or extremely slow.
If anyone is interested, I has a look at when attributes are assigned the same value (as this could be considered inefficient). It turns out it happens quite a bit for what seem to me to be reasonable reasons (sometimes the same simple property, like IsTrivial, can be assigned for a number of different reasons. It would be more expensive to check if it was already set).