The Design of Software (CLOSED)

A public forum for discussing the design of software, from the user interface to the code architecture. Now closed.

The "Design of Software" discussion group has been merged with the main Joel on Software discussion group.

The archives will remain online indefinitely.

Where to check fro error

Okay so in a OO program

Class B needs a resource that Class A provides.

Example in pseudo code.

main () {

  A = new A ();

  B = new B ();

  B.setResource ( A.getResource () );

  B.B_K (); /* uses the resource */

}

My question is:

If B cannot work properly without the Resource, should B expect the resource or should B check for it

class B {

  variable Resource;

  method B () {

  }

  method void B_K () {
       
          if ( Resource != null ) {
              ...
          }
          else {
              error
          }

  }

}

or should we check in main

main {

  A = new A ();
  B = new B ();

  if ( A.resourceAvaiable () ) {
      B.setResource ( A.getResource () );
      B.B_K (); /* use the resource */
  }
  else {
    err
  }

}


thanks.
YetAnotherUsername
Thursday, April 12, 2007
 
 
> If B cannot work properly without the Resource

Implies constructor should demand the resource
Adrian
Thursday, April 12, 2007
 
 
Your second alternative is "more defensive", which is a good thing.

Personally, I like being able to 'undo' as little as possible when something goes wrong.  In your first example, 'B' has to 'undo' whatever it was doing (if anything, we don't know) when it finds out that the 'A' resource is actually not available.

And then has to return an error code, or raise an error, which the caller then has to deal with.  AND, that error is actually associated with a resource 'owned' by 'A', but the error will be associated with 'B' by the time it's reported.

So your second example is much better.
AllanL5
Thursday, April 12, 2007
 
 
Oh, and you could do the same thing simply by checking that A.GetResource returned something useful BEFORE calling B.SetResource.  In other words, don't wrap your calls so densely.

And you should probably do BOTH -- "Belt AND suspenders".  'B' should react well (by raising an error) if given garbage.  AND the caller should do what it can NOT to give 'B' garbage in the first place.
AllanL5
Thursday, April 12, 2007
 
 
I would do niether.

In this case you should probably do:
B b(A.getResource())

as part of the constructor so that B always has accesses to what it needs, an if it does not, then you do not have a valid B.

Depending on what you are doing, the resource from A may not be part of the state of B.  You may think about doing:
b.B_K(A.getResource())

Thursday, April 12, 2007
 
 
It could be done in the constructor but the error still needs to be handled somewhere, example

class B () {

  method B ( resource ) {
      if ( resource == null ) { error }
  }

}

With

main {

  A = new A ();

  B = new B ( A.getResource () );

}

Or

class B {

  method B () {

  }

  method B_K () {

  }

}

main {

  A = new A ();

  if ( A.getResource != null ) {
      B = new B ( A.getResource );
      B.B_K ();
  }

}
YetAnotherUsername
Thursday, April 12, 2007
 
 
class B {
  public: B(Resource const& res) :mRes(res) {}
  private: Resource mRes;
};

class A {
  public: Resource getResource() { return mRes; }
  private: Resource mRes;
};

int main() {
  A a;  // Can throw.  Otherwise, it has a valid resource
  Resource r = a.getResource() //  Never in error.
  B b(r);  // Never in error.
  b.B_K();  //  Will always have a valid resource to use.
  return 0;
}

As you can see, good C++ style can reduce the amount of checking that needs to be done in the code.

But in general, it is up to a function to validate the input when possible.  And calling code to insure that it never passes arguments meeting the precondition.

Thursday, April 12, 2007
 
 
Think in terms of contracts. B has one universal contract that IT will fulfil: when it exits, a certain set of conditions will be true (the only exception is when a constructor throws an error). Then it has numerous other contracts, one per method: you call my method X only after or concurrent with fulfilling Y (preferably a set of parameters) and I will do Z.

Now, obviously the question of "Does B have the required resource?" is NOT part of Z. It must be either part of the universal contract - in which case the resource must be a parameter to the constructor - or a condition on calling one or more methods.

But either way, B must VERIFY that it has the resource. That's its job. If its preconditions or its universal contract are not fulfilled, its behavior is undefined and quite likely to be incorrect.

At the same time...

The real problem is that A failed to acquire the resource requested, and then either it failed to communicate that fact or the caller wasn't listening. It isn't B's job to catch A's errors, because B neither owns nor calls A.

The later error in B - which it *is* B's job to properly identify and communicate - are a side effect of the error in A.

So:
* A ought to be throwing an exception or returning an error code when it can't properly acquire the resource.
* The caller ought to be checking for the error from A, and dealing with it - which quite possibly will involve discarding (or not creating) B.
* B ought to be verifying that the resource passed to it is a valid resource, and throwing an exception or returning an error code if it is not.
* If the resource is not a mandatory parameter of all constructors, or if there is a way to remove/re-set/invalidate the resource, B ought to be verifying that the resource is present and valid at the beginning of each method that uses it. And, again, it should throw an exception or return an error code.
Don Edwards Send private email
Thursday, April 12, 2007
 
 
If not getting the resource from A is weird and unusual, then A.getResource() throws an exception on failure.

If getting the resource often fails, then B's constructor throws an exception if the resource isn't provided.

Well, it depends on the situation, but that's my initial feeling.

Then you catch the exception at the appropriate place.

(Imagine you're using return codes and bubbling the error up through the callstack manually - the 'catch' goes at the place where you'ld have handled the error.)

Thursday, April 12, 2007
 
 
"Where to check fro error"

In the title of your post?
Will Dowling Send private email
Friday, April 13, 2007
 
 
I think a 'fro error has to be checked by a barber.  :)
sgf
Saturday, April 14, 2007
 
 

This topic is archived. No further replies will be accepted.

Other recent topics Other recent topics
 
Powered by FogBugz