On Tue, 25 May 2010 09:26:20 -0400, Jacob Carlborg <doob@me.com> wrote:
> On 2010-05-24 21.08, Steven Schveighoffer wrote:
>>>> 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
>>> I would say that is a bad design, I would go with the MVC pattern. For example, you have a ListView and when it's ready to display, say row 3, it calls your delegate and request you to return the item that should be visible on row 3. Then it's up to you to store the items in some appropriate data structure, like a list or array.
I don't know if a delegate is enough to implement the pattern. What you need is a set of delegates that perform operations on the container. Oh wait, that's an interface!
One interesting difference between an interface and a delegate is that an interface is a single pointer, whereas a delegate is two. With the context-pointer design, many more features are possible. For instance, struct interfaces would be easy, as well as easily tacking on an interface to a class.
In any case, Windows Forms is probably the easiest UI toolkit I've worked with (which isn't saying much), I don't think it's a bad design. That could be the Visual Studio talking though :)
-Steve

On 2010-05-25 00.13, Walter Bright wrote:
> Steven Schveighoffer wrote:
>> 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.
>> Then why do interfaces need to be part of the collection component? Why
> can't the user add them if he wants them?
How would the user do that? The user would need to create an interface and then a wrapper that implements the interface. An interface without implementations is useless. Or am I missing something ?
--
/Jacob Carlborg

On 2010-05-25 15.38, Steven Schveighoffer wrote:
> On Tue, 25 May 2010 09:26:20 -0400, Jacob Carlborg <doob@me.com> wrote:
>>> On 2010-05-24 21.08, Steven Schveighoffer wrote:
>>>>>> 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
>>>>>> I would say that is a bad design, I would go with the MVC pattern. For
>> example, you have a ListView and when it's ready to display, say row
>> 3, it calls your delegate and request you to return the item that
>> should be visible on row 3. Then it's up to you to store the items in
>> some appropriate data structure, like a list or array.
>> I don't know if a delegate is enough to implement the pattern. What you
> need is a set of delegates that perform operations on the container. Oh
> wait, that's an interface!
What I was trying to say is that a ListView should not contain a data structure. I try to explain that I want to say in code instead:
auto data = new Item[10];
auto listView = new ListView;
listView.numberOfRows = size_t delegate (ListView lv) {
return data.length;
}
listView.itemAtRow = Item delegate (ListView lv, size_t row) {
return data[row];
}
Now Item could be an interface but it don't have to be. I suggest you have a look at Apple's documentation of NSTableView:
* http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSTableView_Class/Reference/Reference.html
* http://developer.apple.com/mac/library/documentation/cocoa/Conceptual/TableView/Tasks/UsingTableDataSource.html#//apple_ref/doc/uid/20000117> One interesting difference between an interface and a delegate is that
> an interface is a single pointer, whereas a delegate is two. With the
> context-pointer design, many more features are possible. For instance,
> struct interfaces would be easy, as well as easily tacking on an
> interface to a class.
>> In any case, Windows Forms is probably the easiest UI toolkit I've
> worked with (which isn't saying much), I don't think it's a bad design.
> That could be the Visual Studio talking though :)
I suggest you have a look at Cocoa, it uses the MVC pattern.
> -Steve
--
/Jacob Carlborg

On Tue, 25 May 2010 10:01:48 -0400, Jacob Carlborg <doob@me.com> wrote:
> On 2010-05-25 15.38, Steven Schveighoffer wrote:
>> On Tue, 25 May 2010 09:26:20 -0400, Jacob Carlborg <doob@me.com> wrote:
>>>>> On 2010-05-24 21.08, Steven Schveighoffer wrote:
>>>>>>>> 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
>>>>>>>>> I would say that is a bad design, I would go with the MVC pattern. For
>>> example, you have a ListView and when it's ready to display, say row
>>> 3, it calls your delegate and request you to return the item that
>>> should be visible on row 3. Then it's up to you to store the items in
>>> some appropriate data structure, like a list or array.
>>>> I don't know if a delegate is enough to implement the pattern. What you
>> need is a set of delegates that perform operations on the container. Oh
>> wait, that's an interface!
>> What I was trying to say is that a ListView should not contain a data structure. I try to explain that I want to say in code instead:
>> auto data = new Item[10];
> auto listView = new ListView;
> listView.numberOfRows = size_t delegate (ListView lv) {
> return data.length;
> }
> listView.itemAtRow = Item delegate (ListView lv, size_t row) {
> return data[row];
> }
Yes, I get that. What I'm saying is this is basically an interface. The difference is that the interface is not required to be declared on the container class, and requires 2 words of storage in the ListView per function instead of 1 word for all the functions.
Another way to do this is:
listView.items = data;
Where listView.items is an interface that contains the functions you need. If the set of functions is complex, then using the delegates could be tedious.
It's just a different way of doing it. There are benefits to both ways. Using the delegates is more flexible because a delegate does not need to be defined in a class with a predefined interface being implemented. It's also much easier to build a bunch of delegates on the fly rather than build an interface implementation.
-Steve

On 2010-05-25 10:01:48 -0400, Jacob Carlborg <doob@me.com> said:
> Now Item could be an interface but it don't have to be. I suggest you have a look at Apple's documentation of NSTableView:
What Cocoa is doing is basically allowing 'optional' methods in an interface (a protocol in Objective-C). Taking your example, the NSTableViewDataSource protocol contains a lot of functions to provide the required data to a table. But many of them are optional: for instance a data source that does not implement the "...setObjectValue..." method will prevent the table's content from being edited, one that doesn't implement the "...sortDescriptorsDidChange..." method prevents the table from being sorted by clicking on its column headers, one that doesn't implement the various methods for drag and drop will prevent rows from being dragged.
(Note to Cocoa programmers: Prior to the Mac OS X 10.6 SDK, NSTableViewDataSource was an informal protocol implemented as a category of unimplemented functions in NSObject. The 10.6 SDK changed it to be a formal protocol with optional methods, a feature added to Objective-C 2.0.)
In D, one could create one interface for each of these groups of things, but then you'll have a bazilion of small interfaces and either you lose the relation between them or you end up with a combinational explosion. For instance, let's create a bunch of interfaces for what I wrote above:
interface TableDataSource {...}
interface TableDataSourceEdit : TableDataSource {...}
interface TableDataSourceSort : TableDataSource {...}
interface TableDataSourceDrag : TableDataSource {...}
interface TableDataSourceDropTarget : TableDataSource {...}
Now, when I implement the table view I could have one data source
class TableView {
TableDataSource dataSource;
}
and then I'd dynamically check whether my data source implements each of the child interfaces:
auto dataSourceEdit = cast(TableDataSourceEdit)dataSource)
if (dataSourceEdit) {
dataSourceEdit.setObject(object, row, column);
} else {
// data source cannot be edited
}
That's essentially what is done in Cocoa, except that in Cocoa an object usually checks for the existence of one of its delegate function prior calling it instead of having a whole lot of interfaces. This is why protocols are allowed to have optional methods.
Perhaps interfaces could be allowed to have optional methods that would require you to check if they're implemented before use.
--
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/

Jason House wrote:
> Walter Bright Wrote:
> >> Jason House wrote:
>>> 7. Compiler-assisted verification.
>> For interfaces, the compile time checking is limited to verifying that
>> functions with the right signature are supplied. Templates can go
>> considerably beyond that with the constraint checking.
> > constraints are more powerful, but they have downsides: • If a class is
> incorrectly defined, failure to use a type without a constraint check leads
> to errors in the code using it instead of the class definition. Usage isn't
> always guaranteed to be correct either, so the developer must spend extra
> time diagnosing the real error. • If a class is incorrectly, initial usage
> without a constraint may completely miss the error. Easy examples would be a
> typo propogated with copy/paste, or neglecting to use save. • If a class is
> incorrectly defined and usage uses a constraint, the developer will simply
> get an error that there is no matching call. • If a constraint is incorrectly
> defined and usage uses the constraint, the developer will simply get an error
> that there is no matching call.
> > None of these scenarios are particularly helpful for a developer
> creating/expanding a family of objects.
You can also make constraints that give custom error messages, so you can do better than the compiler's stab at it. How good they are is up to the designer of the type.

Steven Schveighoffer wrote:
> On Mon, 24 May 2010 18:13:38 -0400, Walter Bright <newshound1@digitalmars.com> wrote:
> >> Steven Schveighoffer wrote:
>>> 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.
>>>> Then why do interfaces need to be part of the collection component? Why can't the user add them if he wants them?
> > How do you add an interface to a class?
Define an interface who's member functions call the class' member functions.

On 2010-05-25 17.03, Michel Fortin wrote:
> On 2010-05-25 10:01:48 -0400, Jacob Carlborg <doob@me.com> said:
>>> Now Item could be an interface but it don't have to be. I suggest you
>> have a look at Apple's documentation of NSTableView:
>> What Cocoa is doing is basically allowing 'optional' methods in an
> interface (a protocol in Objective-C). Taking your example, the
> NSTableViewDataSource protocol contains a lot of functions to provide
> the required data to a table. But many of them are optional: for
> instance a data source that does not implement the
> "...setObjectValue..." method will prevent the table's content from
> being edited, one that doesn't implement the
> "...sortDescriptorsDidChange..." method prevents the table from being
> sorted by clicking on its column headers, one that doesn't implement the
> various methods for drag and drop will prevent rows from being dragged.
I've always thought that this design and the similar Java uses with interfaces, anonymous classes and adapters is just a design chosen because the languages are limited, don't support delegates.
> (Note to Cocoa programmers: Prior to the Mac OS X 10.6 SDK,
> NSTableViewDataSource was an informal protocol implemented as a category
> of unimplemented functions in NSObject. The 10.6 SDK changed it to be a
> formal protocol with optional methods, a feature added to Objective-C 2.0.)
>> In D, one could create one interface for each of these groups of things,
> but then you'll have a bazilion of small interfaces and either you lose
> the relation between them or you end up with a combinational explosion.
> For instance, let's create a bunch of interfaces for what I wrote above:
>> interface TableDataSource {...}
> interface TableDataSourceEdit : TableDataSource {...}
> interface TableDataSourceSort : TableDataSource {...}
> interface TableDataSourceDrag : TableDataSource {...}
> interface TableDataSourceDropTarget : TableDataSource {...}
>> Now, when I implement the table view I could have one data source
>> class TableView {
> TableDataSource dataSource;
> }
>> and then I'd dynamically check whether my data source implements each of
> the child interfaces:
>> auto dataSourceEdit = cast(TableDataSourceEdit)dataSource)> if (dataSourceEdit) {
> dataSourceEdit.setObject(object, row, column);
> } else {
> // data source cannot be edited
> }
>> That's essentially what is done in Cocoa, except that in Cocoa an object
> usually checks for the existence of one of its delegate function prior
> calling it instead of having a whole lot of interfaces. This is why
> protocols are allowed to have optional methods.
>> Perhaps interfaces could be allowed to have optional methods that would
> require you to check if they're implemented before use.
How would you check if a method is implemented or not ?
--
/Jacob Carlborg

Walter Bright Wrote:
> Jason House wrote:
> > Walter Bright Wrote:
> > > >> Jason House wrote:
> >>> 7. Compiler-assisted verification.
> >> For interfaces, the compile time checking is limited to verifying that functions with the right signature are supplied. Templates can go considerably beyond that with the constraint checking.
> > > > constraints are more powerful, but they have downsides: • If a class is
> > incorrectly defined, failure to use a type without a constraint check leads
> > to errors in the code using it instead of the class definition. Usage isn't
> > always guaranteed to be correct either, so the developer must spend extra
> > time diagnosing the real error. • If a class is incorrectly, initial usage
> > without a constraint may completely miss the error. Easy examples would be a
> > typo propogated with copy/paste, or neglecting to use save. • If a class is
> > incorrectly defined and usage uses a constraint, the developer will simply
> > get an error that there is no matching call. • If a constraint is incorrectly
> > defined and usage uses the constraint, the developer will simply get an error
> > that there is no matching call.
> > > > None of these scenarios are particularly helpful for a developer creating/expanding a family of objects.
> > > You can also make constraints that give custom error messages, so you can do better than the compiler's stab at it. How good they are is up to the designer of the type.
So you're favoring an isXXX as well as a requireXXX? Such duplication is both annoying and error prone. Making isXXX use requieXXX under the hood ishigher implementation complexity. I don't know about others, but I was drawn to its simplicity over C++. Many have praised its ability to make template programming simple. This feels like a step backwards.

On 24/05/2010 22:14, Marianne Gagnon wrote:
> 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...)
>
That's generally true, but I don't think it applies to DCollections. Creating mock objects is for mocking complex subsystems and modules, such that setting up (and later verifying) the mock object is much easier than if the true object/subsystem was used. But that would not apply to a collection object, since a mock collection would not really be easier to work with than with the real collection object.
--
Bruno Medeiros - Software Engineer