www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - 'out' contracts accessing initial parameter values

reply Derek Parnell <derek psych.ward> writes:
I suspect that I'm trying to do something that can't be done (yet?).

I have a routine that is not a function (i.e. it returns void). I want to
test in the 'out' condition that the inout parameter has indeed been
effected by the routine. This means that I need to access the contents of
the parameter as it was at the time of the 'in' condition, from within the
'out' condition. For example (this doesn't compile BTW) ...


 //----------------------------------------------------------
 void ReplaceChar(inout char[] pText, dchar pFrom, dchar pTo)
 //----------------------------------------------------------
 in {
    char[] lOldText;
    lOldText = pText.dup;
    
 }
 out {
    if ( (pFrom != pTo) && (pText.length > 0) )
        assert(pText != lOldText);
 }
 body {
    dchar[] lTemp;
    
    // Do nothing if the replacement char is 
    // the same as the search char.
    if (pFrom == pTo)
        return;
    
    // Convert the utf8 string to utf32, call the utf32 routine,
    // then convert it back to utf8.
    lTemp = toUTF32(pText);
    ReplaceChar( lTemp, pFrom, pTo);
    pText = toUTF8(lTemp);
    
 }


-- 
Derek
Melbourne, Australia
8/02/2005 4:35:06 PM
Feb 07 2005
parent reply Derek Parnell <derek psych.ward> writes:
On Tue, 8 Feb 2005 16:47:27 +1100, Derek Parnell wrote:

 I suspect that I'm trying to do something that can't be done (yet?).
 
 I have a routine that is not a function (i.e. it returns void). I want to
 test in the 'out' condition that the inout parameter has indeed been
 effected by the routine. This means that I need to access the contents of
 the parameter as it was at the time of the 'in' condition, from within the
 'out' condition. For example (this doesn't compile BTW) ...
 
  //----------------------------------------------------------
  void ReplaceChar(inout char[] pText, dchar pFrom, dchar pTo)
  //----------------------------------------------------------
  in {
     char[] lOldText;
     lOldText = pText.dup;
     
  }
  out {
     if ( (pFrom != pTo) && (pText.length > 0) )
         assert(pText != lOldText);
  }
  body {
     dchar[] lTemp;
     
     // Do nothing if the replacement char is 
     // the same as the search char.
     if (pFrom == pTo)
         return;
     
     // Convert the utf8 string to utf32, call the utf32 routine,
     // then convert it back to utf8.
     lTemp = toUTF32(pText);
     ReplaceChar( lTemp, pFrom, pTo);
     pText = toUTF8(lTemp);
     
  }

It looks like this is a no-comment zone, so I changed the routine to be a function so I could write a reasonable 'out' contract. I prefer this anyhow as functions that alter the input parameters decrease the legibility of programs (and increase the chance of bugs). But wouldn't it be useful if the 'out' contract could reference the values of the original parameters? //---------------------------------------------------------- char[] ReplaceChar(char[] pText, dchar pFrom, dchar pTo) //---------------------------------------------------------- in { // Only string references are permitted. assert( ! (pText is null) ); } out (theResult){ String lTempA; String lTempB; // We must return a string reference. assert( ! (pResult is null) ); // Standardize strings to utf32 form. lTempA = toUTF32(pText); lTempB = toUTF32(pResult); // The lengths must be identical. assert(lTempA.length == lTempB.length); if ( pFrom != pTo) { // From and To are not the same so there might be changes. foreach (uint i, dchar c; lTempA) { if (c == pFrom) { // Each From char must now be a To char. assert(pTo == lTempB[i]); } else { // Each non-From char must be unchanged. assert(lTempA[i] == lTempB[i]); } } } else // From and To are the same so there should be no changes. assert(lTempA == lTempB); } body { if (pFrom == pTo) // From and To are the same, so do nothing. return pText; // Convert to utf32, call utf32 replace function, convert back to utf8 return toUTF8( ReplaceChar( toUTF32(pText), pFrom, pTo) ); } -- Derek Melbourne, Australia 9/02/2005 10:22:08 AM
Feb 08 2005
parent reply "Alex Stevenson" <ans104 cs.york.ac.uk> writes:
On Wed, 9 Feb 2005 11:57:48 +1100, Derek Parnell <derek psych.ward> wrote:

 On Tue, 8 Feb 2005 16:47:27 +1100, Derek Parnell wrote:
 <snip lumps o' reply>

 It looks like this is a no-comment zone, so I changed the routine to be a
 function so I could write a reasonable 'out' contract. I prefer this  
 anyhow
 as functions that alter the input parameters decrease the legibility of
 programs (and increase the chance of bugs).

 But wouldn't it be useful if the 'out' contract could reference the  
 values
 of the original parameters?

For contracts of class methods a private/debug only member variable could store the contract information, but free functions with contracts wouldn't have any safe equivalent. Also I'm not sure if there are issues with multithreading here - simultaneous calls to the same object method might overwrite the stored contract data. Perhaps something like Eiffel, where 'old' gives the original value i.e. .out .{ . assert( bufferLength == old.bufferLength + 1 ); .} This probably isn;t feasible to do automatically in D, since it would require the compiler to identify and copy all 'old' references used by the out contract and copy them someplace safe, perhaps as an automagically generated part of an in contract. This brings up issues of deep and shallow copying etc etc as well. It might be possible to have some way of letting the in contract specify things to be stored - I can't thing of a clean way to do that though. -- Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Feb 08 2005
parent reply "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 01:10:20 -0000, Alex Stevenson <ans104 cs.york.ac.uk>  
wrote:
 On Wed, 9 Feb 2005 11:57:48 +1100, Derek Parnell <derek psych.ward>  
 wrote:

 On Tue, 8 Feb 2005 16:47:27 +1100, Derek Parnell wrote:
 <snip lumps o' reply>

 It looks like this is a no-comment zone, so I changed the routine to be  
 a
 function so I could write a reasonable 'out' contract. I prefer this  
 anyhow
 as functions that alter the input parameters decrease the legibility of
 programs (and increase the chance of bugs).

 But wouldn't it be useful if the 'out' contract could reference the  
 values
 of the original parameters?

For contracts of class methods a private/debug only member variable could store the contract information, but free functions with contracts wouldn't have any safe equivalent. Also I'm not sure if there are issues with multithreading here - simultaneous calls to the same object method might overwrite the stored contract data. Perhaps something like Eiffel, where 'old' gives the original value i.e. .out .{ . assert( bufferLength == old.bufferLength + 1 ); .} This probably isn;t feasible to do automatically in D, since it would require the compiler to identify and copy all 'old' references used by the out contract and copy them someplace safe, perhaps as an automagically generated part of an in contract. This brings up issues of deep and shallow copying etc etc as well. It might be possible to have some way of letting the in contract specify things to be stored - I can't thing of a clean way to do that though.

Why not simply by defining them in the 'in' contract, i.e. void foo(inout char[] a) in { char[] original = a.dup; } out { assert(original != a); } body { ..etc.. } Another way to look at it is that 'in' and 'out' are in the same scope, with a break in between to process the function body. I suspect this is incompatible with how they're currently implemented, which I suspect is as calls to functions. Regan
Feb 08 2005
parent reply "Alex Stevenson" <ans104 cs.york.ac.uk> writes:
On Wed, 09 Feb 2005 14:28:59 +1300, Regan Heath <regan netwin.co.nz> wrote:

 On Wed, 09 Feb 2005 01:10:20 -0000, Alex Stevenson  
 <ans104 cs.york.ac.uk> wrote:
 On Wed, 9 Feb 2005 11:57:48 +1100, Derek Parnell <derek psych.ward>  
 wrote:

 On Tue, 8 Feb 2005 16:47:27 +1100, Derek Parnell wrote:
 <snip lumps o' reply>

 It looks like this is a no-comment zone, so I changed the routine to  
 be a
 function so I could write a reasonable 'out' contract. I prefer this  
 anyhow
 as functions that alter the input parameters decrease the legibility of
 programs (and increase the chance of bugs).

 But wouldn't it be useful if the 'out' contract could reference the  
 values
 of the original parameters?

For contracts of class methods a private/debug only member variable could store the contract information, but free functions with contracts wouldn't have any safe equivalent. Also I'm not sure if there are issues with multithreading here - simultaneous calls to the same object method might overwrite the stored contract data. Perhaps something like Eiffel, where 'old' gives the original value i.e. .out .{ . assert( bufferLength == old.bufferLength + 1 ); .} This probably isn;t feasible to do automatically in D, since it would require the compiler to identify and copy all 'old' references used by the out contract and copy them someplace safe, perhaps as an automagically generated part of an in contract. This brings up issues of deep and shallow copying etc etc as well. It might be possible to have some way of letting the in contract specify things to be stored - I can't thing of a clean way to do that though.

Why not simply by defining them in the 'in' contract, i.e. void foo(inout char[] a) in { char[] original = a.dup; } out { assert(original != a); } body { ..etc.. } Another way to look at it is that 'in' and 'out' are in the same scope, with a break in between to process the function body. I suspect this is incompatible with how they're currently implemented, which I suspect is as calls to functions. Regan

This sounds like a rather more practical approach :-) As I understood it contracts are functions called as the follows: call in contract; return from in contract; call function; return from function; call out contract; return from out contract; So the stack frame of the in contract would have disappeared into the wild blue yonder by the time the out contract was called. I suppose if the in contract called the function and the out contract it could be done, with some stack hackery to let the out contract access the in contract bits and to get the function return right: call in contract function; execute in contract statements; call function; return from function, storing return value; call out contract; return from out contract; return from in contract (returning function return value); Of course this is just vague speculation since I don't actually know anything about the implementation, just a little (very) basic knowledge of compilers and some guesswork. -- Using Opera's revolutionary e-mail client: http://www.opera.com/m2/
Feb 08 2005
parent "Regan Heath" <regan netwin.co.nz> writes:
On Wed, 09 Feb 2005 01:31:01 -0000, Alex Stevenson <ans104 cs.york.ac.uk>  
wrote:
 On Wed, 09 Feb 2005 14:28:59 +1300, Regan Heath <regan netwin.co.nz>  
 wrote:

 On Wed, 09 Feb 2005 01:10:20 -0000, Alex Stevenson  
 <ans104 cs.york.ac.uk> wrote:
 On Wed, 9 Feb 2005 11:57:48 +1100, Derek Parnell <derek psych.ward>  
 wrote:

 On Tue, 8 Feb 2005 16:47:27 +1100, Derek Parnell wrote:
 <snip lumps o' reply>

 It looks like this is a no-comment zone, so I changed the routine to  
 be a
 function so I could write a reasonable 'out' contract. I prefer this  
 anyhow
 as functions that alter the input parameters decrease the legibility  
 of
 programs (and increase the chance of bugs).

 But wouldn't it be useful if the 'out' contract could reference the  
 values
 of the original parameters?

For contracts of class methods a private/debug only member variable could store the contract information, but free functions with contracts wouldn't have any safe equivalent. Also I'm not sure if there are issues with multithreading here - simultaneous calls to the same object method might overwrite the stored contract data. Perhaps something like Eiffel, where 'old' gives the original value i.e. .out .{ . assert( bufferLength == old.bufferLength + 1 ); .} This probably isn;t feasible to do automatically in D, since it would require the compiler to identify and copy all 'old' references used by the out contract and copy them someplace safe, perhaps as an automagically generated part of an in contract. This brings up issues of deep and shallow copying etc etc as well. It might be possible to have some way of letting the in contract specify things to be stored - I can't thing of a clean way to do that though.

Why not simply by defining them in the 'in' contract, i.e. void foo(inout char[] a) in { char[] original = a.dup; } out { assert(original != a); } body { ..etc.. } Another way to look at it is that 'in' and 'out' are in the same scope, with a break in between to process the function body. I suspect this is incompatible with how they're currently implemented, which I suspect is as calls to functions. Regan

This sounds like a rather more practical approach :-) As I understood it contracts are functions called as the follows: call in contract; return from in contract; call function; return from function; call out contract; return from out contract; So the stack frame of the in contract would have disappeared into the wild blue yonder by the time the out contract was called.

That's exactly what I imagined was going on :)
 I suppose if the in contract called the function and the out contract it  
 could be done, with some stack hackery to let the out contract access  
 the in contract bits and to get the function return right:

 call in contract function;
 execute in contract statements;
 call function;
 return from function, storing return value;
 call out contract;
 return from out contract;
 return from in contract (returning function return value);

I wonder if it could be done in the same was nested functions work, i.e. incontract() { function() { ..contents of function.. } outcontract() { ..contents of out contract.. } ..contents of in contract.. function(); outcontract(); }
 Of course this is just vague speculation since I don't actually know  
 anything about the implementation, just a little (very) basic knowledge  
 of compilers and some guesswork.

That's all I'm working with :) Regan
Feb 08 2005