Jump to content
  • Advertisement
Sign in to follow this  
Bombshell93

is there a way of merging or replacing ambiguous methods / properties in an interface?

This topic is 2359 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

So cleaning up my entity component system to have my level editor run better and I'm finding myself changing a lot.
One of the things I'm changing is implementing interfaces to dynamicly check an entity for its components, as well as allowing simple acting upon it, via properties, EG a bomb blows up next to an entity, if it has health, remove some.
The problem I have is multiple components may need and by extension include a Position property,
Likewise others may require a score or a velocity, etc.
Obviously I don't want to waste and put 6 position properties in 1 entity, but to multiple interfaces with the same properties will lead to ambiguity errors.

So is there a way I can merge or replace ambiguous interface members with a single member?

any and all help is appreciated,
Thanks in advanced,
Bombshell

Share this post


Link to post
Share on other sites
Advertisement
One possibility is to make, for example, the Position property it's own interface, and have other interfaces that have a Position inherit from that base interface.

Share this post


Link to post
Share on other sites
so if A contains Position, B inherits from A, C inherits from A, D inherits from B and C
D will only have 1 Position, I thought that caused to the diamond problem?

Share this post


Link to post
Share on other sites
You can't do that in C#? There's no multiple inheritance?

Edit: Interfaces don't have that problem. Even if you implement several interfaces which 'inherit' from another interface, the class will only implement that interface once. Edited by DvDmanDT

Share this post


Link to post
Share on other sites
There is no ambiguity with multiple interfaces using the same method, unless there is a return type conflict.

The diamond problem does not occur in C# since there is multiple *interface* inheritance, but NOT multiple *implementation* inheritance.


class Program
{
static void Main(string[] args)
{
C c = new C();
c.Position = 5;
var ia = c as IA;
var ib = c as IB;
Console.WriteLine(ia.Position);
Console.WriteLine(ib.Position);
}
}
interface IA
{
int Position { get; set; }
string Name { get; set; }
}
interface IB
{
int Position { get; set; }
string Color { get; set; }
}
class C : IA, IB
{
public int Position { get; set; }
public string Name { get; set; }
public string Color { get; set; }
}



If you changed IB.Position to a float, then it would have a conflict and you would need to explicitly implement one or both:


public int Position { get; set; } // becomes IA.Position since it matches the signature
float IB.Position { get; set; }


Note that you can only make ONE of these public. The public one is the one that c.Position uses, and the others are only accessible after you've casted to the interface.

I typically do what SiCrane suggests and pull common interface members out into a base interface, though. Edited by Nypyren

Share this post


Link to post
Share on other sites
thanks for the help great to know, up until now I had no clue on the difference between inheriting an interface and inheriting an abstract class :)

Share this post


Link to post
Share on other sites
This ties in with what SiCrane recommended - a nice way to think about organizing interfaces is to divide them up by a specific job or responsibility. Your case of an "IPositionable" is a great example, as you may have many entity components that all have a position but when you're checking if a component is within range of an explosion you don't really care about if its a health component or whatever. Another example would be if all of your components had a name to identify them, and you have an interface "INamable" with a string property called Name. This way you don't have to worry about a dozen different entity component interfaces, when you only care about a specific function that is all common to the type of component you want to modify, which can make for a neater and more consistent design.

As the other posters mentioned, inheritance rules are different for interfaces compared to classes (concrete or abstract). The nice thing about abstract classes though, is you're able to implement logic that is common to all subclasses, while leaving more specific implementation details up to those subclasses. So both have their pros and cons. Edited by Starnick

Share this post


Link to post
Share on other sites
Well, as far as I remember from the old days of tinkering with IL & Reflector, you don't really inherit an interface. There were some arcane ways in which reflection gets bugged and you can't easily extract the implemented interfaces, but that's not the point. Interfaces get "baked" into your class. You can implement interfaces either implicitly, or explicitly.

I would recommend against getting position into a different interface. I don't really know your design, but position might mean different things for different objects, and might need to carry different values. Generally, creating an interface for the sake of having an interface is a sign of code smell. Do you really need to encapsulate properties in different interfaces, because it would save you typing? No, I don't think so.

Inheritance implies a connection. Is a bomb a health bar? As in GUI elements, they both need to draw themselves. However, one of them has to move (IMoveable?), while the other is stationary. Both need to update what they display over time (IRedrawable or IUpdateable). Moreover, a bomb will probably want to display some sort of blowing up animation when/if it hits something (ICondition that composes IAnimation or IEffect). Interfaces and inheritance are supposed to perscribe behaviour, not save you typing. IPosition makes no sense. IMoveable makes much more sense. ISize makes no sense. IResizable, however, does.

Share this post


Link to post
Share on other sites
@starnick
as was my problem and as it is solved now but thank you for the elaboration :)

@dilyan_rusev
I'm assuming you mean I should not have IPosition but instead put Position properties in the interfaces that need it, which if I'm understanding correctly as long as the type is the same will not cause ambiguity errors.
In which case I'd probably agree, otherwise it'd be like making a structure to hold a single integer.

Share this post


Link to post
Share on other sites
TL;DR - more or less that is my point. If you happen to have such interfaces, at the very least name them properly, not after their properties.

You can't possibly have conflicts when you implement interfaces. I don't know if I can explain it very good, because I haven't been working with .NET for a year, and my memory is somewhat fuzzy.

As I said, interfaces are a special kind of animal in .NET. When you implement them, they kind of don't really "merge" with your class, as would be the case where you inherit a base class.

For example: you've got Animal, which is inherited by Cat. Cat *is* an animal for all intents and purposes. If there are conflicting methods, they either get overridden, or you get a compiler error. You can directly access the base class' implementation, and work with it.

In contrast, when you "inherit" an interface, you actually implement it (I like the Java terminology here better, because it is more accurate, even for .NET). You don't really inherit the methods, because there is nothing to inherit from. Methods and properties that come from an interface have two "modes" of implementation. First, called implicit, is where the compiler is looking for a method/property with the same signature, and then wires things up. The second one, called explicit, is where things get interesting: in C# you've got the weird return_type InterfaceName.MethodName(RestOfSignature), but in IL (stuff that matters), you method/property gets additional information baked in (IIRC, hidebysig). You no longer can invoke it directly, you have to cast your class to the interface first, and then call it through the interface. Also, it says where this comes from, so multiple implementations can't possibly conflict. Here are some examples

  • Cat has its own Fur property, but it also implements IHairyAnimal, which exposes its own Fur. They have the same type and name. The compiler is a smart guy, and would figure you would want to reuse Cat's Fur property to also implement IHairyAnimal's Fur property. Note also that interfaces impose *minimum* requirements. If IHairyAnimal has bool Fur {get;}, but Cat has bool Fur {get;set;}, it would still be OK.The compiler is really trying very hard to make life easier for you.
  • Cat has its own property, and it implements several interfaces that also have the same Fur property with the same return type. Again, no conflict, as the compiler would repeat the previous logic for every individual interface.
  • Cat implements multiple interfaces that have Fur, but with different return type. The compiler at this point would give up, and you will have to implement enough interfaces explicitly, so that there are no more conflicts. For example, if you have two interfaces with different type of Fur, you will have to implement at least one of them explicitly (suppose Cat didn't have its own Fur). When you do that, there are no more conflicts - to access the different kinds of Fur, you would, as expected, cast to the appropriate interface.

    Also, don't get me wrong - it's not evil to have interface with a single property/method. But that should be your last resort, because it is a little bit of over-engineering. You introduce interfaces, because you want to work with interfaces (not classes) in your code. Then, if everything is taken apart in tiny pieces, you might end up in a situation where the interface is not enough, and you cast it to another interface to get the information you need. Now, that *is* bad design. While having small interfaces doesn't necessarily lead down this path, it is very easy with time for your design to evolve into such monstrosity.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!