View mode: basic / threaded / horizontal-split · Log in · Help
February 28, 2008
Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
"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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Re: Syntactic Sugar for Virtual Constructors?
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
Top | Discussion index | About this forum | D home