February 29, 2008
Janice Caron wrote:
> On 28/02/2008, Robert Fraser <fraserofthenight@gmail.com> wrote:
>> Why not just return the instance of MyClass? More flexible, since it
>>  doesn't need to have a default constructor in the general case:
> 
> No, that would be /less/ flexible, since the factory function would
> have to know about every possible derived class at compile time. The
> whole point of a generic factory function is that it has no
> compile-time knowledge of the derived classes. /All/ information about
> derived classes is delayed until runtime.
> 
> The only practical way to do that is to call Object.factory(), and
> since Object.factory() takes a string parameter, a string is what the
> function needs to supply.

So, generate these strings at runtime? The solution:
AbstractBaseClass delegate () [string] builders;

class Derived : AbstractBaseClass
{
   static this ()
   {
      builders["whatever"] = { return new Derived1(); };
   }
}


Of course, you're just talking about syntactic sugar. In this case, I'm quite opposed, since it violates the typical expectation that typeof (new T) == T.
February 29, 2008
Janice Caron wrote:
> On 28/02/2008, BCS <BCS@pathlink.com> wrote:
>>         AbstractBaseClass this(string s, int i)
>>         {
>>                 switch(s)
>>                 {
>>                         case "Foo": return new DerivedClass(i);
>>                         ...
>>                         default: return null;
>>                                 // check code causes exception
>>                 }
>>         }
> 
> The switch is the one thing that you /must not have/. The factory
> cannot possibly know all possible (present and future) derived
> classes. Putting that switch statement there prevents anyone without
> access to the source code from making new derived classes, making the
> mechanism completely unworkable for a library. Also, this mechanism
> needs to import all of the module(s) where the derived class(es)
> is/are defined, which is also bad. Also, the function above would
> cause "executable bloat", whereby every possible derived class will
> end up in every executable which calls that function, whether needed
> or not.
> 
> The good way to implement a factory function is to call the function
> object.Factory(). That way, the factory function needs /no knowledge/
> of the derived class, beyond it's class name, extendability is
> retained, and executable bloat is avoided.

A better way:
abstract class AbstractBaseClass
{
   // that type is probably wrong; I can't comprehend how to name
   // delegate types
   static AbstractBaseClass delegate ()[string] builders;
   static AbstractBaseClass factory(string str)
   {
      return builders[str]();
   }
}

class Derived : AbstractBaseClass
{
   static this ()
   {
      AbstractBaseClass.builders["something"] =
         { return new Derived(); }
   }
}
February 29, 2008
On 29/02/2008, Christopher Wright <dhasenan@gmail.com> wrote:

>  class Derived : AbstractBaseClass
>  {
>     static this ()
>     {
>        builders["whatever"] = { return new Derived1(); };
>     }
>  }

Again, that would require the factory function to have compile-time knowledge of derived classes, which is precisely the thing to avoid.
February 29, 2008
Janice Caron wrote:
> Something Andrei said got me thinking.
> 
> I have a need for so-called "virtual constructors", and of course D
> has Object.factory() which just does the job, given the classname.
> (/Much/ nicer than C++!). But, in my case, the discriminator string
> won't be the class name (which may be unknown to the user), but one of
> a number of IANA-registered strings, documented in some internet RFC
> somewhere. So to deal with that, I need a "factory". The usual way of
> doing this is, given
> 
>     string s = whatever; // official name
> 
> something like:
> 
>     auto x = MyClassFactory.create(s);
> 
> And that's OK, but it does mean that polymorphic creation is still
> "different" from normal creation. I got thinking, wouldn't it be nice
> if I could just do
> 
>     auto x = new MyClass(s);
> 
> and have it work. Now bear in mind that MyClass is an /abstract/
> class. It can never be constructed. Only subclasses can be
> constructed, and that, of course, is the job of a factory. What I'm
> suggesting, then, is just syntactic sugar. It won't give us anything
> we can't do already, but it will let us do it with a nicer syntax.
> 
> To make it work, you'd have to allow a class to have a factory within
> itself, and so what I propose is the following syntax:
> 
>     abstract class MyClass
>     {
>         static string opFactory(/*params*/)
>         {
>             /* returns a string */
>         }
>     }
> 
> Notice that I typed the opFactory function to return a string. The idea is that
> 
>     auto x = new MyClass(s);
> 
> would be rewritten by the compiler as
> 
>     auto x = enforce(cast(MyClass)Object.factory(MyClass.opFactory(s)));
> 
> whenever the class is abstract and static opFactoryis present. So what
> opNew needs to return is the string to pass to Object.factory. Observe
> the explicit cast in the rewritten line. That is there partly so that
> x gets the right type (at compile time), but also to ensure at runtime
> that the factory-created class is in fact a subclass of MyClass!
> 
> (enforce is one of Andrei's new templates that throws an exception if
> the value is non-zero. I think it will also check for null, but if
> not, I'm sure it can be made to).
> 
> I'm sure that better alternative names for opFactory can be thought
> up. Off the top of my head, I came up with opNew, opClass, opNewName,
> opClassName and opFactoryName.
> 
> Thoughts?

I don't see why
   auto x = new MyClass(s);
is any better than
   auto x = MyClass.create(s);

Except the first looks like normal construction, even though it's not, while the second screams out clearly "I'm a static factory method".

So the second one seems preferable to me.  Less magic going on to keep track of in your head.

--bb
February 29, 2008
"Janice Caron" <caron800@googlemail.com> wrote in message news:mailman.89.1204269640.2351.digitalmars-d@puremagic.com...
> On 29/02/2008, Christopher Wright <dhasenan@gmail.com> wrote:
>
>>  class Derived : AbstractBaseClass
>>  {
>>     static this ()
>>     {
>>        builders["whatever"] = { return new Derived1(); };
>>     }
>>  }
>
> Again, that would require the factory function to have compile-time knowledge of derived classes, which is precisely the thing to avoid.

Not necessarily.  If Derived were in a shared object, it would be loaded and then its static this() run, which would add itself to the list of builders in the base class, entirely at runtime.


March 01, 2008
Janice Caron wrote:
> On 29/02/2008, Christopher Wright <dhasenan@gmail.com> wrote:
> 
>>  class Derived : AbstractBaseClass
>>  {
>>     static this ()
>>     {
>>        builders["whatever"] = { return new Derived1(); };
>>     }
>>  }
> 
> Again, that would require the factory function to have compile-time
> knowledge of derived classes, which is precisely the thing to avoid.

You could try reading the code you're commenting on :P though there was a typo, I admit.

It was the derived class adding a delegate to a static array in the base class. The base class doesn't, technically speaking, know anything about any derived classes, and you don't get any of that circular dependency madness.
1 2
Next ›   Last »