February 29, 2008 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | 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 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | 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 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Christopher Wright | 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 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | 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 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | "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 Re: Syntactic Sugar for Virtual Constructors? | ||||
---|---|---|---|---|
| ||||
Posted in reply to Janice Caron | 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.
|
Copyright © 1999-2021 by the D Language Foundation