Topic: assert_handler?


Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Mon, 8 May 2006 22:20:15 GMT
Raw View
Geoff Carlton wrote:
> I've read that paper and it is very interesting.  However, I was struck
> that despite the addition of preconditions, postconditions, and
> invariants, there was no actual replacement for a standard assert.
>
> The closest is a block invariant wrapped in its own scope:
>  myval = func1(x);
>  { invariant { myval < 10; } }
>  myval = func2(x);
>  { invariant { myval < 20; } }

Why do you want to wrap the block-invariant in its own scope?

> It would be problematic to try redefine assert given its existing macro
> nature, but it seems that "assertion" and "assertion_broken" could be
> added.

Right, or block_invariant_broken().

> There appears no way of obtaining file/line information, even in debug.
>  The contract handlers could be passed a struct argument which is
> implementation defined.  This would allow compiler writers to add
> location information or even a callstack if they wished, depending on
> compiler flags.  Best if the struct always had file and line members,
> but compilers could leave them null.

This is worth thinking about. Thanks

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: gcarlton@iinet.net.au (Geoff Carlton)
Date: Mon, 8 May 2006 23:23:23 GMT
Raw View
Thorsten Ottosen wrote:
> Geoff Carlton wrote:
>> I've read that paper and it is very interesting.  However, I was
>> struck that despite the addition of preconditions, postconditions, and
>> invariants, there was no actual replacement for a standard assert.
>>
>> The closest is a block invariant wrapped in its own scope:
>>  myval = func1(x);
>>  { invariant { myval < 10; } }
>>  myval = func2(x);
>>  { invariant { myval < 20; } }
>
> Why do you want to wrap the block-invariant in its own scope?
>

It was my understanding that a block invariant tests a value is correct
for its entire enclosing scope.  Similar to a class invariant testing
for a class lifetime, a block invariant would ensure correctness for the
entire enclosing block.

The example given is a loop variable i that is always <10 in the loop scope.

If this reading is incorrect and the block invariant is a "test and
forget" then it indeed does replace assert.

Geoff

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: nagle@animats.com (John Nagle)
Date: Tue, 9 May 2006 03:13:16 GMT
Raw View
Thorsten Ottosen wrote:
> This is described here
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#failure-handler-functions
>
>
> Let us know what you think
>
> best regards
>
> -Thorsten

    I need to read that over and make some intelligent comments.  I
didn't realize that design by contract was that far along.

    Something I've mentioned in the past about "design by contract"
is that the issue of when control is "inside the object" needs
to be made explicit.  If you can leave the object "out the bottom",
by calling something, that should be expressable in the language.
Trouble usually appears in systems where object A calls object B
while object A is not in its invariant-true state, and object
B then calls back into object A. GUI libraries are notorious
for getting into this tangle.  There needs to be some way to
say "Control is now temporarily leaving the object, check the
invariant here".

    The Spec# people explicitly deal with this problem, which is
a big step forward.  (Given the way Microsoft GUI libraries
are organized, I can understand why they had to address the issue.)
C++ should deal with it as well.

    I've suggested something like this, as syntax:

 class someclass {
 public:
     void f();
 }

 void someclass::f()
 { ...  // some code
     public {
  // Invariant must be checked here
  ...  // code logically "outside" the object
  // Invariant must be rechecked here before "re-entering" object
  }
  ...  // more code
 }

A "public" section means you're putting the object into
a valid state, then leaving the object.  This is useful not only for
code that calls back into a public member function of the object,
but for code where a thread blocks and another thread might
enter the object.  (If we ever add "synchronized", as in Java,
to C++, this needs to be addressed. For now, it's a useful feature
for thread implementations.)


    John Nagle
    Animats

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: 9 May 2006 14:50:02 GMT
Raw View
Geoff Carlton wrote:
> Thorsten Ottosen wrote:
>
>> Geoff Carlton wrote:
>>
>>> I've read that paper and it is very interesting.  However, I was
>>> struck that despite the addition of preconditions, postconditions,
>>> and invariants, there was no actual replacement for a standard assert.
>>>
>>> The closest is a block invariant wrapped in its own scope:
>>>  myval = func1(x);
>>>  { invariant { myval < 10; } }
>>>  myval = func2(x);
>>>  { invariant { myval < 20; } }
>>
>>
>> Why do you want to wrap the block-invariant in its own scope?
>>
>
> It was my understanding that a block invariant tests a value is correct
> for its entire enclosing scope.  Similar to a class invariant testing
> for a class lifetime, a block invariant would ensure correctness for the
> entire enclosing block.

Nope.

> The example given is a loop variable i that is always <10 in the loop
> scope.

The example is:

void foo()
{
     int i = 0;
     for(;;)
     {
         invariant { i < 10; }
         ...
     }
}

> If this reading is incorrect and the block invariant is a "test and
> forget" then it indeed does replace assert.

That is the intend. No magic here :-)

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Tue, 9 May 2006 14:47:28 GMT
Raw View
John Nagle wrote:
> Thorsten Ottosen wrote:
>
>> This is described here
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#failure-handler-functions
>>
>>
>> Let us know what you think
>>
>> best regards
>>
>> -Thorsten
>
>
>    I need to read that over and make some intelligent comments.

That would be nice :-) Although you have already made quite a few of
them over the last couple of years.

> I
> didn't realize that design by contract was that far along.
>
>    Something I've mentioned in the past about "design by contract"
> is that the issue of when control is "inside the object" needs
> to be made explicit.  If you can leave the object "out the bottom",
> by calling something, that should be expressable in the language.

Ok, I think our proposal already allows for that.

> Trouble usually appears in systems where object A calls object B
> while object A is not in its invariant-true state, and object
> B then calls back into object A. GUI libraries are notorious
> for getting into this tangle.  There needs to be some way to
> say "Control is now temporarily leaving the object, check the
> invariant here".
>
>    The Spec# people explicitly deal with this problem, which is
> a big step forward.  (Given the way Microsoft GUI libraries
> are organized, I can understand why they had to address the issue.)
> C++ should deal with it as well.
>
>    I've suggested something like this, as syntax:
>
>     class someclass {
>     public:
>         void f();
>     }
>
>     void someclass::f()
>     {    ...        // some code
>         public {
>         // Invariant must be checked here
>         ...        // code logically "outside" the object
>         // Invariant must be rechecked here before "re-entering" object
>         }
>         ...        // more code
>     }
>
> A "public" section means you're putting the object into
> a valid state, then leaving the object.

We are trying to minimize the number of new constructs. What you can do
in our proposal is to call a public member:

class someclass
{
public:
   void f();
   void f_helper();
};

void someclass::f()
{
   ... // some code
   f_helper(); // would correspond to your "public section"
   ... // more code
}

I thing we ripped out of the proposal was to be able to call the
invariant explicitly.

Is the above not good enough?

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Bob Bell" <belvis@pacbell.net>
Date: Tue, 9 May 2006 21:34:54 CST
Raw View
Thorsten Ottosen wrote:
> John Nagle wrote:
> > A "public" section means you're putting the object into
> > a valid state, then leaving the object.
>
> We are trying to minimize the number of new constructs. What you can do
> in our proposal is to call a public member:
>
> class someclass
> {
> public:
>    void f();
>    void f_helper();
> };
>
> void someclass::f()
> {
>    ... // some code
>    f_helper(); // would correspond to your "public section"
>    ... // more code
> }
>
> I thing we ripped out of the proposal was to be able to call the
> invariant explicitly.
>
> Is the above not good enough?

The problem occurs when an A object, while in an "invariants suspended"
state, calls out to some function F() which then calls back to the A
object.

Either F() is calling back to A through a public function (in which
case invariants are checked), or else F() is a friend. It seems to me
that friendship is a relationship that says "it's OK to call into A
while invariants are suspended" -- after all, a friend of A has
complete access to the implementation state of A, and can do anything
it wishes, including breaking the invariants. Therefore, if friend F()
calls back into A through some private interface that doesn't check
invariants, that's OK; in fact, I think it's the correct behavior.

So to answer your question, yes, what you've got is good enough,
because the only way a non-friend can get back into A is through an
operation that will check invariants.

The only quibble I have is with protected members. Suppose F() is a
member of a derived class of A. If it calls back into A through a
protected member of A, this is not the same as friendship -- protected
does not grant access to implementation. Therefore, it's not OK to call
into A while invariants are suspended. So invariants must be checked on
protected member functions as well as public member functions.

Part of my point of view on this comes from the fact that I've always
thought of a class' protected interface as sort of an extra public
interface, intended only for derived classes. Note that anything in a
class' protected interface can be made public in a derived via a using
declaration:

class B {
  protected:
      void f();
};

class D : public B {
   public:
      using B::f;
};

Bob

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: nagle@animats.com (John Nagle)
Date: Wed, 10 May 2006 05:45:19 GMT
Raw View
Bob Bell wrote:
> Thorsten Ottosen wrote:
>
>>John Nagle wrote:
>>
>>>A "public" section means you're putting the object into
>>>a valid state, then leaving the object.
>>
>>We are trying to minimize the number of new constructs. What you can do
>>in our proposal is to call a public member:
>>
>>class someclass
>>{
>>public:
>>   void f();
>>   void f_helper();
>>};
>>
>>void someclass::f()
>>{
>>   ... // some code
>>   f_helper(); // would correspond to your "public section"
>>   ... // more code
>>}
>>
>>I thing we ripped out of the proposal was to be able to call the
>>invariant explicitly.
>>
>>Is the above not good enough?
>
>
> The problem occurs when an A object, while in an "invariants suspended"
> state, calls out to some function F() which then calls back to the A
> object.
>
> Either F() is calling back to A through a public function (in which
> case invariants are checked), or else F() is a friend. It seems to me
> that friendship is a relationship that says "it's OK to call into A
> while invariants are suspended" -- after all, a friend of A has
> complete access to the implementation state of A, and can do anything
> it wishes, including breaking the invariants. Therefore, if friend F()
> calls back into A through some private interface that doesn't check
> invariants, that's OK; in fact, I think it's the correct behavior.
>
> So to answer your question, yes, what you've got is good enough,
> because the only way a non-friend can get back into A is through an
> operation that will check invariants.

     The Spec# people have an explicit "invariants valid" flag,
which is set false at entry to a public method and set back to
true at exit.  At entry to a public method, if that flag is
false, it's an error.  If you want to temporarily exit the
object, you have to explicitly perform an operation that checks the invariant
and sets the flag.  That's a correct "consistent object" model.
The C++ model is significantly weaker.  You need much more elaborate
invariants with the C++ model to catch unexpected re-entry.  For
example, with the proposed C++ model, the contents of auto variables
of an object member function might be related to the state of the object,
and calling out and back in could change the state of the object.
That won't be detected, because invariants can't talk about auto variables.
The Spec# model would catch this.

     I tend to look at this coming from a proof of correctness background
(see the Pascal-F verifier papers http://www.animats.com/papers/papers.html).
One of the big questions in the formal view of design by contract is "when can
we be sure the object won't change"?  That needs to be nailed down if design
by contract is to be sound.

    John Nagle

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: 10 May 2006 18:30:01 GMT
Raw View
Bob Bell wrote:
> Thorsten Ottosen wrote:
>
>>John Nagle wrote:
>>
>>>A "public" section means you're putting the object into
>>>a valid state, then leaving the object.
>>
>>We are trying to minimize the number of new constructs. What you can do
>>in our proposal is to call a public member:
>>
>>class someclass
>>{
>>public:
>>   void f();
>>   void f_helper();
>>};
>>
>>void someclass::f()
>>{
>>   ... // some code
>>   f_helper(); // would correspond to your "public section"
>>   ... // more code
>>}
>>
>>I thing we ripped out of the proposal was to be able to call the
>>invariant explicitly.
>>
>>Is the above not good enough?
>
>
> The problem occurs when an A object, while in an "invariants suspended"
> state, calls out to some function F() which then calls back to the A
> object.
>
> Either F() is calling back to A through a public function (in which
> case invariants are checked),

Right.

>or else F() is a friend. It seems to me
> that friendship is a relationship that says "it's OK to call into A
> while invariants are suspended" -- after all, a friend of A has
> complete access to the implementation state of A, and can do anything
> it wishes, including breaking the invariants. Therefore, if friend F()
> calls back into A through some private interface that doesn't check
> invariants, that's OK; in fact, I think it's the correct behavior.

Agreed.

> So to answer your question, yes, what you've got is good enough,
> because the only way a non-friend can get back into A is through an
> operation that will check invariants.
>
> The only quibble I have is with protected members. Suppose F() is a
> member of a derived class of A. If it calls back into A through a
> protected member of A, this is not the same as friendship -- protected
> does not grant access to implementation.

not unless that is also protected.

> Therefore, it's not OK to call
> into A while invariants are suspended. So invariants must be checked on
> protected member functions as well as public member functions.

I tend to agree.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Wed, 10 May 2006 18:34:04 GMT
Raw View
John Nagle wrote:
> Bob Bell wrote:

>> So to answer your question, yes, what you've got is good enough,
>> because the only way a non-friend can get back into A is through an
>> operation that will check invariants.
>
>
>     The Spec# people have an explicit "invariants valid" flag,
> which is set false at entry to a public method and set back to
> true at exit.  At entry to a public method, if that flag is
> false, it's an error.  If you want to temporarily exit the
> object, you have to explicitly perform an operation that checks the
> invariant
> and sets the flag.  That's a correct "consistent object" model.
> The C++ model is significantly weaker.  You need much more elaborate
> invariants with the C++ model to catch unexpected re-entry.  For
> example, with the proposed C++ model, the contents of auto variables
> of an object member function might be related to the state of the object,
> and calling out and back in could change the state of the object.
> That won't be detected, because invariants can't talk about auto variables.
> The Spec# model would catch this.

Well, if the invariant was not established when the member function
exits, you would catch it.

> One of the big questions in the formal view of design by contract is
> "when can
> we be sure the object won't change"?  That needs to be nailed down if
> design
> by contract is to be sound.

The Spec# team is opting more for verification than we are with our
proposal. At least that is the impression I got from reading their
papers. It might not be very feasible to get programmers to mark
explicitly when they are break the invariant temporarily. It could be
seen as too much work.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Bob Bell" <belvis@pacbell.net>
Date: 10 May 2006 18:40:02 GMT
Raw View
John Nagle wrote:
> Bob Bell wrote:
> > So to answer your question, yes, what you've got is good enough,
> > because the only way a non-friend can get back into A is through an
> > operation that will check invariants.
>
>      The Spec# people have an explicit "invariants valid" flag,
> which is set false at entry to a public method and set back to
> true at exit.  At entry to a public method, if that flag is
> false, it's an error.  If you want to temporarily exit the
> object, you have to explicitly perform an operation that checks the invariant
> and sets the flag.

How do they deal with friendship? A friend can reach into a class and
mess with private member variables. I don't see how the integrity of an
"invariants valid" flag can be maintained when friendship exists.

Bob

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: 10 May 2006 21:30:51 GMT
Raw View
Bob Bell wrote:
> John Nagle wrote:
> > Bob Bell wrote:
> > > So to answer your question, yes, what you've got is good enough,
> > > because the only way a non-friend can get back into A is through an
> > > operation that will check invariants.
> >
> >      The Spec# people have an explicit "invariants valid" flag,
> > which is set false at entry to a public method and set back to
> > true at exit.  At entry to a public method, if that flag is
> > false, it's an error.  If you want to temporarily exit the
> > object, you have to explicitly perform an operation that checks the invariant
> > and sets the flag.
>
> How do they deal with friendship? A friend can reach into a class and
> mess with private member variables. I don't see how the integrity of an
> "invariants valid" flag can be maintained when friendship exists.

A friend can indeed change the internal state of an object - and if a
friend does so and leaves the object in such a state that one of its
clients can observe the object with a false invariant - then the
contract has been broken. And finding broken contracts - that is,
likely errors in the program is the actual goal of this feature. The
goal is not to ensure the "integrity" of a particular flag, the goal is
to find bugs in the program - and bugs that should be fixed.

Toward the end, I do not see that maintaining an "invariants flag" as
really likely to be all that helpful. The effectiveness of this feature
is not that it would impose a series of rigid constraints on how a
programmer designs and implements an interface. On the contrary, to be
both useful and to be used, design-by-contract has to afford the
programmer the maximum latitude in specifying the scope of a particular
contract. And it only makes sense for this feature to do so, because
the programmer is the one who drew up the contract, and the one who
best understands it. So any contract violations detected have to be
clear-cut: and - most importantly - be violations from the programmer's
point of view - and not just from the feature's point of view.

In particular, there is no reason to check invariants whenever a method
under contract remains in scope but calls out to another method. It is
not necessarily a bug if the invariants of the object do not hold for
the duration of the outside call. Now, were the object to acquire
another client who then calls back as a result of that outside call -
or is otherwise able to observe the object with a false invariant -
then a clear contract violation would have occurred. And at the point -
and no sooner - should the violation be reported.

Reporting violations prematurely and without sufficient grounds is
likely to be counterproductive. Logically, the programmer could simply
wish to stipulate that the called routine has been subsumed into the
method's own implementation. Or to put it another way, the object
should be able to call, say, std::strlen() without having first to
ensure that its invariants are true. Granted, the programmer may decide
upon a more stringent contract - and that possibility should be
available - but such an inflexible requirement should not be mindlessly
forced upon the programmer. The entire rationale for adding
design-by-contract support to C++ is to assist the programmer in
writing a coherent set of interfaces for an implementation - and the
goal is not find as many faults - whether irrelevant or not - with the
programmer's work as possible.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: nagle@animats.com (John Nagle)
Date: Thu, 11 May 2006 06:14:36 GMT
Raw View
Greg Herlihy wrote:
> Bob Bell wrote:
>
>>John Nagle wrote:
>>
>>>Bob Bell wrote:

> Reporting violations prematurely and without sufficient grounds is
> likely to be counterproductive. Logically, the programmer could simply
> wish to stipulate that the called routine has been subsumed into the
> method's own implementation. Or to put it another way, the object
> should be able to call, say, std::strlen() without having first to
> ensure that its invariants are true. Granted, the programmer may decide
> upon a more stringent contract - and that possibility should be
> available - but such an inflexible requirement should not be mindlessly
> forced upon the programmer. The entire rationale for adding
> design-by-contract support to C++ is to assist the programmer in
> writing a coherent set of interfaces for an implementation - and the
> goal is not find as many faults - whether irrelevant or not - with the
> programmer's work as possible.

Right.  There are two cases
1.  The call out of the object is to be viewed as subsumed into the
implementation of the object.

2.  The call out of the object is to be viewed as a temporary exit from the
object.

In case 1, re-entry to the object via a public method is an error. In case 2,
it is not.

The proposal does not provide a means for distinguishing between the two cases.

This is an important distinction, and one that is a frequent source of trouble
in tightly interlinked object systems such as GUI libraries.  Many programmers
don't even understand this distinction, and it's not typically documented
in interface documents.  This typically leads to wierd crashes in GUI
libraries when some unusual sequence of events results into a callback into
an object in flux.  (I've seen this problem in four different
major GUI libraries.  This is not an obscure situation.)

Since knowing which case applies for an object is part of that object's
external interface, a design by contract system should address this.

    John Nagle
    Animats

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Geoff Carlton <gcarlton@iinet.net.au>
Date: Thu, 11 May 2006 09:58:01 CST
Raw View
Thorsten Ottosen wrote:
> frege wrote:
>
>  > Has there been any talk about increasing support for debugging in the
>  > next C++?  In particular, things like extending assert, adding trace()
>  > (or output_debug_string() or whatever).
>
>
> The answer is "yes"! Check out
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html
>

The paper mentions enabling and disabling precondition checks as a
client side decision.  I'm not sure I follow how this would be achieved,
for static or dynamic libraries.

Also, what about within a single project?  In a release build we may
want to skip precondition checks for an internal matrix class, but keep
them for high level classes.

This could be achieved by labeling preconditions with appropriate build
settings:
  precondition "debug|safe_release" { .. }

Another idea would be labeling with a logical category that can then be
switched on or off:
  precondition "internal" { .. }
  precondition "scripted" { .. }

Regardless of how it is done, there seems a fundamental division between
preconditions that should always be enforced, and those that act as a
consistency check between internal classes.

Cheers,
Geoff

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Ganesh" <sgganesh@gmail.com>
Date: Thu, 11 May 2006 11:09:59 CST
Raw View
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html

Just a question: Why not a pure library solution instead of adding
support for
contract programming instead of adding support in language and the
library
Isn't it true that C++ is already becoming too complicated? Yes, there
are
limitations in adding it only to the standard-library, but it wouldn't
lead to making
the language more complex.

Regards,
-Ganesh

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Thu, 11 May 2006 11:08:25 CST
Raw View
John Nagle wrote:
> Greg Herlihy wrote:

>> forced upon the programmer. The entire rationale for adding
>> design-by-contract support to C++ is to assist the programmer in
>> writing a coherent set of interfaces for an implementation - and the
>> goal is not find as many faults - whether irrelevant or not - with the
>> programmer's work as possible.
>
>
> Right.  There are two cases
> 1.  The call out of the object is to be viewed as subsumed into the
> implementation of the object.
>
> 2.  The call out of the object is to be viewed as a temporary exit from
> the object.
>
> In case 1, re-entry to the object via a public method is an error. In
> case 2,
> it is not.
>
> The proposal does not provide a means for distinguishing between the two
> cases.
>
> This is an important distinction, and one that is a frequent source of
> trouble
> in tightly interlinked object systems such as GUI libraries.  Many
> programmers
> don't even understand this distinction, and it's not typically documented
> in interface documents.  This typically leads to wierd crashes in GUI
> libraries when some unusual sequence of events results into a callback into
> an object in flux.  (I've seen this problem in four different
> major GUI libraries.  This is not an obscure situation.)
>
> Since knowing which case applies for an object is part of that object's
> external interface, a design by contract system should address this.

It's getting very abstract and hard to follow. Could you examplify these
two situations (perhaps using the spec# notation)?

Thanks

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Thu, 11 May 2006 11:48:46 CST
Raw View
Geoff Carlton wrote:
>
> Thorsten Ottosen wrote:
>
>> frege wrote:
>>
>>  > Has there been any talk about increasing support for debugging in the
>>  > next C++?  In particular, things like extending assert, adding trace()
>>  > (or output_debug_string() or whatever).
>>
>>
>> The answer is "yes"! Check out
>>
>> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html
>>
>
> The paper mentions enabling and disabling precondition checks as a
> client side decision.  I'm not sure I follow how this would be achieved,
> for static or dynamic libraries.

The normal mode of operation will be to expand the precondition inline
at the call site. So the precondition does not need to be part of the
object code in the library (dynamic or not)

> Also, what about within a single project?  In a release build we may
> want to skip precondition checks for an internal matrix class, but keep
> them for high level classes.
>
> This could be achieved by labeling preconditions with appropriate build
> settings:
>  precondition "debug|safe_release" { .. }
>
> Another idea would be labeling with a logical category that can then be
> switched on or off:
>  precondition "internal" { .. }
>  precondition "scripted" { .. }
>
> Regardless of how it is done, there seems a fundamental division between
> preconditions that should always be enforced, and those that act as a
> consistency check between internal classes.

Both your ideas are ok. We have been thinking much about this issue, and
it is partly a compiler-thing (the compiler may give you various options
for enabling assertions) and partly a language thing. We have been
thinking of something along this:

T& vector<T>::operator[]( size_type at )
precondition
{
   at < size(); [["std.range_check"]]
}

T& binary_search(T* first, T* last )
precondition
{
   is_sorted(first,last); [["std.debug"]]
}

Different librarries can flesh out their own levels of assertions, eg at
boost we might have

"boost.debug"
"boost.range_check"

I think 2-3 levels will satisfy most people's demands.

There is also the possibility of saying


!precondition
{
   // critical code
}

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: John Nagle <nagle@animats.com>
Date: 11 May 2006 17:20:05 GMT
Raw View
Thorsten Ottosen wrote:
> John Nagle wrote:

>> Right.  There are two cases
>> 1.  The call out of the object is to be viewed as subsumed into the
>> implementation of the object.
>>
>> 2.  The call out of the object is to be viewed as a temporary exit
>> from the object.
>>
>> In case 1, re-entry to the object via a public method is an error. In
>> case 2,
>> it is not.
>>
>> The proposal does not provide a means for distinguishing between the
>> two cases.

>
> It's getting very abstract and hard to follow. Could you examplify these
> two situations (perhaps using the spec# notation)?

     The Spec# people have a paper on this specific issue.  See "Verification
of object-oriented programs with invariants" at

 http://www.jot.fm/issues/issue_2004_06/article2/index_html

Section 3, "Validity" discusses this issue.

    John Nagle
    Animats

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: Thu, 11 May 2006 14:56:35 CST
Raw View
Ganesh wrote:
>>>http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html
>
>
> Just a question: Why not a pure library solution instead of adding
> support for
> contract programming instead of adding support in language and the
> library

I gave up that idea years ago. I do use some form of library approach
myself, but we just don't harvest as many benefits as we can with a
language solution. From the list of motivation,
(http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#motivation)
the following is not possible with a library solution:

- It can minimize the need for separation of documentation and
implementation.

- It can enable the compiler to generate faster code

- It can make assertions easier to use and more expressive by avoiding
infinite recursion when checking postconditions and class invariants

Also, a language solution offers much more protecction against side-effects.

> Isn't it true that C++ is already becoming too complicated?

I think C++ already is fairly complicated. But so are many things in a
programmers life.

James Widman is working on an implementation. When he's done, we will
know how complicated it is. At any rate, contracts are fairly orthogonal
to the rest of C++, and so should be fairly easy to implement and use.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Thu, 11 May 2006 20:30:35 GMT
Raw View
John Nagle wrote:
> Thorsten Ottosen wrote:
>
>> John Nagle wrote:
>
>
>>> Right.  There are two cases
>>> 1.  The call out of the object is to be viewed as subsumed into the
>>> implementation of the object.
>>>
>>> 2.  The call out of the object is to be viewed as a temporary exit
>>> from the object.
>>>
>>> In case 1, re-entry to the object via a public method is an error.

But surely the invariant will be checked on re-entry. So what's the problem?

>> In
>>> case 2,
>>> it is not.
>>>
>>> The proposal does not provide a means for distinguishing between the
>>> two cases.
>
>
>>
>> It's getting very abstract and hard to follow. Could you examplify
>> these two situations (perhaps using the spec# notation)?
>
>
>     The Spec# people have a paper on this specific issue.  See
> "Verification
> of object-oriented programs with invariants" at
>
>     http://www.jot.fm/issues/issue_2004_06/article2/index_html

This is not less abtract :-) And it's obvious how it relates to the two
situations you mention above.

> Section 3, "Validity" discusses this issue.

Adding two extra keuwords to pack/unpack is not an option for our proposal.

Anyway, I guess their real way to do what you want is to
use "expose"

http://research.microsoft.com/specsharp/papers/krml136.pdf

(section 1.2)

whereby thay say explicitly that now the invariant don't hold:

void foo()
{
  ...
   expose(this)
   {
     // leave object
   }
   // check invariant here
   ...
}

I still can't figure out if this "solves" the problems you have. We need
concrete examples! :-)

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "frege" <gottlobfrege@gmail.com>
Date: 4 May 2006 21:40:08 GMT
Raw View
Has there been any talk about increasing support for debugging in the
next C++?  In particular, things like extending assert, adding trace()
(or output_debug_string() or whatever).

More in particular, I wish there was an assert_handler similar to
new_handler.  ie when using assert(expression) and the expression is
false, assert_handler is called (if one exists), else it goes back to
the default behaviour.

Basically, I find every big project ends up writing its own
FOO_ASSERT() macro and other debuggin macros, but when I write generic
code, I don't know which assert to use - PROJECTA_ASSERT,
PROJECTB_ASSERT, or just assert().  I'd like to use the C++ standard
assert(), but, as expressed by the plethora of ASSERT macros, the
standard assert is somewhat substandard.

And from there, it would also be nice to add some more debugging
support like trace(), breakpoint(), etc.  I know that maybe for some
systems trace() may be impossible, or breakpoint() might be
meaningless, but I think those systems could at least fail gracefully
(even if that meant that the calls did nothing on those systems).

P.S. I think assert and assert_handler, similar to new, should be at
the class level, and then at the global level.  Possibly also at the
namespace level?

Now maybe, since assert can be seen as just another function, it could
all be handled by making an assert function, and then carefully
handling link order, but we all know assert is best done as a macro,
and most versions of it pass along file and line number, as well as the
expression as a string.  It would be nice is assert_handler was passed
that info as well.  Of course, file and line number might be
meaningless in standard-ese, but I think a generic (implementation
defined) 'location' string would be sufficient.

Sorry if that sounds a little quick and half-baked, but hopefully the
gist of the idea is there.  Any thoughts?

Tony

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "frege" <gottlobfrege@gmail.com>
Date: Thu, 4 May 2006 18:20:32 CST
Raw View
Has there been any talk about increasing support for debugging in the
next C++?  In particular, things like extending assert, adding trace()
(or output_debug_string() or whatever).

More in particular, I wish there was an assert_handler similar to
new_handler.  ie when using assert(expression) and the expression is
false, assert_handler is called (if one exists), else it goes back to
the default behaviour.

Basically, I find every big project ends up writing its own
FOO_ASSERT() macro and other debuggin macros, but when I write generic
code, I don't know which assert to use - PROJECTA_ASSERT,
PROJECTB_ASSERT, or just assert().  I'd like to use the C++ standard
assert(), but, as expressed by the plethora of ASSERT macros, the
standard assert is somewhat substandard.

And from there, it would also be nice to add some more debugging
support like trace(), breakpoint(), etc.  I know that maybe for some
systems trace() may be impossible, or breakpoint() might be
meaningless, but I think those systems could at least fail gracefully
(even if that meant that the calls did nothing on those systems).

P.S. I think assert and assert_handler, similar to new, should be at
the class level, and then at the global level.  Possibly also at the
namespace level?

Now maybe, since assert can be seen as just another function, it could
all be handled by making an assert function, and then carefully
handling link order, but we all know assert is best done as a macro,
and most versions of it pass along file and line number, as well as the
expression as a string.  It would be nice is assert_handler was passed
that info as well.  Of course, file and line number might be
meaningless in standard-ese, but I think a generic (implementation
defined) 'location' string would be sufficient.

Sorry if that sounds a little quick and hal-baked, but hopefully the
gist of the idea is there.  Any thoughts?

Tony

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: "Greg Herlihy" <greghe@pacbell.net>
Date: Fri, 5 May 2006 09:38:20 CST
Raw View
frege wrote:
> Has there been any talk about increasing support for debugging in the
> next C++?  In particular, things like extending assert, adding trace()
> (or output_debug_string() or whatever).
>
> More in particular, I wish there was an assert_handler similar to
> new_handler.  ie when using assert(expression) and the expression is
> false, assert_handler is called (if one exists), else it goes back to
> the default behaviour.
>
> Basically, I find every big project ends up writing its own
> FOO_ASSERT() macro and other debuggin macros, but when I write generic
> code, I don't know which assert to use - PROJECTA_ASSERT,
> PROJECTB_ASSERT, or just assert().  I'd like to use the C++ standard
> assert(), but, as expressed by the plethora of ASSERT macros, the
> standard assert is somewhat substandard.
>
> And from there, it would also be nice to add some more debugging
> support like trace(), breakpoint(), etc.  I know that maybe for some
> systems trace() may be impossible, or breakpoint() might be
> meaningless, but I think those systems could at least fail gracefully
> (even if that meant that the calls did nothing on those systems).
>
> P.S. I think assert and assert_handler, similar to new, should be at
> the class level, and then at the global level.  Possibly also at the
> namespace level?
>
> Now maybe, since assert can be seen as just another function, it could
> all be handled by making an assert function, and then carefully
> handling link order, but we all know assert is best done as a macro,
> and most versions of it pass along file and line number, as well as the
> expression as a string.  It would be nice is assert_handler was passed
> that info as well.  Of course, file and line number might be
> meaningless in standard-ese, but I think a generic (implementation
> defined) 'location' string would be sufficient.
>
> Sorry if that sounds a little quick and half-baked, but hopefully the
> gist of the idea is there.  Any thoughts?

The trouble with an "assert_handler" - and indeed with any kind
extension to assertions - is that it is likely to prove
counterproductive. There are, essentialy, two ways for a programmer to
make the best use of assertions. The first is to use them extensively -
the more assumptions that are verified as the program executes the more
thoroughly the program will have been tested. And the second way almost
seems to contradict the first - and that is for a programmer to
minimize the overhead of assertions in the program under development.

The reasoning for the latter goal simply derives from the fact that
assertions do not participate in the program's execution logic. They
are not part of the program being written - and indeed they are usually
completely removed (or disabled) as soon as the program has been deemed
ready for release.

Now it is important for us, as programmers about to release a program,
(note that if you are not a programmer you can pretend to be one in
order to follow along) to have a great deal of confidence that the
program we are about to release, is as close to identical as it
possible to the program that was actually tested. Clearly if we ship a
different program than the one we tested, we will have no idea how well
the shipping program actually works - not mention all the time we
wasted while testing something else.

Now, we already know that the two versions of the program are
different. So the real issue is whether any of the differences that do
exist is significant enough that it would affect the outcome of any of
the tests performed on the development version if that test were
performed on the release version. The dichotomy between a program's
development and release build is somewhat reminiscent of Heisenberg's
uncertaintly principle. In its software incarnation, the question is to
what degree a a program can test itself without the presence of the
testing code influencing the result.

Now it should also be evident that the more complex and elaborate the
assertion mechanism in the development version, the more that program
will differ from the release version. Furthermore, the larger the
program in question - and the greater the degree of its complexity -
the more likely that such differences will matter: that bugs will
emerge in the release version that were not reproducible in the
development version. For example, timing-related bugs in particular can
often remain latent in the development versions of a program - simply
because those versions tend to run slower than the release version. The
additional overhead is due - not only to assertions - but often due to
unoptimized binaries that are more conducive to source level debugging.

There is another risk that elaborate assertion handling poses to
software development: and that is the greater likelihood that bugs will
creep into the assertion-handling code itself. Bugs of this nature are
extemely expensive in terms of their productivity cost to a project.
Essentially any time spent debugging code that is not part of the
program being shipped - has to be written off as a total loss. Large
scale software development is expensive enough as it is, and costs of
this nature can imperil a budget.

But the strongest argument against an assertion handler, in my view,
remains the one I first stated. By eroding the confidence we can place
in the efficacy of our software testing efforts, we find ourselves in a
worse position when it comes time to release the program than we would
have been without them - even though the entire reason that we had for
adopting assertion handlers in the first place was to improve the
quality of our testing efforts and thereby leave us in a better
position when it came time to ship. In other words the actual outcome
is the opposite of the one anticipated.

Greg

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: Thorsten Ottosen <thorsten.ottosen@dezide.com>
Date: 5 May 2006 19:00:02 GMT
Raw View
frege wrote:

 > Has there been any talk about increasing support for debugging in the
 > next C++?  In particular, things like extending assert, adding trace()
 > (or output_debug_string() or whatever).


The answer is "yes"! Check out

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html

but note that this proposal is about much more than just "debugging".

 > More in particular, I wish there was an assert_handler similar to
 > new_handler.  ie when using assert(expression) and the expression is
 > false, assert_handler is called (if one exists), else it goes back to
 > the default behaviour.


This is described here

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#failure-handler-functions

Let us know what you think

best regards

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: thorsten.ottosen@dezide.com (Thorsten Ottosen)
Date: Fri, 5 May 2006 19:02:52 GMT
Raw View
Greg Herlihy wrote:
> frege wrote:
>
>>Has there been any talk about increasing support for debugging in the
>>next C++?  In particular, things like extending assert, adding trace()
>>(or output_debug_string() or whatever).

> The trouble with an "assert_handler" - and indeed with any kind
> extension to assertions - is that it is likely to prove
> counterproductive. There are, essentialy, two ways for a programmer to
> make the best use of assertions. The first is to use them extensively -
> the more assumptions that are verified as the program executes the more
> thoroughly the program will have been tested. And the second way almost
> seems to contradict the first - and that is for a programmer to
> minimize the overhead of assertions in the program under development.
>
> The reasoning for the latter goal simply derives from the fact that
> assertions do not participate in the program's execution logic. They
> are not part of the program being written - and indeed they are usually
> completely removed (or disabled) as soon as the program has been deemed
> ready for release.

Right. This is called "The Principle of Removability":

http://www.artima.com/cppsource/deepspace3.html

> Now it is important for us, as programmers about to release a program,
> (note that if you are not a programmer you can pretend to be one in
> order to follow along) to have a great deal of confidence that the
> program we are about to release, is as close to identical as it
> possible to the program that was actually tested. Clearly if we ship a
> different program than the one we tested, we will have no idea how well
> the shipping program actually works - not mention all the time we
> wasted while testing something else.

So test the release version.

> Now it should also be evident that the more complex and elaborate the
> assertion mechanism in the development version, the more that program
> will differ from the release version. Furthermore, the larger the
> program in question - and the greater the degree of its complexity -
> the more likely that such differences will matter: that bugs will
> emerge in the release version that were not reproducible in the
> development version. For example, timing-related bugs in particular can
> often remain latent in the development versions of a program - simply
> because those versions tend to run slower than the release version. The
> additional overhead is due - not only to assertions - but often due to
> unoptimized binaries that are more conducive to source level debugging.

So this has little to do with assertions afterall.

> There is another risk that elaborate assertion handling poses to
> software development: and that is the greater likelihood that bugs will
> creep into the assertion-handling code itself. Bugs of this nature are
> extemely expensive in terms of their productivity cost to a project.
> Essentially any time spent debugging code that is not part of the
> program being shipped - has to be written off as a total loss. Large
> scale software development is expensive enough as it is, and costs of
> this nature can imperil a budget.

Can you back this up with any surveys?

> But the strongest argument against an assertion handler, in my view,
> remains the one I first stated. By eroding the confidence we can place
> in the efficacy of our software testing efforts, we find ourselves in a
> worse position when it comes time to release the program than we would
> have been without them - even though the entire reason that we had for
> adopting assertion handlers in the first place was to improve the
> quality of our testing efforts and thereby leave us in a better
> position when it came time to ship.

Assertions are not a *replacement* for testing, it's a complimentary tool.

-Thorsten

---
[ 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.comeaucomputing.com/csc/faq.html                      ]





Author: gcarlton@iinet.net.au (Geoff Carlton)
Date: Mon, 8 May 2006 16:45:29 GMT
Raw View
I've read that paper and it is very interesting.  However, I was struck
that despite the addition of preconditions, postconditions, and
invariants, there was no actual replacement for a standard assert.

The closest is a block invariant wrapped in its own scope:
  myval = func1(x);
  { invariant { myval < 10; } }
  myval = func2(x);
  { invariant { myval < 20; } }

It would be problematic to try redefine assert given its existing macro
nature, but it seems that "assertion" and "assertion_broken" could be added.

There appears no way of obtaining file/line information, even in debug.
  The contract handlers could be passed a struct argument which is
implementation defined.  This would allow compiler writers to add
location information or even a callstack if they wished, depending on
compiler flags.  Best if the struct always had file and line members,
but compilers could leave them null.

Thanks,
Geoff


Thorsten Ottosen wrote:
> frege wrote:
>
>  > Has there been any talk about increasing support for debugging in the
>  > next C++?  In particular, things like extending assert, adding trace()
>  > (or output_debug_string() or whatever).
>
>
> The answer is "yes"! Check out
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html
>
> but note that this proposal is about much more than just "debugging".
>
>  > More in particular, I wish there was an assert_handler similar to
>  > new_handler.  ie when using assert(expression) and the expression is
>  > false, assert_handler is called (if one exists), else it goes back to
>  > the default behaviour.
>
>
> This is described here
>
> http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1962.html#failure-handler-functions
>
>
> Let us know what you think
>
> best regards
>
> -Thorsten
>
> ---
> [ 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.comeaucomputing.com/csc/faq.html                      ]
>

---
[ 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.comeaucomputing.com/csc/faq.html                      ]