View mode: basic / threaded / horizontal-split · Log in · Help
May 24, 2010
To interface or not to interface
A long discussion on the utility of interfaces has taken place on the  
announce newsgroup following my announcement of dcollections for D2.

Dcollections supports interfaces peripherally.  Meaning the types in  
dcollections are essentially concrete classes with interfaces tacked on  
for cases where interfaces make sense.

Whenever I've used dcollections (D1 included) I don't think I've ever used  
the interface for a container, only the concrete type.  But within  
dcollections, there's some functions that use the interface type to do  
(IMO) nifty things like compare two sets that have different  
implementations.

The general consensus is that interfaces for dcollections do not add any  
meaningful value, and that I should do everything with generic programming  
and templates.  My view is that interfaces are useful for binary  
compatibility and in reducing the footprint of executables.  But that  
doesn't mean much at the moment, because D is statically linked.

I'd ask the naysayers of interfaces for dcollections, and also the  
supporters: what is the point of having interfaces in D?  Are interfaces  
pretty much obsolete, and I am just nostalgic about their utility?

What do you think?

-Steve
May 24, 2010
Re: To interface or not to interface
Steven Schveighoffer wrote:
> I'd ask the naysayers of interfaces for dcollections, and also the 
> supporters: what is the point of having interfaces in D?  Are interfaces 
> pretty much obsolete, and I am just nostalgic about their utility?

Interfaces are for runtime polymorphism, rather than compile time polymorphism. 
They are especially useful for things like:

1. runtime plugin interfaces
2. designs where strict implementation hiding is desired
3. to have binary libraries (shared and static)
4. to support Java/C# style coding
5. reduced code memory footprint
6. experience shows they are an excellent fit for user interfaces


Compile time polymorphism, such as what templates provide, are most useful for:

1. maximum performance
2. minimal data memory consumption
3. better compile time checking


I believe the tradeoffs for collection types favor compile time polymorphism 
because:

1. performance is often critical for collections
2. C++ STL has shown the success of this approach
3. collections must fit in naturally with ranges, and ranges are compile time 
polymorphic
May 24, 2010
Re: To interface or not to interface
On Mon, 24 May 2010 14:10:26 -0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> I'd ask the naysayers of interfaces for dcollections, and also the  
>> supporters: what is the point of having interfaces in D?  Are  
>> interfaces pretty much obsolete, and I am just nostalgic about their  
>> utility?
>
> Interfaces are for runtime polymorphism, rather than compile time  
> polymorphism. They are especially useful for things like:
>
> 1. runtime plugin interfaces
> 2. designs where strict implementation hiding is desired
> 3. to have binary libraries (shared and static)
> 4. to support Java/C# style coding
> 5. reduced code memory footprint
> 6. experience shows they are an excellent fit for user interfaces
>
>
> Compile time polymorphism, such as what templates provide, are most  
> useful for:
>
> 1. maximum performance
> 2. minimal data memory consumption
> 3. better compile time checking
>
>
> I believe the tradeoffs for collection types favor compile time  
> polymorphism because:
>
> 1. performance is often critical for collections
> 2. C++ STL has shown the success of this approach
> 3. collections must fit in naturally with ranges, and ranges are compile  
> time polymorphic

I'd counter point 2 by saying that 1. C++ classes are value-types by  
default and 2. C++ doesn't have interfaces, so it's not exactly fair to  
say that the STL author considered interfaces but rejected them.

and on point 3, why is it not OK to *also* provide interfaces in addition  
to ranges as dcollections does?  That is, take away dcollections'  
interfaces, and you have essentially compile-time polymorphism, they all  
support ranges etc.  Interfaces are also there in case you want to use  
them in things like runtime plugin interfaces.

Basically, my point is, compile time interfaces does not mean you can't  
also have runtime interfaces.  In fact, interfaces can be compile-time  
parameterized.

Also, much of a user interface consists of various collections (listview,  
treeview, child widgets, etc.).  Why is runtime polymorphism good there,  
but not on a generic collections package (not as the only means of access  
of course)?

-Steve
May 24, 2010
Re: To interface or not to interface
Steven Schveighoffer wrote:
> On Mon, 24 May 2010 14:10:26 -0400, Walter Bright 
> <newshound1@digitalmars.com> wrote:
> 
>> Steven Schveighoffer wrote:
>>> I'd ask the naysayers of interfaces for dcollections, and also the 
>>> supporters: what is the point of having interfaces in D?  Are 
>>> interfaces pretty much obsolete, and I am just nostalgic about their 
>>> utility?
>>
>> Interfaces are for runtime polymorphism, rather than compile time 
>> polymorphism. They are especially useful for things like:
>>
>> 1. runtime plugin interfaces
>> 2. designs where strict implementation hiding is desired
>> 3. to have binary libraries (shared and static)
>> 4. to support Java/C# style coding
>> 5. reduced code memory footprint
>> 6. experience shows they are an excellent fit for user interfaces
>>
>>
>> Compile time polymorphism, such as what templates provide, are most 
>> useful for:
>>
>> 1. maximum performance
>> 2. minimal data memory consumption
>> 3. better compile time checking
>>
>>
>> I believe the tradeoffs for collection types favor compile time 
>> polymorphism because:
>>
>> 1. performance is often critical for collections
>> 2. C++ STL has shown the success of this approach
>> 3. collections must fit in naturally with ranges, and ranges are 
>> compile time polymorphic
> 
> I'd counter point 2 by saying that 1. C++ classes are value-types by 
> default and 2. C++ doesn't have interfaces, so it's not exactly fair to 
> say that the STL author considered interfaces but rejected them.

C++ certainly does have interfaces. The whole COM system is based on them, for 
example. Technically, D interfaces are just a subset of C++ multiple inheritance.

> and on point 3, why is it not OK to *also* provide interfaces in 
> addition to ranges as dcollections does?  That is, take away 
> dcollections' interfaces, and you have essentially compile-time 
> polymorphism, they all support ranges etc.  Interfaces are also there in 
> case you want to use them in things like runtime plugin interfaces.

The best reason I can think of is to avoid kitchen-sink style components. 
Components should do one thing well. Adding capability should be done with 
aggregation by the user.


> Basically, my point is, compile time interfaces does not mean you can't 
> also have runtime interfaces.  In fact, interfaces can be compile-time 
> parameterized.

Sure, but I'd argue that adding such runtime polymorphism should be done with a 
separate add-on component. It should not be part of the collection component.


> Also, much of a user interface consists of various collections 
> (listview, treeview, child widgets, etc.).  Why is runtime polymorphism 
> good there, but not on a generic collections package (not as the only 
> means of access of course)?

A user interface object is not a collection component, I think there's a 
confusion in the design there.
May 24, 2010
Re: To interface or not to interface
On Mon, 24 May 2010 14:36:57 -0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> On Mon, 24 May 2010 14:10:26 -0400, Walter Bright  
>> <newshound1@digitalmars.com> wrote:
>>
>>> Steven Schveighoffer wrote:
>>>> I'd ask the naysayers of interfaces for dcollections, and also the  
>>>> supporters: what is the point of having interfaces in D?  Are  
>>>> interfaces pretty much obsolete, and I am just nostalgic about their  
>>>> utility?
>>>
>>> Interfaces are for runtime polymorphism, rather than compile time  
>>> polymorphism. They are especially useful for things like:
>>>
>>> 1. runtime plugin interfaces
>>> 2. designs where strict implementation hiding is desired
>>> 3. to have binary libraries (shared and static)
>>> 4. to support Java/C# style coding
>>> 5. reduced code memory footprint
>>> 6. experience shows they are an excellent fit for user interfaces
>>>
>>>
>>> Compile time polymorphism, such as what templates provide, are most  
>>> useful for:
>>>
>>> 1. maximum performance
>>> 2. minimal data memory consumption
>>> 3. better compile time checking
>>>
>>>
>>> I believe the tradeoffs for collection types favor compile time  
>>> polymorphism because:
>>>
>>> 1. performance is often critical for collections
>>> 2. C++ STL has shown the success of this approach
>>> 3. collections must fit in naturally with ranges, and ranges are  
>>> compile time polymorphic
>>  I'd counter point 2 by saying that 1. C++ classes are value-types by  
>> default and 2. C++ doesn't have interfaces, so it's not exactly fair to  
>> say that the STL author considered interfaces but rejected them.
>
> C++ certainly does have interfaces. The whole COM system is based on  
> them, for example. Technically, D interfaces are just a subset of C++  
> multiple inheritance.

And if STL looked like COM, I think it would have been a miserable failure  
indeed.

>
>> and on point 3, why is it not OK to *also* provide interfaces in  
>> addition to ranges as dcollections does?  That is, take away  
>> dcollections' interfaces, and you have essentially compile-time  
>> polymorphism, they all support ranges etc.  Interfaces are also there  
>> in case you want to use them in things like runtime plugin interfaces.
>
> The best reason I can think of is to avoid kitchen-sink style  
> components. Components should do one thing well. Adding capability  
> should be done with aggregation by the user.

What if it can do both things well (I would propose that dcollections  
does)?

>
>
>> Basically, my point is, compile time interfaces does not mean you can't  
>> also have runtime interfaces.  In fact, interfaces can be compile-time  
>> parameterized.
>
> Sure, but I'd argue that adding such runtime polymorphism should be done  
> with a separate add-on component. It should not be part of the  
> collection component.

So I should specifically have to wrap a collection type in order to make  
it runtime polymorphic, forwarding all the operations to the collection?   
Essentially something like:

class WrappedSet(Impl, V) : Set!V
{
   Impl!V impl;

   bool contains(V v) { return impl.contains(v);}
   ...
}

For what reason?  Why is it so bad to just stick Set!V on the end of the  
implementation class?

>
>
>> Also, much of a user interface consists of various collections  
>> (listview, treeview, child widgets, etc.).  Why is runtime polymorphism  
>> good there, but not on a generic collections package (not as the only  
>> means of access of course)?
>
> A user interface object is not a collection component, I think there's a  
> confusion in the design there.

Don't user interface objects have data?  If a UI component is an  
interface, how does it expose access to its data?  For example, a .NET  
ListView control contains an Items property which you can use to access  
the elements in the list view.  The Items property returns a  
ListViewItemCollection which implements IList, IContainer, and  
IEnumerable.  I've found these types of abstractions useful when  
adding/iterating, etc.

-Steve
May 24, 2010
Re: To interface or not to interface
Steven Schveighoffer wrote:
> On Mon, 24 May 2010 14:36:57 -0400, Walter Bright 
> <newshound1@digitalmars.com> wrote:
>>> and on point 3, why is it not OK to *also* provide interfaces in 
>>> addition to ranges as dcollections does?  That is, take away 
>>> dcollections' interfaces, and you have essentially compile-time 
>>> polymorphism, they all support ranges etc.  Interfaces are also there 
>>> in case you want to use them in things like runtime plugin interfaces.
>>
>> The best reason I can think of is to avoid kitchen-sink style 
>> components. Components should do one thing well. Adding capability 
>> should be done with aggregation by the user.
> 
> What if it can do both things well (I would propose that dcollections 
> does)?

Probably for the same reason I don't want a microwave built in to my TV set. 
It's not a question of can it do both well, it's a question of is it a distinct 
component or not.


>> Sure, but I'd argue that adding such runtime polymorphism should be 
>> done with a separate add-on component. It should not be part of the 
>> collection component.
> 
> So I should specifically have to wrap a collection type in order to make 
> it runtime polymorphic, forwarding all the operations to the 
> collection?  Essentially something like:
> 
> class WrappedSet(Impl, V) : Set!V
> {
>    Impl!V impl;
> 
>    bool contains(V v) { return impl.contains(v);}
>    ...
> }
> 
> For what reason?  Why is it so bad to just stick Set!V on the end of the 
> implementation class?

Because then everyone who just wants a hash table winds up carrying around the 
complexity for things they don't want. The idea behind pluggable components is 
that each component should be minimal, and then the user aggregates them to meet 
his needs.



>>> Also, much of a user interface consists of various collections 
>>> (listview, treeview, child widgets, etc.).  Why is runtime 
>>> polymorphism good there, but not on a generic collections package 
>>> (not as the only means of access of course)?
>>
>> A user interface object is not a collection component, I think there's 
>> a confusion in the design there.
> 
> Don't user interface objects have data?  If a UI component is an 
> interface, how does it expose access to its data?

That's up to the UI interface designer. It has nothing to do with how it 
implements the collection under the hood.

> For example, a .NET 
> ListView control contains an Items property which you can use to access 
> the elements in the list view.  The Items property returns a 
> ListViewItemCollection which implements IList, IContainer, and 
> IEnumerable.  I've found these types of abstractions useful when 
> adding/iterating, etc.

A graphical component can wrap a collection component. I see no reason why the 
collection needs to have runtime polymorphism to enable that.
May 24, 2010
Re: To interface or not to interface
On Mon, 24 May 2010 16:27:40 -0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> On Mon, 24 May 2010 14:36:57 -0400, Walter Bright  
>> <newshound1@digitalmars.com> wrote:
>>>> and on point 3, why is it not OK to *also* provide interfaces in  
>>>> addition to ranges as dcollections does?  That is, take away  
>>>> dcollections' interfaces, and you have essentially compile-time  
>>>> polymorphism, they all support ranges etc.  Interfaces are also there  
>>>> in case you want to use them in things like runtime plugin interfaces.
>>>
>>> The best reason I can think of is to avoid kitchen-sink style  
>>> components. Components should do one thing well. Adding capability  
>>> should be done with aggregation by the user.
>>  What if it can do both things well (I would propose that dcollections  
>> does)?
>
> Probably for the same reason I don't want a microwave built in to my TV  
> set. It's not a question of can it do both well, it's a question of is  
> it a distinct component or not.

We're not talking microwave and TV set here.  We're talking more like  
microwave and a cooking device.

>
>
>>> Sure, but I'd argue that adding such runtime polymorphism should be  
>>> done with a separate add-on component. It should not be part of the  
>>> collection component.
>>  So I should specifically have to wrap a collection type in order to  
>> make it runtime polymorphic, forwarding all the operations to the  
>> collection?  Essentially something like:
>>  class WrappedSet(Impl, V) : Set!V
>> {
>>    Impl!V impl;
>>     bool contains(V v) { return impl.contains(v);}
>>    ...
>> }
>>  For what reason?  Why is it so bad to just stick Set!V on the end of  
>> the implementation class?
>
> Because then everyone who just wants a hash table winds up carrying  
> around the complexity for things they don't want. The idea behind  
> pluggable components is that each component should be minimal, and then  
> the user aggregates them to meet his needs.

What extra complexity?  That's what I'm trying to get at, there is none.   
The complexity of "being a set" is builtin to the fact that HashSet is a  
set!

>>>> Also, much of a user interface consists of various collections  
>>>> (listview, treeview, child widgets, etc.).  Why is runtime  
>>>> polymorphism good there, but not on a generic collections package  
>>>> (not as the only means of access of course)?
>>>
>>> A user interface object is not a collection component, I think there's  
>>> a confusion in the design there.
>>  Don't user interface objects have data?  If a UI component is an  
>> interface, how does it expose access to its data?
>
> That's up to the UI interface designer. It has nothing to do with how it  
> implements the collection under the hood.
>
>> For example, a .NET ListView control contains an Items property which  
>> you can use to access the elements in the list view.  The Items  
>> property returns a ListViewItemCollection which implements IList,  
>> IContainer, and IEnumerable.  I've found these types of abstractions  
>> useful when adding/iterating, etc.
>
> A graphical component can wrap a collection component. I see no reason  
> why the collection needs to have runtime polymorphism to enable that.

It's a logical conclusion.  You provide a map-type collection, call it a  
HashMap.  Then, a UI designer wants to abstract his specific Map-like  
container that exposes his elements, so you provide him a Map interface.   
But HashMap implements all the required functions to be able to implement  
the Map interface, so you slap Map on the back of the class definition,  
and presto!  It implements the map interface.  Where's the extra  
complexity?

I don't see how that's a bad thing.

-Steve
May 24, 2010
Re: To interface or not to interface
Steven Schveighoffer wrote:
> It's a logical conclusion.  You provide a map-type collection, call it a 
> HashMap.  Then, a UI designer wants to abstract his specific Map-like 
> container that exposes his elements, so you provide him a Map 
> interface.  But HashMap implements all the required functions to be able 
> to implement the Map interface, so you slap Map on the back of the class 
> definition, and presto!  It implements the map interface.  Where's the 
> extra complexity?

The extra complexity is in the container supporting very different ways to do 
the same thing.

> I don't see how that's a bad thing.

If the user wants an interface, he can add one on to the front of the 
collection. It doesn't need to be in the collection itself.

The "bad" thing is the component integrating in capability that is easily done 
as an add-on.

This reminds me of a fellow I worked with years ago who would provide both a 
free-function interface and a class interface to each of his components. It was 
completely redundant to do both, and added pages of complexity and documentation.
May 24, 2010
Re: To interface or not to interface
In my experience (not related to DCollections), having interfaces is useful to ensure reduced coupling, thus enabling the use of mock classes for unit tests (or simply to test your module, when your module needs to use services provided by another module that is being written by a colleague but not yet usable, etc...)

> A long discussion on the utility of interfaces has taken place on the  
> announce newsgroup following my announcement of dcollections for D2.
> 
> Dcollections supports interfaces peripherally.  Meaning the types in  
> dcollections are essentially concrete classes with interfaces tacked on  
> for cases where interfaces make sense.
> 
> Whenever I've used dcollections (D1 included) I don't think I've ever used  
> the interface for a container, only the concrete type.  But within  
> dcollections, there's some functions that use the interface type to do  
> (IMO) nifty things like compare two sets that have different  
> implementations.
> 
> The general consensus is that interfaces for dcollections do not add any  
> meaningful value, and that I should do everything with generic programming  
> and templates.  My view is that interfaces are useful for binary  
> compatibility and in reducing the footprint of executables.  But that  
> doesn't mean much at the moment, because D is statically linked.
> 
> I'd ask the naysayers of interfaces for dcollections, and also the  
> supporters: what is the point of having interfaces in D?  Are interfaces  
> pretty much obsolete, and I am just nostalgic about their utility?
> 
> What do you think?
> 
> -Steve
May 24, 2010
Re: To interface or not to interface
On Mon, 24 May 2010 17:11:49 -0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> Steven Schveighoffer wrote:
>> It's a logical conclusion.  You provide a map-type collection, call it  
>> a HashMap.  Then, a UI designer wants to abstract his specific Map-like  
>> container that exposes his elements, so you provide him a Map  
>> interface.  But HashMap implements all the required functions to be  
>> able to implement the Map interface, so you slap Map on the back of the  
>> class definition, and presto!  It implements the map interface.   
>> Where's the extra complexity?
>
> The extra complexity is in the container supporting very different ways  
> to do the same thing.

I don't see this being "very different":

coll.add(coll2); // uses coll2 as interface.
coll.add(coll2[0..5]); // uses coll2 slice as a range.
coll.add(arr); // adds an array.

>
>> I don't see how that's a bad thing.
>
> If the user wants an interface, he can add one on to the front of the  
> collection. It doesn't need to be in the collection itself.

We're going in circles here.  I feel like pointing back to my previous  
post with the wrapping example...

All an interface does is give an abstract representation of functions that  
are *already there*.  Removing the interface does not remove the functions  
that implemented the interface.

> The "bad" thing is the component integrating in capability that is  
> easily done as an add-on.
>
> This reminds me of a fellow I worked with years ago who would provide  
> both a free-function interface and a class interface to each of his  
> components. It was completely redundant to do both, and added pages of  
> complexity and documentation.

This is completely different, I'm tacking on one small piece of  
declaration and the class becomes an interface.  I'm not reimplementing or  
wrapping anything.  Surely you can see that.

In a related story, I *did* have to do something like this when someone  
wanted a Java interface to some C++ code we had.  In order to do this, we  
had to declare extern "C" functions that Java could interface via JNI.

-Steve
« First   ‹ Prev
1 2 3 4
Top | Discussion index | About this forum | D home