www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Factory design

reply John C <johnch_atms hotmail.com> writes:
So I've got an abstract class with a factory method. Users call the 
factory method to instantiate an instance. It calls a function which 
modules that contain the contrete class must implement.

But I'm getting linking errors. OptLink thinks 'createXmlReaderImpl' is 
undefined, presumably because it's expecting the body to be contained in 
the same module.

Note that if 'createXmlReaderImpl' is declared with 'extern(C)', then it 
links without errors.

I've seen a similar technique used before. The main entry point in 
dmain.d in phobos, for example. Ideas?

module model;

// Modules containing the concrete class implement this.
XmlReader createXmlReaderImpl(Stream input);

abstract class XmlReader {

   static XmlReader create(Stream input) {
     return createXmlReaderImpl(input);
   }

   // Abstract methods...

}

// impl1 implementation wraps some C library.
module impl1;
import model;

XmlReader createXmlReaderImpl(Stream input) {
   return new XmlReaderImpl(input);
}

class XmlReaderImpl : XmlReader {

   // Implements XmlReader's abstract methods

   private this(Stream input) ...

}

// impl2 implementation wraps some other C library.
module impl2;
import model;

XmlReader createXmlReaderImpl(Stream input) {
   return new XmlReaderImpl(input);
}

class XmlReaderImpl : XmlReader {

   // Implements XmlReader's abstract methods

   private this(Stream input) ...

}

// User code that chooses which implementation to use.
module program;
import model, impl1; // Choosing impl1

void main() {
   Stream s = ...;
   XmlReader reader = XmlReader.create(s);
}

Thanks,
John.
May 28 2006
next sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"John C" <johnch_atms hotmail.com> wrote in message 
news:e5ddb1$17kq$1 digitaldaemon.com...

 Note that if 'createXmlReaderImpl' is declared with 'extern(C)', then it 
 links without errors.
Did you try just putting "extern" (or "extern(D)") in front of both the prototype and the definition?
May 28 2006
parent reply John C <johnch_atms hotmail.com> writes:
Jarrett Billingsley wrote:
 "John C" <johnch_atms hotmail.com> wrote in message 
 news:e5ddb1$17kq$1 digitaldaemon.com...
 
 
Note that if 'createXmlReaderImpl' is declared with 'extern(C)', then it 
links without errors.
Did you try just putting "extern" (or "extern(D)") in front of both the prototype and the definition?
I did - I get the same linking errors. extern(C) works because the name of the function doesn't get mangled.
May 28 2006
parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"John C" <johnch_atms hotmail.com> wrote in message 
news:e5dgdt$1as6$1 digitaldaemon.com...

 extern(C) works because the name of the function doesn't get mangled.
Ohhhh yeah. I ran into the same thing on another thread about 15 down from this one.. This is a real problem. Mangling function names with module names is a good idea on the surface, but it makes it impossible to declare a function in one module and define it in another without some ugly hacks and serious restrictions. Something needs to be done to solve this, such as not mangling module names into the names of functions which are declared "extern."
May 28 2006
parent "Ameer Armaly" <ameer_armaly hotmail.com> writes:
"Jarrett Billingsley" <kb3ctd2 yahoo.com> wrote in message 
news:e5dju8$1dol$1 digitaldaemon.com...
 "John C" <johnch_atms hotmail.com> wrote in message 
 news:e5dgdt$1as6$1 digitaldaemon.com...

 extern(C) works because the name of the function doesn't get mangled.
Ohhhh yeah. I ran into the same thing on another thread about 15 down from this one.. This is a real problem. Mangling function names with module names is a good idea on the surface, but it makes it impossible to declare a function in one module and define it in another without some ugly hacks and serious restrictions. Something needs to be done to solve this, such as not mangling module names into the names of functions which are declared "extern."
I agree. Perhaps with some sort of marker to designate them as module-independent if you will; you would be saying with extern that this function is meant to be declared anywhere.
 
May 28 2006
prev sibling parent Carlos Santander <csantander619 gmail.com> writes:
John C escribió:
 So I've got an abstract class with a factory method. Users call the 
 factory method to instantiate an instance. It calls a function which 
 modules that contain the contrete class must implement.
 
 But I'm getting linking errors. OptLink thinks 'createXmlReaderImpl' is 
 undefined, presumably because it's expecting the body to be contained in 
 the same module.
 
 Note that if 'createXmlReaderImpl' is declared with 'extern(C)', then it 
 links without errors.
 
 I've seen a similar technique used before. The main entry point in 
 dmain.d in phobos, for example. Ideas?
 
 module model;
 
 // Modules containing the concrete class implement this.
 XmlReader createXmlReaderImpl(Stream input);
 
How about putting it in an abstract class, say a singleton?
 abstract class XmlReader {
 
   static XmlReader create(Stream input) {
     return createXmlReaderImpl(input);
   }
 
   // Abstract methods...
 
 }
 
 // impl1 implementation wraps some C library.
 module impl1;
 import model;
 
 XmlReader createXmlReaderImpl(Stream input) {
   return new XmlReaderImpl(input);
 }
 
 class XmlReaderImpl : XmlReader {
 
   // Implements XmlReader's abstract methods
 
   private this(Stream input) ...
 
 }
 
 // impl2 implementation wraps some other C library.
 module impl2;
 import model;
 
 XmlReader createXmlReaderImpl(Stream input) {
   return new XmlReaderImpl(input);
 }
 
 class XmlReaderImpl : XmlReader {
 
   // Implements XmlReader's abstract methods
 
   private this(Stream input) ...
 
 }
 
 // User code that chooses which implementation to use.
 module program;
 import model, impl1; // Choosing impl1
 
 void main() {
   Stream s = ...;
   XmlReader reader = XmlReader.create(s);
 }
 
 Thanks,
 John.
-- Carlos Santander Bernal
May 28 2006