Topic: 4:00am PROPOSAL: asserts in function prototypes


Author: Christopher Eltschka <celtschk@web.de>
Date: Fri, 7 Dec 2001 17:45:46 GMT
Raw View
"Gottlob Frege" <gottlobfrege@hotmail.com> writes:

> Well, it's late, so sorry if this turns out to be a crazy idea, but here it
> goes anyhow:
>
>
> The story:
>
> so I am looking at a function (prototype) like:
>
>     void setTransparency(Image *image, int alpha);
>
> and I wonder whether alpha goes from 0 to 100 or 0 to 255 (or something
> else, I suppose).
>
> How can I tell? If the prototype was setTransparency(int alpha0to255) I'd
> have a good idea.  But not actually enforced by the language.  Then (for
> some reason) I think about XML Shema, and the way it lets you specify so
> much about variables.  Then I think about the exception-specification for
> functions:
>
> int foo(int x) throw(X); // this function could throw an X exception, but
> nothing else
>
> so anyhow, I then come up with (because I thought the
> exception-specification used ':' somehow) this prototype:
>
>     void setTransparency(Image *image : assert(image != 0), int alpha :
> assert(alpha >= 0 && alpha < 255));
>
> obviously the idea here is that after each function parameter you could list
> some requirements.  Note that the assert isn't really necessary:
>
>
>     void setTransparency(Image *image : image != 0, int alpha : alpha >= 0
> && alpha < 255);
>
> also, for more complicated cases where parameters interact:
>
>     unsigned int SimpleSubtract(int a, int b : a >= b);   // (ie grade 1
> subtract before kids understand negative numbers)
>
> so the rule could be (A) any parameters can be used, or (B) only parameters
> already listed can be used
> (ie "unsigned int SimpleSubtract(int a : a >= b, int b); is invalid with
> rule (B).  I prefer (B) for some reason.)
>
> you could also maybe put it the same place the throw-spec goes (maybe bring
> back "assert" in this case):
>
>     void setTransparency(Image *image, int alpha)  assert(image != 0,  alpha
> >= 0 && alpha < 255), throw(X, Y);
>
> (I might like that syntax better, actually.  The restrictions aren't as
> close to the params in this case, but it is very much like throw(), and
> maybe it's good that they are a little bit out of the way(?))
>
> anyhow, implementation would be fairly easy:
>
> prototype:
>     void setTransparency(Image *image : image != 0, int alpha : alpha >= 0
> && alpha < 255);
>
> code you write:
>     void setTransparency(Image *image, int alpha)
>     {
>         int blah;
>         some_code();
>         blah = etc();
>     }
>
> code generated by compiler:
>     void setTransparency(Image *image, int alpha)
>     {
>         assert(image != 0);
>         assert(alpha >= 0 && alpha < 255);
>
>         int blah;
>         some_code();
>         blah = etc();
>     }

If the assertions are in the _prototype_, I'd prefer it if the
compiler makes use of the fact. That is, the function definition
would be unchanged, but the function _call_

  setTransparency(myImage, some_alpha_value)

(which needs the prototype to be visible) would be internally replaced
by something like

  assert(myImage != 0),
  assert(some_alpha_value >=0 && some_alpha_value < 255),
  setTransparency(myImage, some_alpha_value)

This would have the advantage that the compiler could optimize away
unneeded tests:

void foo()
{
  Image* const myImage = new Image;
  // ...
  setTransparency(myImage, 25);
  // ...
}

At this point, the compiler can optimize away the two assertions,
because it's obvious that neither myImage nor 25 fail the assertion.

In the definition, the compiler should be allowed to make use of the
assertions, for example:

void setTransparency(Image* image, int alpha)
{
  int i = alpha/2;
  // since the compiler knows that alpha may _never_ be negative,
  // it may optimize alpha/2 to alpha>>1, which would be wrong for
  // negative values of alpha
}

Indeed, I'd like if the compiler would always be allowed to assume
that after an assertion, the asserted expression holds, even if NDEBUG
is defined (and therefore the assertion is not checked at runtime).

This could be done by making a failed assertion undefined behaviour if
NDEBUG is defined.

[...]

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Clive D. W. Feather" <clive@on-the-train.demon.co.uk>
Date: Mon, 29 Oct 2001 18:36:17 GMT
Raw View
In article <D4xz7.8034$W61.958313@news20.bellglobal.com>, Gottlob Frege
<gottlobfrege@hotmail.com> writes
>    void setTransparency(Image *image : assert(image != 0), int alpha :
>assert(alpha >= 0 && alpha < 255));
>
>obviously the idea here is that after each function parameter you could list
>some requirements.

I presume your idea is to do this as part of each declaration, so that
it can be checked by the compiler when compiling the caller ? How
practical is that ?

Apart from that, I see little difference to:

    static inline void ASSERT_setTransparency (Image *image, int alpha)
    {
        assert (image != 0);
        assert (alpha >= 0 && alpha < 255);
        setTransparency (image, alpha);
    }
    #define setTransparency ASSERT_setTransparency

>    unsigned int SimpleSubtract(int a, int b : a >= b);   // (ie grade 1
>subtract before kids understand negative numbers)
>
>so the rule could be (A) any parameters can be used, or (B) only parameters
>already listed can be used
>(ie "unsigned int SimpleSubtract(int a : a >= b, int b); is invalid with
>rule (B).  I prefer (B) for some reason.)

It fits in with how C does such things already. Look in particular at
VLA parameters.

>The only problem? (well not the _only_ problem, I'm sure) .....  Is assert()
>part of the language/library?

Yes.

>- you need rules for what functions (if any) can be called in the "assert
>parameter" section.  To a certain extent, I frown upon having functions
>there, because then you _still_ can't "see" what the requirements are.  But
>I suppose that you would end up needing to be able to use global scope
>functions.  Obviously for variables, only the parameters and global
>variables and constants can be used in the assert.

At present, you can call anything.

>well, what do ya think.  Like I said, it's late.  But it is all based on
>what I would consider a common problem (that problem being knowing the
>restrictions on function parameters, in case you forgot).

I'm not convinced there is a problem that needs solving, other than by
"read the specification". After all, what if the restriction is
something like "the two images must relate to the same window class",
which might not be testable in a simple manner ?

--
Clive D.W. Feather, writing for himself  | Home: <clive@davros.org>
Tel: +44 20 8371 1138 (work)             | Web:  <http://www.davros.org>
Fax: +44 20 8371 4037 (D-fax)            | Work: <clive@demon.net>
Written on my laptop; please observe the Reply-To address

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: apm35@student.open.ac.uk (apm)
Date: Tue, 23 Oct 2001 16:44:14 GMT
Raw View
"jacob navia" <jacob@jacob.remcomp.fr> wrote in message news:<9qven4$bgr$1@wanadoo.fr>...
> "Gottlob Frege" <gottlobfrege@hotmail.com> wrote in message
> news:D4xz7.8034$W61.958313@news20.bellglobal.com...
> >
> >     void setTransparency(Image *image : assert(image != 0), int alpha :
> > assert(alpha >= 0 && alpha < 255));
[snip]

What you are looking for is Design by Contract (DbC), which does not
exist in C++ (it does in Eiffel and there is an add-on for Java).
There is an open source project called GNU NANA which tries to add DbC
to C/C++ by the use of macros. Might be worth a look.

HTH,

APM

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: Nicola Musatti <objectway@divalsim.it>
Date: Tue, 23 Oct 2001 16:45:16 GMT
Raw View
[Note to moderators: This is a resend of a message which was received by
the queue on friday, but for which I didn't receive neither acceptance
nor rejection]

[cross-post to comp.std.c removed. This answer is only for comp.std.c++]

Gottlob Frege wrote:
[...]
> so I am looking at a function (prototype) like:
>
>     void setTransparency(Image *image, int alpha);
>
> and I wonder whether alpha goes from 0 to 100 or 0 to 255 (or something
> else, I suppose).
>
> How can I tell? If the prototype was setTransparency(int alpha0to255) I'd
> have a good idea.  But not actually enforced by the language.  Then (for
> some reason) I think about XML Shema, and the way it lets you specify so
> much about variables.  Then I think about the exception-specification for
> functions:
>
> int foo(int x) throw(X); // this function could throw an X exception, but
> nothing else
>
> so anyhow, I then come up with (because I thought the
> exception-specification used ':' somehow) this prototype:
>
>     void setTransparency(Image *image : assert(image != 0), int alpha :
> assert(alpha >= 0 && alpha < 255));

I was about to answer that a better solution, even though a less general
one, would be to introduce range types as Pascal and I beleive Ada have.
Than I thought, couldn't we solve your specific problem as follows:

template <typename T, T low, T high> class range {
  public:
    range(T v) : val(v) {
      if ( val < low || val > high )
        throw std::out_of_range;
    }
    operator T () { return val; }
  private:
    T val;
};

And rewrite your prototype as:

void setTransparency(Image & image, range<int,0,255> alpha);

Cheers,
Nicola Musatti

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "jacob navia" <jacob@jacob.remcomp.fr>
Date: Tue, 23 Oct 2001 17:37:49 GMT
Raw View
> What you are looking for is Design by Contract (DbC), which does not
> exist in C++ (it does in Eiffel and there is an add-on for Java).
> There is an open source project called GNU NANA which tries to add DbC
> to C/C++ by the use of macros. Might be worth a look.
>
> HTH,
>
> APM

That's a macro package, i.e. not integrated into the language, and besides
only runs under C++ gcc.

What I was thinking is a pure C implementation without any horrible macros!

require { * }

ensure { * }

That would be much nicer, if integrated into the standard.




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "Gottlob Frege" <gottlobfrege@hotmail.com>
Date: Fri, 19 Oct 2001 15:18:13 GMT
Raw View
Well, it's late, so sorry if this turns out to be a crazy idea, but here it
goes anyhow:


The story:

so I am looking at a function (prototype) like:

    void setTransparency(Image *image, int alpha);

and I wonder whether alpha goes from 0 to 100 or 0 to 255 (or something
else, I suppose).

How can I tell? If the prototype was setTransparency(int alpha0to255) I'd
have a good idea.  But not actually enforced by the language.  Then (for
some reason) I think about XML Shema, and the way it lets you specify so
much about variables.  Then I think about the exception-specification for
functions:

int foo(int x) throw(X); // this function could throw an X exception, but
nothing else

so anyhow, I then come up with (because I thought the
exception-specification used ':' somehow) this prototype:

    void setTransparency(Image *image : assert(image != 0), int alpha :
assert(alpha >= 0 && alpha < 255));

obviously the idea here is that after each function parameter you could list
some requirements.  Note that the assert isn't really necessary:


    void setTransparency(Image *image : image != 0, int alpha : alpha >= 0
&& alpha < 255);

also, for more complicated cases where parameters interact:

    unsigned int SimpleSubtract(int a, int b : a >= b);   // (ie grade 1
subtract before kids understand negative numbers)

so the rule could be (A) any parameters can be used, or (B) only parameters
already listed can be used
(ie "unsigned int SimpleSubtract(int a : a >= b, int b); is invalid with
rule (B).  I prefer (B) for some reason.)

you could also maybe put it the same place the throw-spec goes (maybe bring
back "assert" in this case):

    void setTransparency(Image *image, int alpha)  assert(image != 0,  alpha
>= 0 && alpha < 255), throw(X, Y);

(I might like that syntax better, actually.  The restrictions aren't as
close to the params in this case, but it is very much like throw(), and
maybe it's good that they are a little bit out of the way(?))

anyhow, implementation would be fairly easy:

prototype:
    void setTransparency(Image *image : image != 0, int alpha : alpha >= 0
&& alpha < 255);

code you write:
    void setTransparency(Image *image, int alpha)
    {
        int blah;
        some_code();
        blah = etc();
    }

code generated by compiler:
    void setTransparency(Image *image, int alpha)
    {
        assert(image != 0);
        assert(alpha >= 0 && alpha < 255);

        int blah;
        some_code();
        blah = etc();
    }

The only problem? (well not the _only_ problem, I'm sure) .....  Is assert()
part of the language/library?  I suppose you could throw(std::bad_parameter)
or something instead.  But I think I would prefer something like assert()
(or "assume" which was recently brought up somewhere) built into the
language, and even have set_assert_handler or something (similar to
set_new_handler).

misc:
- obviously better syntax/keywords might be found; I'm just concerned with
the idea.
- "simple" cases of failed assertions could be compile time errors  (ie when
passing in constants, check the asserts at compile time)
- you need rules for what functions (if any) can be called in the "assert
parameter" section.  To a certain extent, I frown upon having functions
there, because then you _still_ can't "see" what the requirements are.  But
I suppose that you would end up needing to be able to use global scope
functions.  Obviously for variables, only the parameters and global
variables and constants can be used in the assert.
- a way to specify no asserts would be nice (similar to throw()):
    ie what if image == 0 is OK (ie handled "gracefully", no assert or
exception)
        void setTransparency(Image *image : true, int alpha : 0 <= alpha &&
alpha <= 255)
                                                                    ^^^^ do
we assert true, or just leave it blank? (Image *image:, int alpha...)
        void setTransparency(Image *image : , int alpha : 0 <= alpha &&
alpha <= 255)
        void setTransparency(Image *image, int alpha) assert(), throw(X, Y)
    etc.
- I originally thought of this for C++, but nothing prevents it from being
used in C (other than the option of throw'ing bad_parameter, of course)

well, what do ya think.  Like I said, it's late.  But it is all based on
what I would consider a common problem (that problem being knowing the
restrictions on function parameters, in case you forgot).

P.S. is there a separate repository for comp.std.c++ "informal proposals"
somewhere?  Or just search for "proposal"?  I mean, I wouldn't want to
re-propose something that's already been covered.   I guess I should have
looked first, sorry.  But what's the chances?  Did I mention that it's late?



---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]





Author: "jacob navia" <jacob@jacob.remcomp.fr>
Date: Sun, 21 Oct 2001 23:48:37 GMT
Raw View
"Gottlob Frege" <gottlobfrege@hotmail.com> wrote in message
news:D4xz7.8034$W61.958313@news20.bellglobal.com...
>
>     void setTransparency(Image *image : assert(image != 0), int alpha :
> assert(alpha >= 0 && alpha < 255));

I would propose rather:
void setTransparency(Image *image; int alpha)
{
    require { // Bertrand Meyer had it right in this issue.
        image != 0;
        alpha >= 0;
        alpha < 255;
    }
    <function body>

    ensure { // As in the eiffel language.
        Imagecheck(image); // Tests image for coherence.
    }
}

Functions in the require and ensure clauses should be fully "functional",
i.e; should never write or modify global state.

The return type of those functions must be boolean.

The compiler generates code for testing the assertion, and if the assertion
fails, it generates code for calling the function pointed to by the
CurrentAssertionFailed function pointer.

Note that all this can be done in ANSI C. The standard doesn't forbid
extensions. They should not introduce new keywords, that's the only
condition.

You should still be able to use:
    int require;
or even
double require(double n);

The require symbol is only valid in this extension context, if followed by
an opening brace. No identifier can be directly in front of an opening brace
in standard C, so this extension doesn't affect any existing user code.

>
>  Note that the assert isn't really necessary:

Yes. See above.


> misc:
> - "simple" cases of failed assertions could be compile time errors  (ie
when
> passing in constants, check the asserts at compile time)

Yes. Good point.


Yours was an interesting message. Thanks for your ideas.

Jacob.




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.research.att.com/~austern/csc/faq.html                ]