www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.announce - Decoupling implementation from usage

reply "Kris" <fu bar.com> writes:
I'm really confused as to how D can decouple implementation from usage. So, 
I'm submitting an example here in an attempt to get clarification from 
anyone who understands how it works. I'll be most appreciative to whomever 
can help.

Walter says that the use of interfaces is supported as a means of 
decoupling; for hiding implementation detail. These are excerpted from 
various recent posts, though the context is consistent:

"Walter Bright" <newshound digitalmars.com> wrote
 You suggest that using Interfaces is the right way to hide implementation
 detail. I'd agree, but how does one expose the means of accessing an
 instance? Does one provide an interface factory, and expose a header for
 that?

That's the classic way of doing it.

 COM/interface/factory methodology in C++ does enable full hiding, however,
 and if you do that in D, you get full hiding as well.

 There are two solutions you can use. Both involve putting your interfaces 
 in
 a separate module. One means making a module just for your factory stub:
    ISearchEngine createSearchEngine (char[] someAttributes);

Good. Here's a trivial example, using a "search engine" as the mule. First we define an abstraction of the engine itself, using an interface: ~~~~~~~~~~~~~~~~~~~~~~ module ISearchEngine; interface ISearchEngine { void search (char[] terms); } ~~~~~~~~~~~~~~~~~~~~~~ Next, we create a Factory to instantiate a search engine. We implement the interface and provide a method to create an instance: ~~~~~~~~~~~~~~~~~~~~~~ module SearchFactory; public import ISearchEngine; import std.stdio; private class SearchEngine : ISearchEngine { void search (char[] terms) { writefln ("searching for ", terms); } } ISearchEngine create() { return new SearchEngine; } ~~~~~~~~~~~~~~~~~~~~~~ Next, we "use" the Factory in a client application (main.d): ~~~~~~~~~~~~~~~~~~~~~~ private import SearchFactory; void main() { auto s = create(); s.search("blah"); } ~~~~~~~~~~~~~~~~~~~~~~ compile it: dmd main ISearchEngine SearchFactory and run it: "searching for blah" So far so good. Now we want to remove the Factory (source code) from the distribution package, since it holds all kinds of proprietary information that I, as a company like Google, are not currently willing to share with everyone. What I wish to do is ship a .obj file, or a lib/whatever, along with some kind of "header" that will satisfy the compiler. Following Walter's instructions (from above: re factory stub), I'll create a "di" file, as follows: ~~~~~~~~~~~~~~~~~~~~~~ module SearchFactory; public import ISearchEngine; ISearchEngine create(); ~~~~~~~~~~~~~~~~~~~~~~ This is basically a stripped version of the original SearchFactory.d, using the same module name to ensure the namespace is compatible with the existing SearchFactory.obj. At this point we have our "di" file, an interface describing the abstract search engine, an obj file implementing the engine, and main.d as the client. We should now be able to remove the original SearchFactory.d from the distribution, since the "di" file is to be used instead; as a proxy. I'll rename SeachFactory.d to be SearchFactory.dd to investigate: dmd main ISearchEngine SearchFactory SearchFactory.d: module SearchFactory cannot read file 'SearchFactory.d' Hum. I'm having some difficulty parsing that message, though it seems to be saying that SearchFactory.d is missing. Well, yes. It is ... there's a "di" to take its place. So let's try to tell the compiler this by being explicit with the file extension: dmd main ISearchEngine SearchFactory.di Error: unrecognized file extension di Hum. That does not work either; though it's hardly surprising. Here's where I got the notion that I could use a "di" file:
 I can point to one side-effect that actually does help: the compiler now
 looks for "di" files, which means that hand-coded "implementation
 bridging" files can (at last!) live side-by-side with the real
 implementation module, eliminating some prior grief for a developer.
 However, this conflicts with -H rather badly, and therefore is likely to
 be an unintended and somewhat precarious benefit. Was that aspect
 considered?

Actually, it's intended. You can automatically build them, hand build them, or hand edit the automatically built one.

and here:
 It looks at each directory in the import path, first for a .di file, then 
 a
 .d file.

Yet, it really does seem like the "di" file is being completely ignored. I then introduced a syntax error within the "di" file, which wasn't reported.
 COM/interface/factory methodology in C++ does enable full hiding, however,
 and if you do that in D, you get full hiding as well.

I think I've followed the instructions available (thin as they are), to achieve what Walter describes above. Yet it does not appear to operate at all. Either it is broken, or D does not support decoupling as described above. Currently, the original (complete) source-code apparently has to exist side-by-side with the "di" file. This means that, say, a commercial enterprise will have to ship implementation source-code along with (or instead of) libraries or object files. It also appears to have serious implications for DDL. Does anyone know how this is supposed to work?
Jan 01 2006
parent reply Sean Kelly <sean f4.ca> writes:
Kris wrote:
 
 This is basically a stripped version of the original SearchFactory.d, using 
 the same module name to ensure the namespace is compatible with the existing 
 SearchFactory.obj. At this point we have our "di" file, an interface 
 describing the abstract search engine, an obj file implementing the engine, 
 and main.d as the client. We should now be able to remove the original 
 SearchFactory.d from the distribution, since the "di" file is to be used 
 instead; as a proxy. I'll rename SeachFactory.d to be SearchFactory.dd to 
 investigate:
 
 dmd main ISearchEngine SearchFactory
 SearchFactory.d: module SearchFactory cannot read file 'SearchFactory.d'
 
 Hum. I'm having some difficulty parsing that message, though it seems to be 
 saying that SearchFactory.d is missing. Well, yes. It is ... there's a "di" 
 to take its place. So let's try to tell the compiler this by being explicit 
 with the file extension:
 
 dmd main ISearchEngine SearchFactory.di
 Error: unrecognized file extension di
 
 Hum. That does not work either; though it's hardly surprising. Here's where 
 I got the notion that I could use a "di" file:

 Yet, it really does seem like the "di" file is being completely ignored. I 
 then introduced a syntax error within the "di" file, which wasn't reported.
 
 COM/interface/factory methodology in C++ does enable full hiding, however,
 and if you do that in D, you get full hiding as well.

I think I've followed the instructions available (thin as they are), to achieve what Walter describes above. Yet it does not appear to operate at all. Either it is broken, or D does not support decoupling as described above. Currently, the original (complete) source-code apparently has to exist side-by-side with the "di" file. This means that, say, a commercial enterprise will have to ship implementation source-code along with (or instead of) libraries or object files. It also appears to have serious implications for DDL. Does anyone know how this is supposed to work?

The .di file is a header and so should not be explicitly referenced during compilation. Using your example, I did this: C:\code\d\tst>dmd -c SearchFactory.d C:\code\d\tst>del SearchFactory.d C:\code\d\tst>dmd main.d ISearchEngine.d SearchFactory.obj C:\bin\dmd\bin\..\..\dm\bin\link.exe main+ISearchEngine+SearchFactory,,,user32+kernel32/noi; C:\code\d\tst>main searching for blah C:\code\d\tst> Sean
Jan 01 2006
parent reply "Kris" <fu bar.com> writes:
Thank you, Sean.

That's just what the doctor ordered, and a relief to see it still operates. 
Is any of this procedure documented on the D website, do you know? I looked 
but didn't find it.




"Sean Kelly" <sean f4.ca> wrote in message 
news:dpadu2$1dtk$1 digitaldaemon.com...
 Kris wrote:
 This is basically a stripped version of the original SearchFactory.d, 
 using the same module name to ensure the namespace is compatible with the 
 existing SearchFactory.obj. At this point we have our "di" file, an 
 interface describing the abstract search engine, an obj file implementing 
 the engine, and main.d as the client. We should now be able to remove the 
 original SearchFactory.d from the distribution, since the "di" file is to 
 be used instead; as a proxy. I'll rename SeachFactory.d to be 
 SearchFactory.dd to investigate:

 dmd main ISearchEngine SearchFactory
 SearchFactory.d: module SearchFactory cannot read file 'SearchFactory.d'

 Hum. I'm having some difficulty parsing that message, though it seems to 
 be saying that SearchFactory.d is missing. Well, yes. It is ... there's a 
 "di" to take its place. So let's try to tell the compiler this by being 
 explicit with the file extension:

 dmd main ISearchEngine SearchFactory.di
 Error: unrecognized file extension di

 Hum. That does not work either; though it's hardly surprising. Here's 
 where I got the notion that I could use a "di" file:

 Yet, it really does seem like the "di" file is being completely ignored. 
 I then introduced a syntax error within the "di" file, which wasn't 
 reported.

 COM/interface/factory methodology in C++ does enable full hiding, 
 however,
 and if you do that in D, you get full hiding as well.

I think I've followed the instructions available (thin as they are), to achieve what Walter describes above. Yet it does not appear to operate at all. Either it is broken, or D does not support decoupling as described above. Currently, the original (complete) source-code apparently has to exist side-by-side with the "di" file. This means that, say, a commercial enterprise will have to ship implementation source-code along with (or instead of) libraries or object files. It also appears to have serious implications for DDL. Does anyone know how this is supposed to work?

The .di file is a header and so should not be explicitly referenced during compilation. Using your example, I did this: C:\code\d\tst>dmd -c SearchFactory.d C:\code\d\tst>del SearchFactory.d C:\code\d\tst>dmd main.d ISearchEngine.d SearchFactory.obj C:\bin\dmd\bin\..\..\dm\bin\link.exe main+ISearchEngine+SearchFactory,,,user32+kernel32/noi; C:\code\d\tst>main searching for blah C:\code\d\tst> Sean

Jan 02 2006
parent Sean Kelly <sean f4.ca> writes:
Kris wrote:
 Thank you, Sean.
 
 That's just what the doctor ordered, and a relief to see it still operates. 
 Is any of this procedure documented on the D website, do you know? I looked 
 but didn't find it.

I don't think so. Sean
Jan 02 2006