Thread overview
default parameters in interface, does it make sense
Aug 10, 2004
Regan Heath
Aug 10, 2004
parabolis
Aug 10, 2004
Regan Heath
Aug 10, 2004
Andy Friesen
Aug 10, 2004
antiAlias
Aug 10, 2004
Andy Friesen
Aug 11, 2004
J C Calvarese
August 10, 2004
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/
August 10, 2004
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 );
}

:)

August 10, 2004
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/
August 10, 2004
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
August 10, 2004
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


August 10, 2004
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
August 11, 2004
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/