Re: creaping coupling......

From: Mark Nicholls (nicholls.mark_at_mtvne.com)
Date: 02/25/05


Date: Fri, 25 Feb 2005 11:33:52 -0000


"Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
news:1adglflng2htt$.1wj8496rkoktq.dlg@40tude.net...
> On Thu, 24 Feb 2005 17:00:31 -0000, Mark Nicholls wrote:
>
> >>> "Dmitry A. Kazakov" <mailbox@dmitry-kazakov.de> wrote in message
> >>> news:xl2m948rh45h.16pt6a4mj108b$.dlg@40tude.net...
>
> >> OK, but CreateB is of B, you have not decoupled it yet. If it were of
IB,
> >> like in the factory pattern, then you would need not to know of any
> >> concrete B:
> >
> > I don't CreateB returns something that implements IB.
>
> Yes, but its name assumes that it creates either B or B'Class. Any of
these
> indeed implement IB, but it is a more strict contract than required. If
you
> want to decouple then the contract has to be as weak as possible. Take
> CreateIB, known of only that it creates an IB'Class. [It cannot create IB,
> because IB is abstract (=interface).]

OK call it CreateIB()

>
> >> package IB_Things is
> >> type IB is abstract ...; -- The interface
> >> function Factory (...) return IB'Class;
> >> -- This does not depend on any B, though its body probably will
> >> ...
> >> end IB_Things;
> >
> > yes.
> >
> >> use IB_Things; -- B definitely knows its interface (and IB a part of
it)
> >> package B_Thing;
> >> type B is new IB with ...; -- This implements IB
> >> ...
> >> end B_Thing;
> >>
> >> use IB_Things; -- We don't use B_Thing here, only IB_Things
> >> package C_Thing is
> >> type C is ...; -- This can't use B
> >
> > I'm not following this....it's too un C like.
>
> The package, namespace, file, where C is declared does not refer to
> B_Thing.

no, but it's implementation has to....

>
> >> Now B's interface is decoupled from C's one. The implementation could
still
> >> be coupled directly or indirectly.
> >
> > can we javaesque psuedo code?
>
> In C++:
>
> ----- file IB.h -----------
> class IB
> {
> private :
> IB () {} // Enforce no objects
> };
> IB * Factory (...); // Need pointers because of C++ deficiency
>
> -------- file B.h ----------
> #include "IB.h"
> class B : public IB
> {
> public :
> B (); // This is a concrete type
> };
>
> ------ file C.h ----------
> // Do not include B.h!
> #include "IB.h"
> class C
> {
> public :
> // Whatsoever here cannot depend on B
> };

OK, but in my example IB contains a method that uses another type, IZ....

class IB
 {
 public:
    void DoSomething(IZ z);
 private :
    IB () {} // Enforce no objects
};

so IB.h requires knowledge of IZ.h

and this makes C.h coupled to IZ.h.....when it doesn't need to be.

>
> >>>>>> so (in .net though I expect this happens in a lot of strongly typed
> >>>>>> languages).
> >>>>>>
> >>>>>> C has to know about how to instantiate a B.....fair enough.
> >>>>>> C has to know that about IB.......damn.....why?
> >>>>>
> >>>>> ok, well, actually if C ever wants to do anything with B (assuming
the class
> >>>>> interface B is empty), then C would need to know about IB.....but C
would
> >>>>> not need to know the details of IB, just that B implements IB.
> >>>>
> >>>> If you know B => you know its interface => you also know IB, because
the
> >>>> interface of B contains (=B implements) the interface IB.
> >>>
> >>> but I do not need to know what the interface contains.....I have an
object
> >>> that implements IB....what IB actually does is neither here nor there.
> >>>
> >>> e.g. in COM I can have an object that implements all sorts of
interfaces, I
> >>> do not need to know what those interfaces are to handle a pointer to
that
> >>> object.
> >>
> >> The question is whether the object implements the interfaces publicly
or
> >> privately. If it does that publicly, then this is the contract of the
> >> object. This contract has to be known for each and every instance. So
if
> >> Integer publicly implements Numeric, then yes you have to know that
there
> >> are things like "+".
> >
> > bit there is a difference from saying
> >
> > "I am capable of implementing things via interface XYZ"
> >
> > and
> >
> > "I am capable of implementing things via interface XYZ i.e.
> > XYZ.Boom(IA a);
> > XYZ.Boom(IB b);"
> >
> > the second statement is what my compiler wants.....my code only needs
the
> > 1st statement.....so my code then has to reference all the information
it
> > requires to validate that the second statement is true.......this is bad
in
> > isolation....but recursively it seriously inhibits and decoupling.
>
> But the first implies the second.

no it doesn't.

Oh dear this is reminiscent of the probablity thing.

You need to define your universe.....

we have A,B,C

and A->B

how can we get to A-->C......?...we can't

if we have B-->C then we can.

i.e. are the statements

"I am capable of implementing things via interface XYZ"

and

"I am capable of implementing things via interface XYZ i.e.
XYZ.Boom(IA a);
XYZ.Boom(IB b);"

equivalent?

only if you know that all things that implement XYZ implement Boom.......but
if you don't know that, they aren't.

My code does not need to know wether the object implements specific methods,
only that it promises to implement any methods declared in a named
interface.

consider specifically that we compile, deploy and then we delete a method to
XYZ.....code that only instatiates and then passes an object on should still
work (bizarrely in .net I think this can be done, even though the compiler
demands closure, the runtime doesn't....which further undermines the value
of the demand).....if it does work, then why does your compiler demand
closure.....and if it doesn't, why logically shouldn't it....because no real
promises have been broken.

> You cannot claim to be a bird but refuse
> to lay eggs.

I can, if the definition of bird does not demand it.

>
> >>> interestingly in .net you can 'explicitly' implement an
interface.....which
> >>> means it is implemented 'privately', i.e. it's method signatures do
not
> >>> appear in the class interface......this is very good......but
unfortunately
> >>> in order to instantiate such an object the compiler insists I know of
the
> >>> interface it implements, even when I may have no interest in that
interest.
> >>
> >> OK, but that is rather an implementation issue. I.e. whether private
> >> interfaces could be implemented privately. It is sometimes possible,
but in
> >> general it is rather not. The reason is that in some cases it could
make
> >> the compiler very complicated and the code very inefficient. Though it
is
> >> clearly the trend.
> >
> > I cannot see why it should make the compiler slower....it would be more
> > complicated because it would validate the contents of the interface if
the
> > client code actually operated on it.......it would just JIT it.
> >
> > It would actually make it quicker in most cases.
> >
> > It would have no effect on the compiled code, the coupling is
> > incidental....i.e. there is no actual need to know the valididty of the
> > interface itself, its not its business to do this.
>
> The major problem with opaque type implementations is that to produce
> efficient code the compiler should know the size of the objects in
advance.

yet I believe the runtime actually does not demand this...so at least in the
case of .net, this would/should not be a problem.

> If it does not, then the object have to be allocated in the heap. It is a
> performance hit in order of magnitude. For massively parallel systems with
> shared memory it would be a disaster.

I am not operating in this context, I don't believe my OOP tool is capable
of this.

I like the use of the word disaster....I believe it is proportionate.

> Of course, the compiler might look
> into implementations, but that would couple implementation. So you will
> have lots of nasty problems with shared libraries, separate compilation,
> switching implementations etc.

OK, I believe you, but this is not my or my compilers context, it would be
simply solved by having a compiler switch

app = windows app
app = console app
app = massively parallel app!

>
> >>>>>> C has to know about IA then......disaster......why?
> >>>>>> etc etc etc
> >>>>>>
> >>>>>> Soon C has to reference all sorts of stuff it not interested in.
> >>>>>>
> >>>>>> it seems to me that all C should need to know is that some method
> >>>>>> (constuctor) returns something labelled B.....what you can actually
do with
> >>>>>> B is incidental.
> >>>>>>
> >>>>>> Is there a way around this? (OK I could return 'object's and cast
in the
> >>>>>> code that accesses the interfaces....but uuuuggghhhh)
> >>>>>>
> >>>>> so let me mildly rephrase.....
> >>>>>
> >>>>> C has to know about how to instantiate a B.....fair enough.
> >>>>> C has to know that about the existence of IB and that B implements
> >>>>> it.....fair enough.
> >>>>> C has to know the details of the methods of IB......!....no.....but
my
> >>>>> compiler seems to reckon it does.
> >>>>
> >>>> The methods of IB = all existence of IB. Without its methods IB is
just a
> >>>> text: "IB".
> >>>
> >>> and that's all I want.
> >>>
> >>> I want to go
> >>>
> >>> IB b = CreateB();
> >>>
> >>> ID d = CreateD();
> >>>
> >>> d.DoSomethingWithB(b);
> >>
> >> If IB is just a name, then it should be not IB, but Any:
> >
> > it is more that Any...becuase it promises that it can *potentially* be
used
> > to invoke methods on this interface.
> >
> > but if no actual invocations occur in this code, there is no need to
> > consider IB as anthing more that the promise of potentiallity.
>
> If this code has no invocations of IB then why do you declare the object
as
> IB? It is your code that creates unnecessary coupling!

because the code that actually does do the invocation needs the promise..

i.e.

IWriteable pipe = new Pipe();
IPipeWriter writer = new PipeWriter(pipe);
writer.Write("hello");

it is perfectly reasonable for PipeWriter to demand IWriteable......it is
unnecessary for this code to know anything about the intricacies of the
IWriteable interface.....that is a private matter between PipeWriter and
Pipe.

If you can give me a better way of doing the above, please do, I do not
exclude ignorance/idiocy on my part.

>
> >> Object_B : Any'Class := Factory_Of_Everything ("That should be B");
> >> Object_D : D'Class := Factory_Of_Ds ();
> >>
> >> D_does_something_with_anything (Object_D, Object_B);
> >>
> >>> now the knowledge of what's in IB is isolated in D.....good.
> >>> DoSomethingWithB expects an IB object, so the client caller of it
needs to
> >>> know of the existence of IB in order to be able to pass an object that
> >>> implements it.
> >>
> >> OK, then it should be:
> >>
> >> Object_B : IB'Class := Factory_Of_IB ("That should be my precious B");
> >> Object_D : D'Class := Factory_Of_Ds ();
> >>
> >> D_does_something_with_IB (Object_D, Object_B);
> >
> > I don't understand this, your OOP tool may well be more capable than
mine,
> > or I may not be able to see the equivalent C# code.
>
> You have just to ask yourself what is the precondition of the code that
> requires that Object_B?

The procondition of the operating class is that the passed object implements
an inteface....no more, the specifics of that interface are a wholely
private matter between operating client and server class, the instantiating
client has absolutely no interest.

>
> If D_does_something_with... requires IB'Class then Object_B *must* be in
> that class. You cannot then claim that you do not need each and every
> method of IB'Class in your code because you don't know what
> D_does_something... uses, and you call it!
>
> Alternatively, if D_does_something... works with any object, then there is
> absolutely no need to create an IB for it.
>
> Also I see nothing wrong with OO here.

I see nothing wrong with OO principle, rather than OO practive.....though I
have long claimed that OO theory should better seperate the concepts of
operation from instantiation (and object passing), and that the
coupling/overloading of class with interface is also a cause of significant
confusion.

>
> >>>>> C thus has to know the interfaces of all parameters in the methods
of
> >>>>> IB....!!......no.....but my compiler seems to reckon it does.
> >>>>
> >>>> Clearly it should! The interfaces of the parameters mentioned in an
> >>>> interface is a part of that interface.
> >>>>
> >>>>> recursively....!!!!......C has to know the complete tree of
interfaces
> >>>>> stemming from B.....!!!......disaster.
> >>>>
> >>>> Why so? It should know the [sub]tree of all ancestors of B.
> >>>
> >>> but why does it need to?
> >>
> >> Because its interface refers to the interface of B. It is a closure.
> >
> > but the closure is not required.....
>
> It is required because we want to decouple interface and implementation.
> Once they are decoupled, you cannot tell which subset of the interface
> would be required in an implementation based on the interface.

In the exampes given closure is not required.

I can theoretically typesafely create (or recieve and send) objects till I
am blue in the face.....I need not know any specific methods.

As I said in a parallel post......it's like money.....

If I go to the shop, I ask how much for the newspaper....he say "50
cents".......it makes life much easier than saying...."half a chicken and a
packet of chips" one day and "a bag of rice and a popadom" the next........

I need not know what the shopkeeper wants with my my money, just that he
need the potential to get what he wants.

My instantiating client does not need to know what or how another is going
to do it's job, just that it is, and that I have given it the potential to
do so by satisfying the precondition...."does it implement XYZ".

>
> A poultry farm that sells broilers might need no egg laying, nevertheless
> broilers are hatched out of eggs.

? thats self referential....my examples aren't....
What came first....the broiler or the egg?

Maybe the farmer simply buys broilers in, and sells them on at a profit, he
may be amazed when you tell him broilers can lay eggs and that eggs exists,
and that chickens come out of eggs.

To me there is a principle that you should only include the minimal
information that you need, this would seem to be the basis of
taxonomy.....and this the basis of OO, yet my compiler insists on complete
knowledge of stuff that is none of it's business.

>
> >> To be boringly formal: the "use" relation is transitive.
> >
> > but the relation is not required.....in this context.
> >
> > thus the closure with this relation is overkill and incidental.
>
> Not at all. The whole essence of interface is that its properties do not
> depend on the context you might wish to use it. You can rely on it in any
> context.

and I am not breaking that.......I am simply saying the promise to implement
an inteface is weaker than the promise to implement named methods of an
interface.

for examlpe, changing the names of the methods, breaks one promise but not
the other......yet if the code does not require any specific invocations,
then it only requires the weaker promise.

>
> You might also look at this in other way: the set of all contexts where
> something can be used in some definite way constitutes an interface.

I see no contradiction.

>
> Nothing here is incidental. If it appears so, then you have a design
> problem: fat classes.

then solve the problem

inteface IWriteable
{
     void Write(string);
     void Write(IStream);
}

client code.

IWriteable pipe = new Pipe();
IPipeWriter writer = new PipeWriter(pipe);
writer.Write("hello");

client code needs to reference the module containing IStream......why?

you could claim that IWriteable is fat ?!?.....but that way really leads to
1 method interfaces.....

i.e.
inteface IStringWriteable
{
     void Write(string);
}

inteface IStreamWriteable
{
     void Write(IStream);
}

and

interface IStreamWriter
interface IStringWriter

oh and 'new' is has to be removed.....because the class implements both
interfaces so....

some factory

class CStreamPipeFactory
class CStringPipeFactory

but even now, recursively, if Pipe implements ...IStreamWriter and
IStringWriter, CStreamPipeFactory needs to know about IStringWriter......and
it doesn't need to.....OK so maybe we need StreamPipe and
StringPipe.......but now I cannot write Streams and strings into the same
pipe......

The same thing would apply to IStreamReadable and
IStreamWritable......eventually if you remove all incidental coupling you
recursively would have to seperate the concrete classes.......but that would
mean any pipe I write to, I can't read from........thats pretty
limiting.....some would say it renders pipes completely useless.....because
it does.

>
> >>>> It need not to
> >>>> know any of its successors, siblings or ancestor's siblings as well
as
> >>>> their successors.
> >>>
> >>> correct, but I do not see why it needs intimate knowledge of the
methods of
> >>> the interface when it, itself never accesses them.
> >>
> >> But that's the essence of OO (or ADT)!
> >
> > then it's wrong !.......it's too strong....it's incidental....it is not
> > required.
>
> Refactor, re-partition.

show me how to write Pipe, and PipeReader....in such a way that no object
knows about intefaces that it never accesses.

>
> >> No floating procedures. When you
> >> refer to a type (=its interface) you take everything with
> >
> > even when you don't need any of it except the promise that something can
> > operate via that interface.
>
> Yes. Next day you might change your mind and use something from the
> interface. If you 100% sure that you will never ever do it, then it is a
> design problem: you over-specify.

recursively this makes the whole code a huge blob of coupling...and forces
you to use primitive types for subsystem interfaces.

>
> >> , and thus you are
> >> ready to use it.
> >
> > but this code does not want to.....thus it does not need this
> > information...and thus the information is incidental and should be
hidden.
> >
> >> This is the *contract* model.
> >
> > I have no problem with the contract, but I want 2.....
> >
> > one that say's.
> >
> > contract 1: "I promise I can obey contract 2"
> > contract 2: "I promise if you satisfy ABC, I'll do XYZ"
> >
> > I only need 1......but my OOP insists that if I have 1.....I must know
what
> > 2 contains.
>
> Yes. You'll never sign any contract without looking into it. Would you?

yes, it's called money.....

I promise to do work for money.....my employer does not need to know what I
do with that money....I may just put it under my mattress.

Imagine the cost and paperwork involved if my contract of employment
stipulated what I did with my money and recursively what all other parties I
could pass money to could do with it..

All contracts then become coupled...

>
> DMCA:
>
> contract 1: By buying DVD I sign to the contract 2
> contract 2: I can be jailed if I try to play on my Linux box
>
> > I simply want my code to depend on contract 1......the constructor
satisfies
> > this contract...it supplies a IB...
>
> Stop,
>
> 1. "the constructor supplies an IB"
> 2. "the constructor supplies a B"
>
> are two different contracts!

I am using 'constructor' loosely......some method that returns an object of
a given type/interface.

>
> > The delegate requires contract 1 as part of it's preconditions.....and I
> > know it's satisfied......but the compiler insists on sticking it's nose
> > in......
>
> Abstract factory seems what you need.

nope....it doesn't break contract 1 from 2.

any types in methods in the interface returned will automatically have to be
referenced....even if no methods are actually invoked.

>
> >>> OK, I can cast my way out of this, but I soon end in a completely
untypesafe
> >>> world.
> >>
> >> Casting is bad. If you need it then there must something wrong with the
> >> design. Perhaps you have to re-partition the type space. [Of course,
there
> >> might be pathological cases when the type hierarchy is not a tree. But
they
> >> are rather rare.]
> >
> > Think of a pipe.....
> >
> > pipe implements IPipeReadable and IPipeWritable.
> >
> > I have a PipeReader that reads via IPipeReadable.....yet my OOP will
insist
> > that it actually has to be coupled to IPipeWriteable as well....because
it
> > takes the closure........that to me is bad, and recursively.....very
> > bad......it's analogous to making all private fields public.
>
> class Readable
> {
> public :
> virtual Element Read () = 0;
> };
>
> class Writable
> {
> public :
> virtual void Write (const Element& Item) = 0;
> };
>
> class InPipe : public Readable
> {
> public :
> Element Read ();
> };
>
> class OutPipe : public Writable
> {
> public :
> void Write (const Element& Item) = 0;
> };
>
> class Socket : public Readable, public Writable
> {
> public :
> Element Read ();
> void Write (const Element& Item) = 0;
> };
>

now write some client code that creates an object that implements Writable
and passes it to another object that actually writes something.

do so such that the client code does not have to reference the module
containing the definition for Element......for it doesn't need to know it.

As I say the irony here is that I can actually write code in .net that does
this...

write an empty interface.
write the factory with an empty implementation
write an empty pipe writer
write a the client to create an object from the factory and pass it to the
pipewiter.
compile
deploy
reversion, compile and deploy the interface with the correct methods.
write the pipe implementation, compile and deploy
reversion, compile and deploy the factory to create the concrete pipe.
reversion, compile and deploy the writer to write to the pipe.

I now have a piece of deployed code that executes and works, typesafely.

recompile whole project........BOOOOMMMM.......client does not reference
'Element'.........



Relevant Pages

  • Re: ActiveX.exe question
    ... > the public interface still need registered in order to use them. ... Compile AXExe.exe against a Share on the TestPC ... Open a Standard-Exe-Project on your DevelopPC and name it AXTest ... Compile AXTest.exe against the Share on the TestPC ...
    (microsoft.public.vb.general.discussion)
  • Re: RAD vs. performance
    ... thus they fulfull the number interface and can be used interchangeably. ... I'm not about to ditch statically typed languages ... Because you need whole-program optimisation for a start. ... The benefits of static typing come at compile time. ...
    (comp.lang.misc)
  • Re: Is Direct3D a rip-off of OpenGL?
    ... People who think that a method change in a NEW INTERFACE in DirectX really ... Moving to use a NEW INTERFACE, ... > ago simply isn't going to compile with the latest SDK, ...
    (comp.graphics.api.opengl)
  • Re: Variable uses a type not supported in Visual Basic (Error 458)
    ... > Microsoft Visual Basic for Applications Software Development Kit ... > interface in a Visual Basic class, ... > generate libraries that use a Visual Basic- or Visual Basic for ... > Rebuild your type library by pressing CTRL+F7 or selecting Compile ...
    (microsoft.public.vb.bugs)
  • Re: Duplicate definition on Interface declaration
    ... Interface class. ... Init() method perhaps? ... There are no conditional compile arguments named "Init". ... definition error when I try to display some forms and/or controls in the IDE ...
    (microsoft.public.vb.general.discussion)