www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - default parameters in interface, does it make sense

reply Regan Heath <regan netwin.co.nz> writes:
Hi all,

I have some code which reads:

interface Foo {
   void bar(int a = 5);
}

class FooBar : Foo {
   void bar(int a) {
   }
}

the default parameter in the interface appears to be ignored completely by 
the compiler, I was expecting either:

- an error, as it's not allowed.
- an error, as FooBar does not implement an identical method (complete 
with default param)

What does everyone think, is there any point to default parameters in 
interfaces, if so, what should they do, how should they behave.

Regan

-- 
Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 09 2004
parent reply parabolis <parabolis softhome.net> writes:
Regan Heath wrote:

 What does everyone think, is there any point to default parameters in 
 interfaces, if so, what should they do, how should they behave.

interface DataSink { write( ubyte buf, uint len = 0, uint off = 0 ); } :)
Aug 10 2004
parent reply Regan Heath <regan netwin.co.nz> writes:
On Tue, 10 Aug 2004 10:12:56 -0700, parabolis <parabolis softhome.net> 
wrote:

 Regan Heath wrote:

 What does everyone think, is there any point to default parameters in 
 interfaces, if so, what should they do, how should they behave.

interface DataSink { write( ubyte buf, uint len = 0, uint off = 0 ); }

What's your point?.. try: interface DataSink { void write( ubyte[] buf, uint len = 0, uint off = 0 ); } class weirdOne : DataSink { void write( ubyte[] buf, uint len = 100, uint off = 100 ) { printf("weirdOne: %u %u\n",len,off); } } class weirdTwo : DataSink { void write( ubyte[] buf, uint len, uint off ) { printf("weirdTwo: %u %u\n",len,off); } } void main() { weirdOne w1 = new weirdOne(); weirdTwo w2 = new weirdTwo(); ubyte[] bf; w1.write(bf); w2.write(bf,1,2); } Notice w2.write requires those parameters to be specified, so the interface ones mean nothing. Notice w1.write outputs "100 100" and w2.write outputs "1 2", neither outputs "0 0". Regan -- Using M2, Opera's revolutionary e-mail client: http://www.opera.com/m2/
Aug 10 2004
parent reply Andy Friesen <andy ikagames.com> writes:
Regan Heath wrote:
 On Tue, 10 Aug 2004 10:12:56 -0700, parabolis <parabolis softhome.net> 
 wrote:
 
 Regan Heath wrote:

 What does everyone think, is there any point to default parameters in 
 interfaces, if so, what should they do, how should they behave.

interface DataSink { write( ubyte buf, uint len = 0, uint off = 0 ); }

What's your point?.. try: interface DataSink { void write( ubyte[] buf, uint len = 0, uint off = 0 ); } class weirdOne : DataSink { void write( ubyte[] buf, uint len = 100, uint off = 100 ) { printf("weirdOne: %u %u\n",len,off); } } class weirdTwo : DataSink { void write( ubyte[] buf, uint len, uint off ) { printf("weirdTwo: %u %u\n",len,off); } } void main() { weirdOne w1 = new weirdOne(); weirdTwo w2 = new weirdTwo(); ubyte[] bf; w1.write(bf); w2.write(bf,1,2); } Notice w2.write requires those parameters to be specified, so the interface ones mean nothing. Notice w1.write outputs "100 100" and w2.write outputs "1 2", neither outputs "0 0".

This is the reason default arguments were originally not part of the D spec: default arguments do not get along with polymorphism at all. Given: DataSink w3 = new weirdOne(); w3.write(bf); The defaults specified in the DataSink interface will be used. An overload or two in place of a default argument is a bit more fingerwork, but it's also much more likely to do the right thing. template DataSinkAdapter() { void write(ubyte[] buf, uint len) { return write(buf, len, 0); } void write(ubyte[] buf) { return write(buf, buf.length); } } -- andy
Aug 10 2004
parent reply "antiAlias" <gblazzer corneleus.com> writes:
I'd tend to agree with you Andy; but if the compiler were tightened up so
that it took Interface default-args into consideration, would that not
resolve the problem? I mean, the default-args should actually be part of the
signature matching process WRT interface-contracts. If it were, the
implementing class would have to follow suit. Right? As would override's ?

So this:

interface I
{
    void x (int y = 1);
}

class MyI
{
    void x (int y) {}
}

... would just fail to compile. Right now, the compiler is a bit too lax
about such things. Perhaps it should be a bug-report?


"Andy Friesen" <andy ikagames.com> wrote in message
news:cfbios$oqs$1 digitaldaemon.com...
 Regan Heath wrote:
 On Tue, 10 Aug 2004 10:12:56 -0700, parabolis <parabolis softhome.net>
 wrote:

 Regan Heath wrote:

 What does everyone think, is there any point to default parameters in
 interfaces, if so, what should they do, how should they behave.

interface DataSink { write( ubyte buf, uint len = 0, uint off = 0 ); }

What's your point?.. try: interface DataSink { void write( ubyte[] buf, uint len = 0, uint off = 0 ); } class weirdOne : DataSink { void write( ubyte[] buf, uint len = 100, uint off = 100 ) { printf("weirdOne: %u %u\n",len,off); } } class weirdTwo : DataSink { void write( ubyte[] buf, uint len, uint off ) { printf("weirdTwo: %u %u\n",len,off); } } void main() { weirdOne w1 = new weirdOne(); weirdTwo w2 = new weirdTwo(); ubyte[] bf; w1.write(bf); w2.write(bf,1,2); } Notice w2.write requires those parameters to be specified, so the interface ones mean nothing. Notice w1.write outputs "100 100" and w2.write outputs "1 2", neither outputs "0 0".

This is the reason default arguments were originally not part of the D spec: default arguments do not get along with polymorphism at all. Given: DataSink w3 = new weirdOne(); w3.write(bf); The defaults specified in the DataSink interface will be used. An overload or two in place of a default argument is a bit more fingerwork, but it's also much more likely to do the right thing. template DataSinkAdapter() { void write(ubyte[] buf, uint len) { return write(buf, len, 0); } void write(ubyte[] buf) { return write(buf, buf.length); } } -- andy

Aug 10 2004
next sibling parent Andy Friesen <andy ikagames.com> writes:
antiAlias wrote:

 I'd tend to agree with you Andy; but if the compiler were tightened up so
 that it took Interface default-args into consideration, would that not
 resolve the problem? I mean, the default-args should actually be part of the
 signature matching process WRT interface-contracts. If it were, the
 implementing class would have to follow suit. Right? As would override's ?
 
 ... would just fail to compile. Right now, the compiler is a bit too lax
 about such things. Perhaps it should be a bug-report?

This would work too, though I would be happier if default arguments were shorthand for override methods: class MyI : I { void foo(int arg=0) { ... } final void foo() { foo(arg); } // default argument is equivalent to inserting this } This means that interfaces can't have default arguments: interface I { void foo(int arg=0); // illegal final void foo() { foo(0); } // because you can't do this in an interface void foo(); // but you can do this } class MyI : I { void foo(int arg=0) { ... } // satisfies both foo(int) and foo()! } But it reconciles the differences between default arguments and method overloads into a single, unified set of rules, thus obliviating silliness such as class MyClass { void foo(int arg=0) { ... } // why?! void foo() { ... } } -- andy
Aug 10 2004
prev sibling parent J C Calvarese <jcc7 cox.net> writes:
antiAlias wrote:
 I'd tend to agree with you Andy; but if the compiler were tightened up so
 that it took Interface default-args into consideration, would that not
 resolve the problem? I mean, the default-args should actually be part of the
 signature matching process WRT interface-contracts. If it were, the
 implementing class would have to follow suit. Right? As would override's ?
 
 So this:
 
 interface I
 {
     void x (int y = 1);
 }
 
 class MyI
 {
     void x (int y) {}
 }
 
 ... would just fail to compile. Right now, the compiler is a bit too lax
 about such things. Perhaps it should be a bug-report?

Isn't the real challenge this statement from the spec? "A function parameter's default value is not inherited" (http://www.digitalmars.com/d/function.html) Unless the default values are inheritable, we can't expect any of these recent ideas to work. I'm thinking about the ideas that have been raised, but I'm doubtful we could talk Walter into making the default values any more complicated. I think we were lucky to get him to include default values in the first place. Maybe we could have the default values _only_ inherit from an interface and if multiple interfaces are involved with different default values, it'd be a compiler error. I think that fit into the idea of interfaces. I'm not an interface user yet, so I could be blowing hot air. Please don't give me a hard time if this suggestion doesn't make any sense.
 "Andy Friesen" <andy ikagames.com> wrote in message
 news:cfbios$oqs$1 digitaldaemon.com...
 
Regan Heath wrote:

On Tue, 10 Aug 2004 10:12:56 -0700, parabolis <parabolis softhome.net>
wrote:


Regan Heath wrote:


What does everyone think, is there any point to default parameters in
interfaces, if so, what should they do, how should they behave.

interface DataSink { write( ubyte buf, uint len = 0, uint off = 0 ); }

What's your point?.. try: interface DataSink { void write( ubyte[] buf, uint len = 0, uint off = 0 ); } class weirdOne : DataSink { void write( ubyte[] buf, uint len = 100, uint off = 100 ) { printf("weirdOne: %u %u\n",len,off); } } class weirdTwo : DataSink { void write( ubyte[] buf, uint len, uint off ) { printf("weirdTwo: %u %u\n",len,off); } } void main() { weirdOne w1 = new weirdOne(); weirdTwo w2 = new weirdTwo(); ubyte[] bf; w1.write(bf); w2.write(bf,1,2); } Notice w2.write requires those parameters to be specified, so the interface ones mean nothing. Notice w1.write outputs "100 100" and w2.write outputs "1 2", neither outputs "0 0".

This is the reason default arguments were originally not part of the D spec: default arguments do not get along with polymorphism at all. Given: DataSink w3 = new weirdOne(); w3.write(bf); The defaults specified in the DataSink interface will be used. An overload or two in place of a default argument is a bit more fingerwork, but it's also much more likely to do the right thing. template DataSinkAdapter() { void write(ubyte[] buf, uint len) { return write(buf, len, 0); } void write(ubyte[] buf) { return write(buf, buf.length); } } -- andy


-- Justin (a/k/a jcc7) http://jcc_7.tripod.com/d/
Aug 10 2004