www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Feature request: interfaces declare types

reply Henning Hasemann <hhasemann web.de> writes:
Imagine, you want to write a STL-alike thingy.
You might come to a point, where you want to define an interface that describes
what all your containers (or a special group of them) have in common.
Say:

interface Container(T) {
  T first();
  void remove(T);
}

K, no problem here. But now say you want to extend it to use iterators.
Obviously all your iterators will share an interface. Something like:

interface Iterator(T) {
  T content();
}

No question your iterators will be implemented very differently.
A linked list might put prev and next pointers into it, while
a data structure based on an array might store an elements index.
Lets adapt our Container:

interface Container(T) {
  T first();
  void remove(T);

  Iterator(T) firstIterator();
  void remove(Iterator(T));
}

... but wait! Every implementation of Container(T) will always only accept its
own iterators!
Only way to solve this is to have every remove() method cast the parameter
to its internal used iterator class at runtime, which shouldnt be necessary.

What I request is to be able to write something like:

interface ContainerIterator(T) {
  T content();
}

interface Container(T) {
  type Iterator : ContainerIterator!(T);
  
  T first();
  void remove(T);
  Iterator(T) firstIterator();
  void remove(Iterator(T));
}

In this example the imaginary "type" keyword says:
Whatever class wants to implement this interface has to define a type Iterator
(through a nested class, alias whatever) that in turn is derived from
ContainerIterator!(T).

So in the interface, this type can be used for return and parameter types,
anyone who uses this interface can access the type, too and all neccessary
type-checking could be done at compile time with no additional cost.

Usage example:

// I dont care what container they use
class Foo {
  Container(int) someNumbers;
  // ...
  int popNumber() {
    Container(int).Iterator nr = someNumbers.firstIterator();
    int r = nr.content();
    someNumbers.remove(nr);
    return r;
  }
}

-- 
GPG Public Key: http://keyserver.veridis.com:11371/search?q=0x41911851
Fingerprint: 344F 4072 F038 BB9E B35D  E6AB DDD6 D36D 4191 1851
May 23 2007
parent reply Reiner Pope <some address.com> writes:
Henning Hasemann wrote:
 What I request is to be able to write something like:
 
 interface ContainerIterator(T) {
   T content();
 }
 
 interface Container(T) {
   type Iterator : ContainerIterator!(T);
   
   T first();
   void remove(T);
   Iterator(T) firstIterator();
   void remove(Iterator(T));
 }
I'm not sure if this does what you want: interface Container(T, Iterator) { alias T Type; alias Iterator IteratorType; static assert(is(Iterator : ContainerIterator!(T))); T first(); void remove(T); Iterator firstIterator(); void remove(Iterator); } class ListIterator(T) : ContainerIterator!(T) { ... } class LinkedList(T) : Container!(T, ListIterator!(T)) { ... }
 Usage example:
 
 // I dont care what container they use
 class Foo {
   Container(int) someNumbers;
   // ...
   int popNumber() {
     Container(int).Iterator nr = someNumbers.firstIterator();
     int r = nr.content();
     someNumbers.remove(nr);
     return r;
   }
 }
 
My code doesn't entirely suit your use-case, but it does something similar: class Foo (ContainerType) { ContainerType someNumbers; int popNumber() { ContainerType.Iterator nr = someNumbers.firstIterator(); ... } } Your given usage example is a long way from D's type system: interfaces are dynamic in nature, so you would expect the Iterator type specified by it only to be known dynamically. But when you use types, you have to know them statically. I think what you are after would be better solved by some kind of Concepts. Cheers, Reiner
May 23 2007
parent Henning Hasemann <hhasemann web.de> writes:
On Thu, 24 May 2007 07:49:50 +1000
Reiner Pope <some address.com> wrote:

 
 My code doesn't entirely suit your use-case, but it does something similar:
 
 class Foo (ContainerType)  {
      ContainerType someNumbers;
 
      int popNumber() {
          ContainerType.Iterator nr = someNumbers.firstIterator();
          ...
      }
 }
 
 Your given usage example is a long way from D's type system: interfaces 
 are dynamic in nature, so you would expect the Iterator type specified 
 by it only to be known dynamically. But when you use types, you have to 
 know them statically.
The point with my example is working with a container you dont know the explicit type of. Imagine some function returns a bunch of items like this: Container(int) getMyItems(); Now you want to work with this bunch of items and you want to use iterators. So your example doesnt seem to help me, because I need to know the Iterator type in advance in order to use Container(). But if I knew that at that time I knew the Container type as well, so I wouldnt have to work with the interface. But I see the problem you mentioned: If I have Container(int) a = getMyItems(); a.Iterator would be one type and if I then do a = getSomeOtherItem(); a.Iterator might be another which the type system shouldnt be able to handle because that choice might depend on runtime cirumstances.
 I think what you are after would be better solved by some kind of Concepts.
Sorry I'm not sure I get what you mean with "some kind of Concepts", could you be more specific? Henning -- GPG Public Key: http://keyserver.veridis.com:11371/search?q=0x41911851 Fingerprint: 344F 4072 F038 BB9E B35D E6AB DDD6 D36D 4191 1851
May 23 2007