Re: creaping coupling......

From: Dmitry A. Kazakov (mailbox_at_dmitry-kazakov.de)
Date: 02/25/05


Date: Fri, 25 Feb 2005 20:02:53 +0100

On Fri, 25 Feb 2005 11:33:52 -0000, Mark Nicholls wrote:

> "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()

Then its interface becomes decoupled from B's interface.

>> The package, namespace, file, where C is declared does not refer to
>> B_Thing.
>
> no, but it's implementation has to....

Of course, to create B you have to refer to it, directly or indirectly.

>>>> 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.

It has to be because it uses IB which uses IZ. It is transitive. This is
why changing interfaces is an expensive thing. This is why design is worth
its weight in gold.

If from the domain point of view it makes a lot of sense to have many
different Cs which are independent on IZ, then IB is a design fault. You
should have rather:

class IIB
{ // This one does not refer to IZ
public:

private :
   IIB () {} // Enforce no objects
};
IIB * Factory (...); // Abstract factory of things using no IZ
-----------------------
class IB : public IB
{
public:
   void DoSomething(IZ z);
private :
   IB () {} // Enforce no objects
};
IB * Factory (...); // Abstract factory of thigs using IZ

>>> 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?

Yes.

> 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.

How does it differ? Isn't "named interface" = "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.

No problem. The class of objects that are only known to be instantiatable
is *not* XYZ'Class. It is Any'Class. You are using wrong class.

>> You cannot claim to be a bird but refuse
>> to lay eggs.
>
> I can, if the definition of bird does not demand it.

Yes, but either God or Darwin have defined birds this way. If you disagree
with them, you have an opportunity to re-design. It is not a disaster, but
might be too expensive in this particualr case... (:-))

>>>>> 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 you want to allocate things on the stack you need to know the size. I
cannot tell for .NET, but presumably it is already far too slow and uses
by-reference semantics anyway.

>> 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!

This is what I hate most in MS compilers, these 2**10 different targets:
Multithreaded/Not x DLL/Static x Debug/Release x ... This is the real
disaster. It is unmaintable if you have 10 interdependent projects for 3-4
platforms. How would you test it? You start to weep being asked to
recompile once. How about recompiling 2**10 times? In our case to compile
one C++ target is about 4 hours. Then somebody have to reformat the hard
drive, re-install the platform and test that. 2**10 times, rememeber!

>>> 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.

It is a design problem to me. Your client need not to know that there are
pipes and writers. It needs an object where it can put its string. That
object might create a pipe and a writer, but it is not interesting to your
client.

>>> 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.

Interface has no specifics. It is indivisible. To have "specifics" you need
to split the interface into two and use only one of them.

>> 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),

It is already separated. You can have a type specific constructing function
(returns T) and a class-wide constructing function (returns T'Class). When
S is a descendant of T and you have a T'Class constructing function
(=abstract factory), then you can create S knowing nothing about the
methods specific to S. You will see only the methods of T'Class.

> and that the
> coupling/overloading of class with interface is also a cause of significant
> confusion.

Overloading is wrong, but coupling is OK. Any type implements several
interfaces, including one of its own. I see no reason to decouple these.

>> 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.

But you need to know what you are sending. The receiver's contract limits
you in that respect. To fulfil the contract you have to know what's it
about. That's the interface.

> 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.

It is a good example. The interface of a cent tells nothing about chicken.
Neither one of chicken does something about cents. It is the shop's
interface that binds those together. So the shop has to know that chickens
are sold for cents.

It would be interesting to research the issue together with multiple
dispatch assuming that all subroutines are methods of their arguments. In
the shop chickens need to get a method "sell", but not earlier. So I think
that your arguments have a rationale. We cannot foresee all interfaces
chicken might need to implement. We need ad-hoc supertypes created and
deleted on the fly.

>> 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.

Exactly. But that does not influence the chicken-egg relation.

> 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.

The universe shall know how to run chickens. The farmer doesn't need to,
but he can educate himself... It becomes a philosophical dispute: does a
chicken exist while nobody looks at it? (:-))

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

That's OK to me. I would try to make interfaces finer if that becomes a
problem. With exception of MD it is possible to do. For MD there are
patterns provided that not all possible combinations of the parameter types
need to be implemented. Otherwise, well, then you are in trouble...

> 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.

"Object that implements Writable" implies that there should be something
writable. It is a contract. This contract contains definiton of what is to
write. You cannot just write, you write something somewhere. Something is
Element, somewhere is Writable. They are equivalent from any point of view
except for semantcis of Write, which is no matter anyway. So if you want to
decouple from Element you have to have another contract: "[any] object that
can be passed".

Again I see here rather a design problem. Why somebody who creates Writable
should know nothing about what will be written? What for does he create
this?

-- 
Regards,
Dmitry A. Kazakov
http://www.dmitry-kazakov.de


Relevant Pages

  • Re: creaping coupling......
    ... but it is a more strict contract than required. ... I.e. whether private ... >> the compiler very complicated and the code very inefficient. ... > interface itself, its not its business to do this. ...
    (comp.object)
  • Re: creaping coupling......
    ... which is which....and I tend to live in a interface based world. ... This contract has to be known for each and every instance. ... the second statement is what my compiler wants.....my code only needs the ... I.e. whether private ...
    (comp.object)
  • Re: MFC and c++ problems
    ... compiler to generate code that is architecturally nonsensical. ... So a design in which a control has any syntactic knowledge of any container of itself ... GetParent->SendMessage is the interface of choice, ...
    (microsoft.public.vc.mfc)
  • Re: Win32 API and gfortran
    ... write out a module containing only interface blocks and compile the ... that the /iface switches and ATTRIBUTES directives change the compiler ... arguments are passed in the normal Fortran way ...
    (comp.lang.fortran)
  • Re: Using early-bound interface on a late-bound object
    ... > the compiler determines which interfaces to use, ... > supports the declared interface. ... >> help if someone can point me to some authoritative document or reference ... within customer shops when they mirrored this 'division' to keep their ...
    (microsoft.public.vb.general.discussion)