View mode: basic / threaded / horizontal-split · Log in · Help
May 26, 2010
Re: To interface or not to interface
On 2010-05-26 06:55:14 -0400, Jacob Carlborg <doob@me.com> said:

> 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.

Indeed.

Well, I think you could use runtime-reflection to achieve the same 
thing in Java, but that would make your interfaces "informal", in the 
sense that you just can't put those optional functions in the 
interfaces. (And it'd uglify the code a lot.) Technically, this is what 
was done prior Mac OS X 10.6 with informal protocols; I say "almost" 
since the method signatures being added as unimplemented categories to 
NSObject, they could still checked for correctness by the compiler.


>> 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 ?

In Objective-C, it's quite easy. For instance, I've made my own 
subclass of NSTableView querying the delegate for a background color 
for a given row. So here's how you use the delegate:

	id delegate = [self delegate];
	
	if ([delegate 
respondsToSelector:@selector(tableView:backgroundColorForRow:)]) {
		NSColor *color = [delegate tableView:self backgroundColorForRow:row];
		...draw background color...
	}

In D you can't do that currently, but here's how it could be added. 
First add an optional attribute for interface members:

	interface TableDelegate {
		...
		@optional NSColor backgroundColorForRow(NSTableView table, size_t row);
	}

Classes implementing the interface can omit the @optional methods. When 
omitted, the interface function is null. When using the interface, you 
must check first if the optional function is implemented by making sure 
the address isn't null:

	TableDelegate delegate = this.delegate;
	
	if (&delegate.backgroundColorForRow != null) {
		NSColor color = delegate.backgroundColorForRow(this, row);
		...draw background color...
	}

This would work somewhat similarily to weak-linked symbols.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
May 26, 2010
Re: To interface or not to interface
Jason House wrote:
> 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.

In C++, the concepts design died. There's nothing you can do in C++ about the 
bad error messages. Furthermore, compile time error checking in C++ is limited 
to types. If something cannot be expressed as a distinct type, it cannot be 
checked in C++. (BTW, interfaces in D have the same problem, you can only check 
the type with them. With templates, you can check behavior and other 
characteristics.)

The fundamental problem is a compiler can only see a worm's eye view of what a 
component is supposed to do. There's no algorithm in the world that can take a 
block of code and have the compiler figure out that this is a hash map 
collection class, and give lucid error messages in those terms rather than low 
level operations.

As a component designer, however, D gives you the ability to detect usage errors 
at compile time in ways that go far beyond just type errors, and inform the user 
about them in high level terms.

You're right in that D doesn't do this automatically, just like a browser cannot 
automatically make attractive web pages. You as the component designer have to 
write the code to make it work the way you want.
May 26, 2010
Re: To interface or not to interface
On 2010-05-26 16.20, Michel Fortin wrote:
> On 2010-05-26 06:55:14 -0400, Jacob Carlborg <doob@me.com> said:
>
>> 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.
>
> Indeed.
>
> Well, I think you could use runtime-reflection to achieve the same thing
> in Java, but that would make your interfaces "informal", in the sense
> that you just can't put those optional functions in the interfaces. (And
> it'd uglify the code a lot.) Technically, this is what was done prior
> Mac OS X 10.6 with informal protocols; I say "almost" since the method
> signatures being added as unimplemented categories to NSObject, they
> could still checked for correctness by the compiler.

If I recall correctly writing code that uses runtime-refelection in Java 
isn't pretty, especial compared to something like Ruby where it's just 
as easy as any other code you write.

>>> 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 ?
>
> In Objective-C, it's quite easy. For instance, I've made my own subclass
> of NSTableView querying the delegate for a background color for a given
> row. So here's how you use the delegate:
>
> id delegate = [self delegate];
>
> if ([delegate
> respondsToSelector:@selector(tableView:backgroundColorForRow:)]) {
> NSColor *color = [delegate tableView:self backgroundColorForRow:row];
> ...draw background color...
> }

Yes, Objective-C makes that easy with its message passing system.

> In D you can't do that currently, but here's how it could be added.
> First add an optional attribute for interface members:
>
> interface TableDelegate {
> ...
> @optional NSColor backgroundColorForRow(NSTableView table, size_t row);
> }
>
> Classes implementing the interface can omit the @optional methods. When
> omitted, the interface function is null. When using the interface, you
> must check first if the optional function is implemented by making sure
> the address isn't null:
>
> TableDelegate delegate = this.delegate;
>
> if (&delegate.backgroundColorForRow != null) {
> NSColor color = delegate.backgroundColorForRow(this, row);
> ...draw background color...
> }
>
> This would work somewhat similarily to weak-linked symbols.

That is quite a clever idea, to check for null. The question is then how 
much trouble would that be to implement.


-- 
/Jacob Carlborg
May 26, 2010
Re: To interface or not to interface
On 2010-05-26 15:44:58 -0400, Jacob Carlborg <doob@me.com> said:

> On 2010-05-26 16.20, Michel Fortin wrote:
> 
>> In D you can't do that currently, but here's how it could be added.
>> First add an optional attribute for interface members:
>> 
>> interface TableDelegate {
>> ...
>> @optional NSColor backgroundColorForRow(NSTableView table, size_t row);
>> }
>> 
>> Classes implementing the interface can omit the @optional methods. When
>> omitted, the interface function is null. When using the interface, you
>> must check first if the optional function is implemented by making sure
>> the address isn't null:
>> 
>> TableDelegate delegate = this.delegate;
>> 
>> if (&delegate.backgroundColorForRow != null) {
>> NSColor color = delegate.backgroundColorForRow(this, row);
>> ...draw background color...
>> }
>> 
>> This would work somewhat similarily to weak-linked symbols.
> 
> That is quite a clever idea, to check for null. The question is then 
> how much trouble would that be to implement.

If I had to guess those things would need to be done:

1. Add the "@optional" attribute token to the lexer
2. Allow @optional to be attached to functions in an interface
3. When checking if a class correctly implements an interface, allow 
unimplemented @optional functions
4. When generating the interface's vtable, use null for unimplemented 
@optional functions

I think that's all. Checking for null is easily done by retrieving the 
delegate pointer (which you can already do), and calling the function 
uses the usual calling mechanism for interfaces. I expect that trying 
to call an unimplemented interface function would be like trying to 
call a null function pointer.

-- 
Michel Fortin
michel.fortin@michelf.com
http://michelf.com/
May 27, 2010
Re: To interface or not to interface
On Tue, 25 May 2010 23:29:34 -0400, Walter Bright  
<newshound1@digitalmars.com> wrote:

> 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.

Quoting from earlier message:

  Wrapping seems like it would add more overhead than just implementing  
the interface, especially since D's inliner has some strange restrictions.

-Steve
May 27, 2010
Re: To interface or not to interface
== Quote from Steven Schveighoffer (schveiguy@yahoo.com)'s article
> On Tue, 25 May 2010 23:29:34 -0400, Walter Bright
> <newshound1@digitalmars.com> wrote:
> > 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.
> Quoting from earlier message:
>    Wrapping seems like it would add more overhead than just implementing
> the interface, especially since D's inliner has some strange restrictions.
> -Steve

I think the main problem is that adding an interface post-hoc on the user's side
is a cumbersome error-prone process. This problem has been avoided quite elegantly
by Go by the way, which allows interfaces to be "applied" to all types that
conform without requiring inheritance (can't resist to mention that I proposed
this exact approach some years ago (long before Go was released) in this news
group ;-) ).

cheers
Martin
Next ›   Last »
1 2 3 4
Top | Discussion index | About this forum | D home