I just got it! (invariant/const)
Georg Wrede
georg at nospam.org
Wed Apr 9 11:21:15 PDT 2008
Steven Schveighoffer wrote:
> "Georg Wrede" wrote
>
>>Jason House wrote:
>>
>>>Consider this example:
>>>
>>>class D{
>>> void invMemberFunc() invariant; // not pure
>>>}
>>>
>>>class C{
>>> int f(invariant D) invariant pure{
>>> D.invMemberFunc(); // illegal
>>> }
>>>}
>>
>>((Upon proofreading it dawned to me that the example above may contain
>>errors, but for the sake of clarity, somebody still explain.))
>>
>>Not being an expert on this stuff, I have to ask:
>>
>> void invMemberFunc() invariant; // not pure
>>
>>What does it actually mean? A function taking no arguments, returning
>>nothing? If it has no side effect, then it has no bearing on the program,
>>therefore, it essentially is a null function, doing nothing. Or, if it has
>>side effects, then the whole question is about: Do we allow or disallow
>>pure functions calling member functions with intra-object side-effects.
>>(And as far as I understand it, currently this is considered illegal, but
>>just may become legal in D3 -- if it /really/ then seems like a warranted
>>idea.) (1)
>>
>>And then it is /invariant/. What exactly does the word invariant mean in a
>>function definition when it's after the function name? That it requires
>>the argument to be an invariant? (I sure hope it's not some property
>>"invariant" of the function, meaning somehow that it doesn't change
>>(whatever)).
>
> It means that the 'this' pointer is invariant. We don't see the body of the
> function, so we don't know if it's pure or not.
Ok. But I strongly resent being able to put the invariant either before
or after the function name. It really gives the impression that it means
something else.
> However, the point is, since it is not *declared* pure (we don't know the
> correct syntax for this by the way because it doesn't exist yet!), the
> compiler doesn't know whether it has side effects or not. Remember, Walter
> and Andrei are trying to create a statically verifyable functional
> programming construct. This means that the compiler doesn't just *assume*
> that a pure function has no side effects, it *guarantees* that the function
> has no side effects.
>> And then,
>>
>> int f(invariant D) invariant pure{ ... }
>>
> A pure function can take non-invariant arguments, it
> just can't use the non-invariant pieces of that. Yeah, I know you just did
> a double take :) But think about this:
In A/W pure, where the reason for all this invariantness is
optimization, it would seem hard to enforce, so it would be easier to
simply forbid non-invariant arguments.
> f(int x)
>
> Does x need to be invariant for f to be pure?
Well, excluding A/W, the pureness of a function is within itself, and
not in whether the arguments can change. But here it's different.
> No, because every time we
> call x, we create a COPY of x on the stack, which means f has it's own
> private copy that isn't invariant, but f is guaranteed that nothing else
> will change it. Now if we have:
Generalising this, the point is to be able to make a local copy from
data that potentially can change? Thus, the compiler can optimize
relying on the now acquired invariantness.
> f(int *x)
>
> Does x need to be invariant for f to be pure? Actually, no :) Because f is
> STILL given a stack variable, which happens to be a pointer to mutable data.
> If f dereferences x, then it cannot be pure unless x is invariant. See the
> difference? Now the real crux of the issue:
>
> class C
> {
> invariant int x;
> int y;
> }
>
> f(C c)
>
> Does c need to be invariant for f to be pure? No. Because c is still a
> stack variable, which is a reference to an instance of C. However, in order
> for f to be declared pure, it can only access c.x, it cannot access c.y,
> because c.y might change.
Which would mean that if f initially makes a local copy of c.y, then
everyting would be ok?
> What about structs?
>
> struct S
> {
> int x;
> }
>
> f(S s)
>
> Again, s does not need to be invariant, because the entire struct is copied
> onto the stack. This is similar to the f(int) case.
Ok. And the point being here is that a private copy is made. (Just
making sure that _stack_ is not the keyword here. It might as well be on
the heap (for example), /as long as/ f has the only reference to it. Of
course normally it would be stack, of course.)
> f(S *s)
>
> Now, f can still be pure, but it is not allowed to dereference s.
Which is useless, right? :-) But still "correct".
>>Finally,
>>
>>>class D{
>>> void invMemberFunc() invariant; // not pure
>>>}
>>>
>>>class C{
>>> int f(invariant D) invariant pure{
>>> D.invMemberFunc(); // illegal
>>> }
>>>}
>>
>>Since invMemberFunc is not pure, then using it in f should really be
>>illegal. Syntactically, that is, per definition. This because other
>>alternatives would be too complicated for the compiler (and the
>>programmer) to be practical.
>>
>>The above example might be clearer (at least to me :-), and depending of
>>course on what exactly you are asking... ) if it said
>>
>>class D {
>> int invMemberFunc(int i) invariant; // not pure
>>}
>>
>>class C {
>> int e;
>> invariant int g;
>> int f(invariant D d) invariant pure{
>> e = d.invMemberFunc(g); // illegal
>> }
>>}
>
> Whether invMemberFunc takes or returns an int or not is irrelevant :) The
> fact that it is invariant means it can still might change global data, and
> so it might not be pure. It could be pure in the sense that it does not
> change global data, but because we didn't declare it pure, the compiler
> cannot know whether it is pure or not, and so it errs on the side of
> caution.
Agreed.
>>(1) Which leads to the thought: since a pure function can't call other
>>functions to use their side effects, the only reason left to call a
>>function is to get it's value. From which follows that calling void
>>functions should be made illegal! On the grounds that there is no point in
>>calling such a function in the first place. (This as part of the
>>"barriers" mentioned in the post 69190 "What is pure and what is not
>>pure".)
>
> This is true, calling a pure function which returns nothing makes no sense,
> but clearly this function can be pure:
>
> void f() {return;}
>
> as it has no side effects :) Should it be illegal? I'd say no. Useless,
> but not illegal.
If there wasn't for the risk that this needs to be allowed as a
potential product of some template stuff, I'd say this should have been
made illegal, in the same sense as unreachable code: it makes no sense.
More information about the Digitalmars-d
mailing list