Sign in to follow this  

[.net] Interface Functions

This topic is 4681 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Is writing class functions and accessors as non-virtual, then passing through to these with explicit interface implementations to avoid a speed hit from virtual when calling directly to the class a good optimization or are they called as not virtual if not through the interface anyway? Hope that was clear [grin], got to run..

Share this post


Link to post
Share on other sites
Quote:
Original post by DrGUI
Hope that was clear [grin], got to run..
Not quite - at least not to me (of course I can be a little slow sometimes :)). Can you provide an example of what you're trying to do?

Share this post


Link to post
Share on other sites
Sorry about it being rushed.

If you have like:

public interface IA
{
void Z();
}

public class A
{
public void Z() {}
}

If you called A.Z(), that would be a normal call.

public class B : IA
{
public void Z() {}
}

If you call (B as IA).Z() now, this will be a virtual call because of the level of indirection.

My question is: if you can B.Z(), is that a virtual call or not. If it is, you could avoid the virtual call when B is used directly by using explicit interface implementation and simply calling the non-virtual functions in your class.

Clear now? :~)))
Thanks

Share this post


Link to post
Share on other sites
What do you mean by explicit interface implementation? Do you mean using an interface because interfaces are nothing but virtual functions anyway, right?

My guess is that whenever you call a virtual function (defined in an interface or not) from the furthest derived class, it gets optimized so that the function is called directly without using the v-table. Since there's no reason this shouldn't happen, I suspect it get's done that way if the compiler is any good at all.

I'm no expert, but that's my two cents. I'm not sure I understand exactly what you're asking though...

Share this post


Link to post
Share on other sites
He's talking about .NET code I assume, probably C# ...

I don't know for sure what the interface code generates exactly, but I do know the way the language SPECIFIES it, they do not guarantee that it will or won't be implemented the same as a virtual, unless you specify the virtual keyword on your first level implementation ..


public interface IInterface
{
void Foo();
}

public class NoVirtualNoInterface
{
public void Foo() {}
}

public class VirtualNoInterface
{
public virtual void Foo() {}
}

public class NoVirtualInterface : public IInterface
{
public void Foo() {}
}

public class VirtualInterface : public IInterface
{
public virtual void Foo() {}
}

public class ExplicitInterface : public IInterface
{
void IInterface.Foo() {}
}

public class DerivedNoVirtualInterface : public NoVirtualInterface
{
public void Foo() {}
}

public class DerivedVirtualInterface : public VirtualInterface
{
public virtual void Foo() {}
}

public class DerivedExplicitInterface : public ExplicitInterface
{
void Interface Foo() {}
}



There are even more cases I didn't cover, but here's what we can say for sure:

NoVirtualNoInterface is the only version above that is guaranteed not to require an indirection in or lookup cost in the call.

VirtualNoInterface, VirtualInterface, DerivedVirtualInterface are the only ones guaranteed to use a vtable, and have those exact behaviors and performance characteristics WHEN called through a virtual class.

VirtualInterface, and DerivedVirtualInterface will have interface call overhead, WHEN called through an interface.

ExplicitInterface, and DerivedExplicitInterface can only call those functions through an interface, so they have interface call overhead.

In general the overhead of virtual and interface calls is identical, but the JIT compiler can detect and optimize various situations with each.


Share this post


Link to post
Share on other sites
Didn't I say I was using C#? <cringe>

Thanks for replying!

Geronimo2000, I guessed that too, but I wanted to make sure.

Thanks too Xai, I meant calling an interface function not through the interface, but directly through the class.

Oh - I'm afraid you got the explicit interface a little wrong:
Should be:
public class DerivedExplicitInterface : IInterface
{
void IInterface.Foo() {}
}
but that's just a little mistake if you were thinking of C++ at the time!

Thanks again - isn't it wonderful having a community like this?

Share this post


Link to post
Share on other sites
If I'm following your question correctly, you're wondering about perf, I threw this together real fast, albeit running under 2.0b1...

Concrete = 00:00:05.1447911
Sealed = 00:00:04.9875533
Derived Concrete = 00:00:07.4113756
Sealed Derived Concrete = 00:00:06.2860134
Derived Override Concrete = 00:00:06.3353831
Sealed Derived Override Concrete = 00:00:06.3394249
Concrete Implementation = 00:00:04.9450892
Sealed Concrete Implementation = 00:00:04.9364544
Interface Definition = 00:00:08.2264802


using System;
using System.Diagnostics;

namespace ConsoleApplication2 {
public static class Program {
private const int iterations = 1000000000;
private static Stopwatch stopwatch = new Stopwatch();
private static long output;

private static void Main() {
ConcreteClass concreteClass = new ConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += concreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Concrete = " + stopwatch.Elapsed);

SealedConcreteClass sealedConcreteClass = new SealedConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += sealedConcreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Sealed = " + stopwatch.Elapsed);

DerivedConcreteClass derivedConcreteClass = new DerivedConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += derivedConcreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Derived Concrete = " + stopwatch.Elapsed);

SealedDerivedConcreteClass sealedDerivedConcreteClass = new SealedDerivedConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += sealedDerivedConcreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Sealed Derived Concrete = " + stopwatch.Elapsed);

DerivedOverrideConcreteClass derivedOverrideConcreteClass = new DerivedOverrideConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += derivedOverrideConcreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Derived Override Concrete = " + stopwatch.Elapsed);

SealedDerivedOverrideConcreteClass sealedDerivedOverrideConcreteClass = new SealedDerivedOverrideConcreteClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += sealedDerivedOverrideConcreteClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Sealed Derived Override Concrete = " + stopwatch.Elapsed);

ConcreteImplementationClass concreteImplementationClass = new ConcreteImplementationClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += concreteImplementationClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Concrete Implementation = " + stopwatch.Elapsed);

SealedConcreteImplementationClass sealedConcreteImplementationClass = new SealedConcreteImplementationClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += sealedConcreteImplementationClass.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Sealed Concrete Implementation = " + stopwatch.Elapsed);

InterfaceDefinition interfaceDefinition = new SealedConcreteImplementationClass();
output = 0;
stopwatch.Reset();
stopwatch.Start();
for(int i = 0; i < iterations; i++) {
output += interfaceDefinition.Add(i);
}
stopwatch.Stop();
Console.WriteLine("Interface Definition = " + stopwatch.Elapsed);

Console.ReadLine();
}
}

public sealed class ConcreteClass {
private int total;

public int Add(int valueToAdd) {
this.total += valueToAdd;
return this.total;
}
}

public sealed class SealedConcreteClass {
private int total;

public int Add(int valueToAdd) {
this.total += valueToAdd;
return this.total;
}
}

public abstract class AbstractClass {
private int total;

public virtual int Add(int valueToAdd) {
this.total += valueToAdd;
return this.total;
}
}

public class DerivedConcreteClass : AbstractClass{
}

public sealed class SealedDerivedConcreteClass : AbstractClass {
}

public class DerivedOverrideConcreteClass : AbstractClass {
private int myTotal;

public override int Add(int valueToAdd) {
this.myTotal += valueToAdd;
return this.myTotal;
}
}

public sealed class SealedDerivedOverrideConcreteClass : AbstractClass {
private int myTotal;

public override int Add(int valueToAdd) {
this.myTotal += valueToAdd;
return this.myTotal;
}
}

public interface InterfaceDefinition {
int Add(int valueToAdd);
}

public class ConcreteImplementationClass : InterfaceDefinition {
private int total;

public int Add(int valueToAdd) {
this.total += valueToAdd;
return this.total;
}
}

public sealed class SealedConcreteImplementationClass : InterfaceDefinition {
private int total;

public int Add(int valueToAdd) {
this.total += valueToAdd;
return this.total;
}
}
}

Share this post


Link to post
Share on other sites
Thanks a lot! Real fast?!

But there doesn't seem to be much difference between concrete and sealed concrete!

public sealed class ConcreteClass {

public sealed class SealedConcreteClass {

Thanks anywho!

Share this post


Link to post
Share on other sites

This topic is 4681 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this