I just got it! (invariant/const)
Steven Schveighoffer
schveiguy at yahoo.com
Wed Apr 9 08:51:37 PDT 2008
"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.
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.
> Along the same lines (please anybody explain),
>
> int f(invariant D) invariant { ... } //omitting pure here for now
>
> What does that mean? Like, one would understand the latter invariant on
> the line to mean that you only can pass invariant data to the function,
> but then the former invariant on the line would be superfluous, right?
Not exactly, it is another way of saying that the 'this' pointer is
invariant.
>
> And then,
>
> int f(invariant D) invariant pure{ ... }
>
> If the function is pure, then should that now implicitly demand an
> invariant argument? (At least as far as I've understood anything about
> this D version.) And therefore actually /both/ invariants are superfluous
> in the definition.
Not necessarily :) 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:
f(int x)
Does x need to be invariant for f to be pure? 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:
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.
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.
f(S *s)
Now, f can still be pure, but it is not allowed to dereference s.
The rules for pure are:
can only access:
- local variables (mutable, invariant or const)
- invariant data that is referenced by local variables (a class is
intrinsically a reference, so class instances fall under this category)
- pure functions
There are interesting puzzles that I'm not sure how they will be solved.
For example:
pure int f()
{
char[] c = new char[15];
c[0] = 'h'; // does this compile?
}
Does c need to be invariant to access members of the array? Clearly from
this code, you can see that c is private to f. But under the rules, the
data c references is not invariant, and so should be inaccessible. How will
the compiler make this distinction?
>
> 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.
Note that passing in an int and returning an int does not mean it can't be
pure. I know you didn't get that when you wrote the post, but I want to
emphasize it for other readers...
> (1) Which leads to the tought: 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.
-Steve
More information about the Digitalmars-d
mailing list