Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions
From: James Giles (jamesgiles_at_worldnet.att.net)
Date: 02/07/05
- Next message: Madhusudan Singh: "Re: Integrable singularity"
- Previous message: gtg531e: "Re: shell variables"
- In reply to: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Next in thread: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Reply: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Reply: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Mon, 07 Feb 2005 21:06:17 GMT
Pierre Asselin wrote:
> James Giles <jamesgiles@worldnet.att.net> wrote:
>
>> ASSERT (scalar-logical-expr)
>> constraint: scalar-logical-expr must be a restricted expression
>>
>> [ unlike C assert, becomes part of the subprogram interface
>> and can be tested by the caller, often at compile-time ]
>
> Okay. I assume the ASSERT statement would only be allowed in
> subprograms ?
Procedures. Either SUBROUTINEs or FUNCTIONs. Or, in the
case where the procedure is external, the ASSERT statement could
be in an explicit INTERFACE block. The ASSERT is a declaration
statement and not an executable statement. (Because of this difference
from C and other languages with ASSERT, perhaps some other keyword
should be considered. STIPULATE?)
>> You can assert that the elements of an argument must all be non-
>> negative:
>> Real :: P(:,:)
>> Assert ( All(P >= 0.0) )
>
> I find this surprising. In my mind this test has a "run-time"
> quality to it. [...]
And, it might indeed be a run-time test. It depends on what the
compiler can determine about the value of P. The version of
this feature proposed to the committee was mainly concerned
with such tests as this one. As I've pointed out, I believe that
tests that can more often be made at compile-time are more
interesting. That's why I concentrated on shape in most of the
examples. Future parts of the proposal will also concentrate
on properties that are usually or, at least often, static. The
values of the arguments, while premitted in ASSERTions
by the definition of the feature, ar not often interesting there.
> I guess it depends on the definition of a restricted expression.
> You say
>
>> A restricted expression is the same
>> things as a specification expression except that the latter must
>> be of type INTEGER.
>
> but that doesn't mean much to me, because to really understand what
> a specification expression is I'd have to go parse the standard
> and that would take all day. I would hope that a restricted
> expression can be explained in very few words so the scope of the
> new ASSERT statement is clear. If your example ALL(P>=0.0) turns
> out to be a restricted expression, I'm nervous because I probably
> don't understand what's going on.
Yes, I was afraid that some might not be familiar with specification
expressions. Perhaps, as I mentioned, there should be a separate
thread to discuss that issue.
>> [ ... ]
>> Real :: x(:,:), y(:,:), z(:,:)
>> Assert (size(x,1) == size(y,1), size(x,2) == size(z,2), &
>> size(y,2) == size(z,1))
>> ! now x = matmul(y,z) is guaranteed conformable
>> [ ... ]
>> But suppose you could write the declaration with some kind of place-
>> holder syntax with the meaning that the corresponding values of each
>> placeholder had to match as determined from the properties of the
>> actual arguments. So the above could be written as:
>>
>> Real :: x(^i,^k), y(^i,^j), z(^j,^k)
>
>> And this would mean the same thing as the version in the last
>> section that used ASSERT. Aside from the unfamiliar syntax this
>> is a easy to read as the old-fashioned way.
>
> I object, out of fear of ASSERT spaghetti. *This example* may be
> easier to read in (i,k)(i,j)(j,k) notation but I can imagine examples
> where I would have to reverse-engineer ten lines of declarations
> to understand what the heck is going on.
But, I claim that whatever *other* syntax you used to express the
same concept would be even *more* spaghetti. The issue isn't
to create a feature that eliminates the possibility that people
might write complex programs (they'll do that no matter what you
do), but to make it at least a little easier to express, read, verify,
and maintain such porgrams. I ended with a more complicated
example, though still not really as big as some programmers might
write, to show that this new notation is actually simpler to read than
alternatives (at least, alternatives that I've ever come across).
>> At present, you can write procedures with different numbers of
>> arguments or different Types, KINDs, or Ranks of its arguments,
>> give those procedures a common name (with a generic interface).
>> The implementation decides which procedure to actually invoke based
>> on those differences. But, suppose two procedures have the same
>> number, Type, KIND, and Rank arguments, but have disjoint assertions?
>
> Will you *require* the assertions to be disjoint ? Are the restricted
> expressions restricted enough that disjointness can be checked at
> compile time ? I'm assuming no.
Well, in fact I'd prefer eventually to lift the requirement that the
expressions be disjoint, and instead provide a way for the programmer
to express what order the procedures' requirements are attempted.
That way, a simple procedure that has very specific restrictions
can be called automatically for those specific cases while calls
failing to meet those limits can use a slower, but more general
version of the procedure. Programmers calling such procedures
needn't even know this decision is being made.
But, in my present proposal, it's the programmer's responsibility to
ensure that the assertions are disjoint (or, at least, that the program
doesn't depend on which version of the procedure is called if the
assertions overlap).
>> The implementation is still capable of choosing between them (the
>> assertions are in the interface). Why not extend ad-hoc polymorphism
>> to allow this?
>
> Okay when the asserts can be checked at compile time. It is then
> a compile-time error for a particular call to match zero interfaces
> or more than one interface.
It will be a compile-time warning. The only thing that's illegal is
to actually execute a call that matches no interfaces.
> What if the asserts can't be checked at compile time? The compiler
> will then have to emit code that checks all the assertions at run-time
> and dispatches the call according to the results. A dispatch failure
> is now a run-time error, and a polymorphic call can entail a substantial
> penalty both in code size and running time.
Which it probably already does in codes that have this problem to
solve. With the further penalty that at present all these tests have to
be done in a verbose style and not benefit from the convenience
of generic programming (which, as I'll discuss later, can be substantial).
> That's fine with me, by the way. If you don't want the penalties,
> don't do that. My question is: can the programmer be sure he's
> not doing that ? Many F90 programmers were surprised when their
> arrays were copied instead of passed by reference, because they
> didn't understand the new language features; this could be a lot
> worse.
There are a lot of things that implementations do that take different
amounts of time in different circumstances. There are even situations
where copy-in/copy-out is more efficient than passing the discontiguous
slices (these are actually common, though I agree that the programmer
of the procedure being called should have more control over whether
the actual argument is copied or not).
In the case of assertions, the purpose is mostly to save the programmer's
time. If the tests' overhead becomes onerous, the programmer will have
to take time to write that part of the program differently. That's not
likely unless the ASSERT expressions are allowed to be array valued
and make different procedure linkages for the different array elements!
-- J. Giles "I conclude that there are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies." -- C. A. R. Hoare
- Next message: Madhusudan Singh: "Re: Integrable singularity"
- Previous message: gtg531e: "Re: shell variables"
- In reply to: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Next in thread: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Reply: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Reply: Pierre Asselin: "Re: Part 2 of Short Steps Toward Generic Programming: Specification Assertions"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|