www.digitalmars.com         C & C++   DMDScript  

D - in/out contracts on function pointers

reply Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
It just occurred to me that in & out contracts on function pointers
would be nice:

int (*foo)(int a,int b)
in
{
    assert(a>0);
    assert(b>0);
}
out(retval)
{
    assert(retval <= a+b);
};

The idea, of course, is that when you use the function pointer to call
the function, it runs the in an out tests in addition to any in and out
contracts specified in the funciton implementation.  This would allow
you to specify some common requirements on how the functions are called
and what they do.

Right now, I don't know what to do with assignments.  That is, if you
have a function pointer with in & out contracts, and you attempt to
assign that pointer to another with the same type but different
contracts, should that be legal and what should it mean?  My thought, at
first pass, is that it should be legal and the only binding contracts
should be the ones where the function is actually used.

Comments, anyone?

--
The Villagers are Online! villagersonline.com

.[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
.[ (a version.of(English).(precise.more)) is(possible) ]
?[ you want.to(help(develop(it))) ]
May 28 2003
parent reply "Sean L. Palmer" <palmer.sean verizon.net> writes:
I like the idea, and agree with the point on copying.

This would move in/out contracts to be part of the function signature, but
being unable to copy without identical contracts seems too restrictive.  So
copying does nothing to contracts, seems like a good solution.

For myself this particular form of contract would be better expressed by a
limitation on the type of the input itself, such as:

typedef 1..MAXINT posint;
int (*foo)(posint a, posint b);

You'd still need the out contract (but I leave it out here)

The compiler would then need to ensure somehow (perhaps by range checking at
call time, perhaps inferred) that the range requirement is met.  It allows
one to clearly and cleanly delineate range of a value *in one place* in the
code, and have it automatically enforced.  I prefer this to in/out contracts
in this particular case, but in/out contracts have other uses which are
valid.

Just playing with syntax for ranges, I find these.

Without the intermediate typedef:

int (*foo)(1..MAXINT a, 1..MAXINT b);

Even better syntax may be:

int (*foo)(1..+ a, 1..+ b);

or perhaps:

int (*foo)(int a > 0, int > 0 b);

Which leads back to:

typedef int posint > 0;

Or:

typedef int > 0 posint;

Thoughts?

Sean

"Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
news:3ED53A84.513DDBDB deming-os.org...
 It just occurred to me that in & out contracts on function pointers
 would be nice:

 int (*foo)(int a,int b)
 in
 {
     assert(a>0);
     assert(b>0);
 }
 out(retval)
 {
     assert(retval <= a+b);
 };

 The idea, of course, is that when you use the function pointer to call
 the function, it runs the in an out tests in addition to any in and out
 contracts specified in the funciton implementation.  This would allow
 you to specify some common requirements on how the functions are called
 and what they do.

 Right now, I don't know what to do with assignments.  That is, if you
 have a function pointer with in & out contracts, and you attempt to
 assign that pointer to another with the same type but different
 contracts, should that be legal and what should it mean?  My thought, at
 first pass, is that it should be legal and the only binding contracts
 should be the ones where the function is actually used.

 Comments, anyone?

 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
May 28 2003
next sibling parent Antti Sykari <jsykari gamma.hut.fi> writes:
 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3ED53A84.513DDBDB deming-os.org...
 It just occurred to me that in & out contracts on function pointers
 would be nice:

 int (*foo)(int a,int b)
 in
 {
     assert(a>0);
     assert(b>0);
 }
 out(retval)
 {
     assert(retval <= a+b);
 };

 The idea, of course, is that when you use the function pointer to call
 the function, it runs the in an out tests in addition to any in and out
 contracts specified in the funciton implementation.  This would allow
 you to specify some common requirements on how the functions are called
 and what they do.
[..]
 Comments, anyone?
I'd find it most natural to use an interface with pre- and postconditions. Maybe it's just me but bare function pointers seem like a low-level feature from the ancient C days. -Antti
May 28 2003
prev sibling parent Russ Lewis <spamhole-2001-07-16 deming-os.org> writes:
I prefer the typedef idea, from a design perspective.  But I don't think that
the types should be named "posint" or anything like that, since that just
describes the container.  Instead, (IMHO) you should describe the purpose of the
type:

typedef 1..+ columnIndex;
typedef 1..+ rowIndex;
void foo(columnIndex col, rowIndex row);

The beauty of range-limited types (either typedefs or inline declarations) is
that the compiler is entitled to implement it using a type with a larger size
and add (implicit) aserts throughout the code that ensure that the value stays
within the range.  Especially nice when you are modeling something with a
relatively small range:

typedef 0..7 smallSelector;

Presumably, the compiler would implement this as a byte or ubyte.  The compiler
then adds implicit asserts before each read and after each write.  A beautiful
side effect of this is that the compiler can implicitly define that:

smallSelector.init = 8;

meaning that if we ever try to read an unitialized smallSelector variable, we
will get a runtime assert "value read was out of valid range".  Nice!

"Sean L. Palmer" wrote:

 I like the idea, and agree with the point on copying.

 This would move in/out contracts to be part of the function signature, but
 being unable to copy without identical contracts seems too restrictive.  So
 copying does nothing to contracts, seems like a good solution.

 For myself this particular form of contract would be better expressed by a
 limitation on the type of the input itself, such as:

 typedef 1..MAXINT posint;
 int (*foo)(posint a, posint b);

 You'd still need the out contract (but I leave it out here)

 The compiler would then need to ensure somehow (perhaps by range checking at
 call time, perhaps inferred) that the range requirement is met.  It allows
 one to clearly and cleanly delineate range of a value *in one place* in the
 code, and have it automatically enforced.  I prefer this to in/out contracts
 in this particular case, but in/out contracts have other uses which are
 valid.

 Just playing with syntax for ranges, I find these.

 Without the intermediate typedef:

 int (*foo)(1..MAXINT a, 1..MAXINT b);

 Even better syntax may be:

 int (*foo)(1..+ a, 1..+ b);

 or perhaps:

 int (*foo)(int a > 0, int > 0 b);

 Which leads back to:

 typedef int posint > 0;

 Or:

 typedef int > 0 posint;

 Thoughts?

 Sean

 "Russ Lewis" <spamhole-2001-07-16 deming-os.org> wrote in message
 news:3ED53A84.513DDBDB deming-os.org...
 It just occurred to me that in & out contracts on function pointers
 would be nice:

 int (*foo)(int a,int b)
 in
 {
     assert(a>0);
     assert(b>0);
 }
 out(retval)
 {
     assert(retval <= a+b);
 };

 The idea, of course, is that when you use the function pointer to call
 the function, it runs the in an out tests in addition to any in and out
 contracts specified in the funciton implementation.  This would allow
 you to specify some common requirements on how the functions are called
 and what they do.

 Right now, I don't know what to do with assignments.  That is, if you
 have a function pointer with in & out contracts, and you attempt to
 assign that pointer to another with the same type but different
 contracts, should that be legal and what should it mean?  My thought, at
 first pass, is that it should be legal and the only binding contracts
 should be the ones where the function is actually used.

 Comments, anyone?

 --
 The Villagers are Online! villagersonline.com

 .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ]
 .[ (a version.of(English).(precise.more)) is(possible) ]
 ?[ you want.to(help(develop(it))) ]
-- The Villagers are Online! villagersonline.com .[ (the fox.(quick,brown)) jumped.over(the dog.lazy) ] .[ (a version.of(English).(precise.more)) is(possible) ] ?[ you want.to(help(develop(it))) ]
Jun 02 2003