Jump to page: 1 2
Thread overview
Syntactic Sugar for Virtual Constructors?
Feb 28, 2008
Janice Caron
Feb 28, 2008
Janice Caron
Feb 28, 2008
BCS
Feb 28, 2008
Janice Caron
Feb 28, 2008
BCS
Feb 29, 2008
Christopher Wright
Feb 28, 2008
Christopher Wright
Feb 28, 2008
Robert Fraser
Feb 28, 2008
Janice Caron
Feb 28, 2008
Robert Fraser
Feb 29, 2008
Christopher Wright
Feb 29, 2008
Janice Caron
Mar 01, 2008
Christopher Wright
Feb 29, 2008
Bill Baxter
February 28, 2008
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?
February 28, 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?

what about static opCall?

class MyClass
{
       static MyClass opCall(string s)
       {
            // have to implement factoryString
            return cast(MyClass)Object.factory(factoryString(s));
       }
}

auto x = MyClass(s);

then you could also make the opCall method a mixin to avoid reimplementation.

-Steve


February 28, 2008
Janice Caron wrote:
> 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.

But in a fragile way, and bound to the language. A library solution that takes the pain out of writing factories would be more general, more flexible, and less work for Walter. And, hey, it probably does 80% of what you need, today. Except for you having to map IANA strings to classes. And since major dependency injection libraries don't support this, you're SOL: it's not enough of a use case to include there, so it certainly isn't enough of a use case for a language solution.
February 28, 2008
On 28/02/2008, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> what about static opCall?

Ooh - I never thought of that. That's close.

In the past, what I've done is to build a standalone function (not a member function) called new_MyClass(), which is only an underscore different from the standard "new" function. Ditching the word "new" altogether is attractive.

But to clarify - it's the syntactic sugar of being able to say

    new AbstractBaseClass(...)

(and end up with a derived class) that I was asking for. I am well aware that we already have the functionality, but the point of the request /is/ the sugar. It's not that I want the syntax to be "simpler than it is now", or something, it's that I want it to be /identical/ other uses of new. It's just one of those nice little touches that would make D seem more cool. :-)
February 28, 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?

Why not just return the instance of MyClass? More flexible, since it doesn't need to have a default constructor in the general case:

abstract class MyClass
{
    static string opFactory(/*params*/)
    {
        /* returns a MyClass */
    }
}

That would cover the more common case of all the factory's types being known by the implmentation. Then for the case you needed, you can explicitly call Object#factory(string) from within the static opFactory and explicitly do the cast. Still just as nice on the call site, but more flexible for the implementor.
February 28, 2008
Janice Caron wrote:
> On 28/02/2008, Steven Schveighoffer <schveiguy@yahoo.com> wrote:
> 
>>what about static opCall?
> 
> 
> Ooh - I never thought of that. That's close.
> 
> In the past, what I've done is to build a standalone function (not a
> member function) called new_MyClass(), which is only an underscore
> different from the standard "new" function. Ditching the word "new"
> altogether is attractive.
> 
> But to clarify - it's the syntactic sugar of being able to say
> 
>     new AbstractBaseClass(...)
> 


how about allow this functions in abstract classes

abstract class AbstractBaseClass
{
	AbstractBaseClass this(string s, int i)
	{
		switch(s)
		{
			case "Foo": return new DerivedClass(i);
			...
			default: return null;
				// check code causes exception
		}
	}
}

the return type could be used to detect the usage.


> (and end up with a derived class) that I was asking for. I am well
> aware that we already have the functionality, but the point of the
> request /is/ the sugar. It's not that I want the syntax to be "simpler
> than it is now", or something, it's that I want it to be /identical/
> other uses of new. It's just one of those nice little touches that
> would make D seem more cool. :-)
February 28, 2008
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.
February 28, 2008
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.
February 28, 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;
>>                }
>>        }
> 

your point is valid (in some cases) but totally orthogonal to mine. Re wright it as this:

AbstractBaseClass this(string s, int i)
{
	// code to return a sub type of
	// AbstractBaseClass based on value of s
	// or null on an argument error so that
	// check code causes exception
}

and no important feature of my suggestion is changed but your point vanishes.

> 
> The switch is the one thing that you /must not have/. The factory
> cannot possibly know all possible (present and future) derived
> classes.

But it might /in some cases/ known all the /valid/ ones

> Putting that switch statement there prevents anyone without
> access to the source code from making new derived classes,

Re-read that last, but in a "good thing" context. in some cases it will be a good thing.

> making the
> mechanism completely unworkable for a library.

over generalized: unworkable for /some/ (or even many) libraries

> Also, this mechanism
> needs to import all of the module(s) where the derived class(es)
> is/are defined, which is also bad.

In line with the above point of view; this is unavoidable for some cases.

> 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.

Every possible derived class that can get used at run time will have to be available some how for any solution. The only escape would be lazy loading of DLL's or SO's and that can be used in my solution as well.

> 
> The good way to implement a factory function is to call the function
> object.Factory(). That way, the factory function needs 


> [the function will have] /no knowledge/
> of the derived class, beyond it's class name,

read that in a "bad thing" context. Again, it can be.

BTW, I was not proposing that my solution is a better way to do what you are looking to do, I'm proposing it as a clean solution that can do something more general than what you are looking for.
February 28, 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.

Why not generate the string and then call Object.factory() from within that virtual constructor if you need the functionality, and for a typical factory that knows about all the subclasses, allow the cool syntax?
« First   ‹ Prev
1 2