www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Templated interfaces

reply James Dunne <james.jdunne gmail.com> writes:
This proposition might be a bit long, but I think it's worth a serious look.


PROPOSITION:
In a world of templated and generic programming, why hasn't the concept 
of the Interface been given much attention?  I often find myself wanting 
a templated container of elements, inheriting an interface of function 
names to call.  Anyone who has attempted to write such a container in D 
(or C# for that matter) will know what I'm talking about.  This post 
could be considered a proposition to extend D's interface concept to 
allow for templating function parameter types and return value types.


EXAMPLE CASE:
I want an interface to define a set of functions for inherited classes 
to call, but don't want to force the container type in the interface 
function declarations.  As far as I know, this is not possible with D, 
using interfaces at least.  One must create an abstract base class for 
types of items to store in containers inheriting from the interface and 
define the interface's functions on that base class.  Some code might help:

/* A base object to store */
public abstract IBaseObject {

}

/* My base interface for collections which can store IBaseObjects */
public interface IBaseObjectCollection {
	public IBaseObject	Add(IBaseObject x);
	public IBaseObject	opIndex(int i);
	.
	.
	.
}

/* Collection doing cool thing #1 with items */
public class Collection1(ItemType : IBaseObject) :
		IBaseObjectCollection
{
	ItemType[]	list;

	public IBaseObject	Add(IBaseObject x) {
		if (typeid(x) != typeid(ItemType))
			throw new Exception("Wrong type!");
		list ~= cast(ItemType)x;
	}

	public IBaseObject	opIndex(int i) {
		return list[i];
	}
}

/* Collection doing cool thing #2 with items */
public class Collection2(ItemType : IBaseObject) :
		IBaseObjectCollection
{
	ItemType[]	list;

	public IBaseObject	Add(IBaseObject x) {
		if (typeid(x) != typeid(ItemType))
			throw new Exception("Wrong type!");
		list ~= cast(ItemType)x;
// duplicated for sake of difference from Collection1
		list ~= cast(ItemType)x;
	}

	public IBaseObject	opIndex(int i) {
		return list[i];
	}
}


FINDINGS/PROBLEMS ON/WITH EXAMPLE CASE:
I have two classes inheriting from the IBaseObjectCollection interface, 
which means that the functions defined in the classes may only use the 
type IBaseObject, and not the ItemType object that the user actually 
wants to store.  With the template parameter specialization, ItemType is 
guaranteed to be inheriting IBaseObject, but casting (both implicit and 
explicit) is needed.

Also, the point of the templated collection is defeated as a 
strongly-typed collection.  From the user's perspective, the collection 
is perceived to be able to store any object inheriting IBaseObject, but 
this is misleading because the collection uses a dynamic array of type 
ItemType internally.

Finally, the templated collection may not store basic D types, like int, 
short, char[], etc. because they do not inherit from any class and 
cannot be made to be.  (At least in the sense of inheriting the 
collection from an interface, as is the case)


SOLUTION:
What is really needed is *templated interfaces*.  This will truly give 
interfaces the power they need to do their job right.  The interface 
will be defined more loosely, sort of as a guaranteed naming convention 
that all inheriting classes must follow.  Then, true strongly-typed 
collections can be defined and can in turn also be abstracted more.

For a code demonstration of this templated interface:

public interface ICollection(itemType) {
	public itemType	Add(itemType x);
	public itemType	Remove(int i);
	public itemType	opIndex(int i);
}

public class IntegerCollection : ICollection!(int) {
	int[]	list;

	public int Add(int x) {
		list ~= x;
	}

	public int Remove(int i) {
		...
	}

	public int opIndex(int i) {
		return list[i];
	}
}

Isn't that much simpler and cleaner?  This can be a very powerful 
feature for tying together concept-related, but /not necessarily/ 
type-related, classes and for enforcing strong naming conventions and 
general design patterns.

-- 
Regards,
James Dunne
Sep 12 2005
next sibling parent Derek Parnell <derek psych.ward> writes:
On Mon, 12 Sep 2005 20:05:13 -0500, James Dunne wrote:

 This proposition might be a bit long, but I think it's worth a serious look.
 
 PROPOSITION:

 to extend D's interface concept to allow for templating function parameter
 types and return value types.

Seems sensible and a useful simplification. It gave me a sort of "oh yeah, of course" reaction accompanied with a slap to one's forehead. -- Derek (skype: derek.j.parnell) Melbourne, Australia 13/09/2005 11:37:36 AM
Sep 12 2005
prev sibling parent reply "Ben Hinkle" <ben.hinkle gmail.com> writes:
 For a code demonstration of this templated interface:

 public interface ICollection(itemType) {
 public itemType Add(itemType x);
 public itemType Remove(int i);
 public itemType opIndex(int i);
 }

 public class IntegerCollection : ICollection!(int) {
 int[] list;

 public int Add(int x) {
 list ~= x;
 }

 public int Remove(int i) {
 ...
 }

 public int opIndex(int i) {
 return list[i];
 }
 }

hmm. works for me in dmd.130 out of the box (well, supply a Remove body and a main). Am I missing something?
Sep 12 2005
next sibling parent reply Derek Parnell <derek psych.ward> writes:
On Mon, 12 Sep 2005 21:44:41 -0400, Ben Hinkle wrote:

 For a code demonstration of this templated interface:

 public interface ICollection(itemType) {
 public itemType Add(itemType x);
 public itemType Remove(int i);
 public itemType opIndex(int i);
 }

 public class IntegerCollection : ICollection!(int) {
 int[] list;

 public int Add(int x) {
 list ~= x;
 }

 public int Remove(int i) {
 ...
 }

 public int opIndex(int i) {
 return list[i];
 }
 }

hmm. works for me in dmd.130 out of the box (well, supply a Remove body and a main). Am I missing something?

Well how about that! It's not documented so I assumed it wasn't implemented. I also tried other undocumented templating ideas and discovered that you can do templated structs too. struct SS(Type) { Type[] list; void opCall(Type x, int y) { list.length = y; list[] = x; } } void main() { SS!(int) A; SS!(real) B; A(3, 10); B(3.1472L, 5); } -- Derek (skype: derek.j.parnell) Melbourne, Australia 13/09/2005 12:04:22 PM
Sep 12 2005
parent reply James Dunne <james.jdunne gmail.com> writes:
Derek Parnell wrote:
 On Mon, 12 Sep 2005 21:44:41 -0400, Ben Hinkle wrote:
 
 
For a code demonstration of this templated interface:

public interface ICollection(itemType) {
public itemType Add(itemType x);
public itemType Remove(int i);
public itemType opIndex(int i);
}

public class IntegerCollection : ICollection!(int) {
int[] list;

public int Add(int x) {
list ~= x;
}

public int Remove(int i) {
...
}

public int opIndex(int i) {
return list[i];
}
}

hmm. works for me in dmd.130 out of the box (well, supply a Remove body and a main). Am I missing something?

Well how about that! It's not documented so I assumed it wasn't implemented. I also tried other undocumented templating ideas and discovered that you can do templated structs too. struct SS(Type) { Type[] list; void opCall(Type x, int y) { list.length = y; list[] = x; } } void main() { SS!(int) A; SS!(real) B; A(3, 10); B(3.1472L, 5); }

I have successfully tested such code and it works. I just naturally assumed it wouldn't when I wrote up the proposal. For that, I am slightly embarassed. It seems there's some general templating shorthand defined for all aggregate types (classes, interfaces, structs). Any hey - wow! That was the quickest acceptance and implementation of a proposal I've ever seen!! =P This is awesome!! Why isn't this documented?? I'm so unbelievably happy right now. -- Regards, James Dunne
Sep 12 2005
next sibling parent reply Sean Kelly <sean f4.ca> writes:
In article <dg5df7$b0q$1 digitaldaemon.com>, James Dunne says...
It seems there's some general templating shorthand defined for all 
aggregate types (classes, interfaces, structs).

Yup. Templates in D are very consistent. The only thing I occasionally miss is a shorthand for template functions.
This is awesome!!  Why isn't this documented??  I'm so unbelievably 
happy right now.

The first rule of D is that you don't document D ;-) Sean
Sep 12 2005
parent "Walter Bright" <newshound digitalmars.com> writes:
"Sean Kelly" <sean f4.ca> wrote in message
news:dg5koe$gdh$1 digitaldaemon.com...
 The first rule of D is that you don't document D ;-)

Ouch!
Sep 14 2005
prev sibling parent "Walter Bright" <newshound digitalmars.com> writes:
"James Dunne" <james.jdunne gmail.com> wrote in message
news:dg5df7$b0q$1 digitaldaemon.com...
 Any hey - wow!  That was the quickest acceptance and implementation of a
 proposal I've ever seen!! =P

What's kinda neat about it is that the syntax is exactly what you expected it to be.
 This is awesome!!  Why isn't this documented??

Because writing documentation is not one of my favorite activities and I tend to avoid it <g>. I recently did a quick look at the Phobos documentation, and it stinks. The best solution I can think of is to proceed with writing Ddoc, which should cut the effort for documenting the library by half or more. This won't help with the language spec, though.
 I'm so unbelievably happy right now.

Sep 14 2005
prev sibling parent James Dunne <james.jdunne gmail.com> writes:
Ben Hinkle wrote:
For a code demonstration of this templated interface:

public interface ICollection(itemType) {
public itemType Add(itemType x);
public itemType Remove(int i);
public itemType opIndex(int i);
}

public class IntegerCollection : ICollection!(int) {
int[] list;

public int Add(int x) {
list ~= x;
}

public int Remove(int i) {
...
}

public int opIndex(int i) {
return list[i];
}
}

hmm. works for me in dmd.130 out of the box (well, supply a Remove body and a main). Am I missing something?

No, but I think I might've. =P Feeling a bit sheepish now... I'll do some tests and check the front-end code to ensure this is really implemented yet undocumented. -- Regards, James Dunne
Sep 12 2005