Thread overview | |||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 19, 2013 How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
I would like to require any implementation of an interface to override import std.stdio, std.cstream; interface A { void opOpAssign(string op : "^")(int c); } class B : A { int x; void opOpAssign(string op : "+")(int c) { x = c; } // Note it uses + } void main(string[] argv) { B b = new B; b ^= 3; writeln(b.x); din.getc(); } but the compiler gives an error that is 3 and b are incompatible types.. I'm not sure if ^= is overloaded in some default way or what but there is no error about b not implementing the property OpAssign. If I use override for opOpassign in B, dmd says it can't override a non-virtual function. This is a bit strange as it would seem it would break inheritance. The following code produces an undefined symbol... I could make A.opOpAssign final but then inheritance because a casualty. import std.stdio, std.cstream; interface A { void opOpAssign(string op)(int c) if (op == "^"); } class B : A { int x; void opOpAssign(string op : "^")(int c) { x = c; } } class C : B { void opOpAssign(string op : "^")(int c) { x = c+2; } } void main(string[] argv) { B b = new B; C c = new C; A a = new C; b ^= 3; writeln(b.x); c ^= 3; writeln(c.x); a ^= 3; writeln((cast(C)a).x); din.getc(); } Let me guess... this is a feature of D? |
July 19, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | You can't have templates in interfaces unless they are final, otherwise it won't work right. The way I'd do it is is make the op template final, and have it forward to another normal virtual function: interface Addable { final Addable opBinary(string op : "+")(Addable rhs) { return this.opAdd(rhs); } /* virtual */ Addable opAdd(Addable rhs); } class Test : Addable { override Addable opAdd(Addable rhs) { return new Test(); } } void main() { auto test = new Test(); auto test2 = new Test(); auto sum = test + test2; } |
July 19, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Fri, Jul 19, 2013 at 04:28:42PM +0200, Adam D. Ruppe wrote: > You can't have templates in interfaces unless they are final, otherwise it won't work right. > > The way I'd do it is is make the op template final, and have it forward to another normal virtual function: > > interface Addable { > final Addable opBinary(string op : "+")(Addable rhs) { > return this.opAdd(rhs); > } > > /* virtual */ Addable opAdd(Addable rhs); > } > > class Test : Addable { > override Addable opAdd(Addable rhs) { > return new Test(); > } > } [...] I'd add that you need to do this for base classes too, if you want overloaded operators to be overridable by derived classes. Template methods and inheritance don't mix together very well. T -- The diminished 7th chord is the most flexible and fear-instilling chord. Use it often, use it unsparingly, to subdue your listeners into submission! |
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | The relevant blog post: http://3d.benjamin-thaut.de/?p=94 What you should understand is template functions are not/can not be virtual. They do not exist until they are instantiated. Thus you can not require that they be overloaded. |
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Saturday, 20 July 2013 at 01:37:13 UTC, Jesse Phillips wrote:
> The relevant blog post:
>
> http://3d.benjamin-thaut.de/?p=94
>
> What you should understand is template functions are not/can not be virtual. They do not exist until they are instantiated. Thus you can not require that they be overloaded.
And this is a compiler limitation? After all, templated functions are ultimately just normal functions... In my case the template parameter is explicitly known and the overloadable operations being templated isn't my fault.
I guess I can redirect each templated function to a non-templated version using the method in benjamin's page but this seems like it defeats exactly what templates are for...
|
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | On Sat, Jul 20, 2013 at 12:13:49PM +0200, JS wrote: > On Saturday, 20 July 2013 at 01:37:13 UTC, Jesse Phillips wrote: > >The relevant blog post: > > > >http://3d.benjamin-thaut.de/?p=94 > > > >What you should understand is template functions are not/can not be virtual. They do not exist until they are instantiated. Thus you can not require that they be overloaded. > > And this is a compiler limitation? After all, templated functions are ultimately just normal functions... Nope. Templated functions don't exist until they're instantiated. Which means the compiler can't know in advance how many instantiations there will be and which ones they are. And given that D supports separate compilation, you *can't* know this (even after linking, there's the possibility that some external dynamic library might instantiate yet another version of the function). There are ways of implementing overloadable templated functions, of course. But they are rather complicated to implement, and incur runtime overhead. > In my case the template parameter is explicitly known and the overloadable operations being templated isn't my fault. > > I guess I can redirect each templated function to a non-templated version using the method in benjamin's page but this seems like it defeats exactly what templates are for... Not really. Having operator overloading implemented as template functions give you more flexibility (albeit at the cost of more code complexity). You could either redirect each operator to an overridable function, or you could do this: class MyClass { auto opBinary(string op)(T t) { // Buahaha, now op is a runtime parameter return opBinaryImpl(op, t); } auto opBinaryImpl(string op, T t) { // which means this method is overridable in // derived classes. ... } } You could also do this only for a certain subset of operators, depending on what granularity you wish to have. I'd write more, but I gotta run. Maybe later. T -- "Hi." "'Lo." |
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to H. S. Teoh | On Saturday, 20 July 2013 at 13:27:03 UTC, H. S. Teoh wrote:
> On Sat, Jul 20, 2013 at 12:13:49PM +0200, JS wrote:
>> On Saturday, 20 July 2013 at 01:37:13 UTC, Jesse Phillips wrote:
>> >The relevant blog post:
>> >
>> >http://3d.benjamin-thaut.de/?p=94
>> >
>> >What you should understand is template functions are not/can not
>> >be virtual. They do not exist until they are instantiated. Thus
>> >you can not require that they be overloaded.
>>
>> And this is a compiler limitation? After all, templated functions
>> are ultimately just normal functions...
>
> Nope. Templated functions don't exist until they're instantiated. Which
> means the compiler can't know in advance how many instantiations there
> will be and which ones they are. And given that D supports separate
> compilation, you *can't* know this (even after linking, there's the
> possibility that some external dynamic library might instantiate yet
> another version of the function).
>
> There are ways of implementing overloadable templated functions, of
> course. But they are rather complicated to implement, and incur runtime
> overhead.
>
>
>> In my case the template parameter is explicitly known and the
>> overloadable operations being templated isn't my fault.
>>
>> I guess I can redirect each templated function to a non-templated
>> version using the method in benjamin's page but this seems like it
>> defeats exactly what templates are for...
>
> Not really. Having operator overloading implemented as template
> functions give you more flexibility (albeit at the cost of more code
> complexity). You could either redirect each operator to an overridable
> function, or you could do this:
>
> class MyClass {
> auto opBinary(string op)(T t) {
> // Buahaha, now op is a runtime parameter
> return opBinaryImpl(op, t);
> }
> auto opBinaryImpl(string op, T t) {
> // which means this method is overridable in
> // derived classes.
> ...
> }
> }
>
> You could also do this only for a certain subset of operators, depending
> on what granularity you wish to have.
>
> I'd write more, but I gotta run. Maybe later.
>
>
> T
Thanks. I still think that interfaces define contracts that must be followed. If define an interfaces to use an operator I think any inheritance of it must implement that operator.
This might not work for templated members but should work for them if they are specialized.
e.g., we might not be able to do opOpAssign(string)() but we should be able to use opOpAssign(string op : "+")() to enforce a contract... in this case it not really any different than the code you show excep it is more natural(instead of opBinaryImpl we actually get to use opOpAssign as the name).
e.g.,
class MyClass {
auto opBinary(string op : "|" T : int)(T t) { }
// opBinary is completely specialized and is no different than a regular function, it can be overridden directly in children without having to use a redirection. (note in your opBinaryImpl, T must be specified
}
This way any children of MyClass *can* override the operation if necessary and inheritance actually works for templates to some degree. In fact, it should almost alway work because type parameter information can be used to pass to a normal function.
auto opBinary(string op, T)(T t)
{
returnopBinaryImpl(op, typeinfo(T), cast(object)t);
}
auto opBinaryImpl(string op, typeinfo type, object value) { }
so we could use this for the general case but then have the specifications for the cases we know about at the time of design.... but users of the base class can design their own operators to use(at a performance cost).
|
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | On Saturday, 20 July 2013 at 16:46:52 UTC, JS wrote:
> class MyClass {
> auto opBinary(string op : "|" T : int)(T t) { }
> // opBinary is completely specialized and is no different than a regular function, it can be overridden directly in children without having to use a redirection. (note in your opBinaryImpl, T must be specified
> }
I understand there is a little boilerplate when wanting to have overriding for the operator overloads, but I don't see much gain from the proposal.
Do you really want to force people to write
int opBinary(string op : "|" T : int)(T t)
instead of
override int opOr(int t)
when trying to override your function?
Though it might be interesting if an aliased function could be overridden:
class I {
final int opBinary(string op)(int t) { ... }
alias opAdd = opBinary!"+";
}
class MyClass : I{
override int opAdd(int v) { ... }
}
|
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips | On Saturday, 20 July 2013 at 18:34:30 UTC, Jesse Phillips wrote: > On Saturday, 20 July 2013 at 16:46:52 UTC, JS wrote: >> class MyClass { >> auto opBinary(string op : "|" T : int)(T t) { } >> // opBinary is completely specialized and is no different than a regular function, it can be overridden directly in children without having to use a redirection. (note in your opBinaryImpl, T must be specified >> } > > I understand there is a little boilerplate when wanting to have overriding for the operator overloads, but I don't see much gain from the proposal. > > Do you really want to force people to write > > int opBinary(string op : "|" T : int)(T t) > > instead of > > override int opOr(int t) > > when trying to override your function? > well, I see your point but it is less verbose AND if they want to allow the same op in there class, which they probably do, they have to override the long hand anyways and redirect. So all in all I think the long hand is better(more consistent with "previous practices"). > Though it might be interesting if an aliased function could be overridden: > > class I { > final int opBinary(string op)(int t) { ... } > alias opAdd = opBinary!"+"; > } > > class MyClass : I{ > override int opAdd(int v) { ... } > } I think this would be better. This way either choice could be used but there is no extra redirection that takes place(well, through the alias but that is symbolic). |
July 20, 2013 Re: How to require operator overloading in interface | ||||
---|---|---|---|---|
| ||||
Posted in reply to JS | On Saturday, 20 July 2013 at 18:53:44 UTC, JS wrote:
> if they want to allow the same op in there class, which they probably do, they have to override the long hand anyways and redirect.
Nope, that is why you make the template final and forwards, all derived classes will be able to instantiate the template and behavior will be overridden by the forwarded function.
|
Copyright © 1999-2021 by the D Language Foundation