digitalmars.D.announce - Decoupling implementation from usage
- Kris (111/137) Jan 01 2006 I'm really confused as to how D can decouple implementation from usage. ...
- Sean Kelly (13/54) Jan 01 2006 The .di file is a header and so should not be explicitly referenced
- Kris (6/62) Jan 02 2006 Thank you, Sean.
- Sean Kelly (3/8) Jan 02 2006 I don't think so.
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> wroteYou 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:and here: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.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? begin 666 SearchFactory.zip M2\_,2P7+HX H)!>E)I:D:FA:`P!02P,$% ```` `48,A-"/8/Q%'````7P`` MRLPK22U*2TQ&D^/EJN;E4H""LOS,%(5BL*R"1G)&8E%TK )05VZQ)M"(6I I M`%!+`P04````" "U R$T]M=5HU<```!I````! ```&UA:6XN9"LHRBQ++$E5 MR,PMR"\J40A.32Q*SG!+3"[)+ZJTYN7BY2K+STQ1R$W,S-/0Y.6JYN52 (+$ MTI)\A6(%6X7DHE2 `1J:U BY8KUBL#D:2DDYB1E*(*E:`%!+`P04````" !X MC"$T&&Z EJ4````O`0``#P MX>-*H?0`==U"UUV6+M(X:D 3F42E%.]>JQ:U`[/Z_PUO:I>U%>%&BG5Y43HX M?J522-&TS\IHF+IQ''"="V=;&$M3O 0^9,=QC9LA-IT*!%TI[[%E<-K?D.(M M!9;IG,G IQ2Q+A7?'PC$M4_6SJ;^FYY-H+RRB*,9-K9 [AC18<'3%1JD&+Z* M.PMHIM$W3G8Z3*%E"TL]_MX>/E!+`0(4`!0````(`)>,(31%C<MF0 ```% ` M```0``````````$`( ````````!396%R8VA&86-T;W)Y+F1I4$L!`A0`% `` M`` `48,A-"/8/Q%'````7P````\``````````0` ````; ```$E396%R8VA% M( ```.(```!M86EN+F102P$"% `4````" !XC"$T&&Z EJ4````O`0``#P`` M```````!`" ```!=`0``4V5A<F-H1F%C=&]R>2YD4$L%! `````$``0`[ `` '`"\"```````` ` end
Jan 01 2006
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:[snip]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.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> SeanCOM/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
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:[snip]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.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> SeanCOM/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 02 2006
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