Hello denizens of stack overflow, I'm having an issue (perhaps with understanding?) regarding polymorphism and generics. I want to be able to define a "system" that contains a "component". I also want to be able to extend systems and components to be able to have greater functionality.
I currently have two base classes, Component, and I/A_ComponentSystem (For the sake of brevity, I'm not going to be showing any actual code, just definitions):
public abstract class Component { }
public interface IComponentSystem { }
public interface IComponentSystem<TComponent> : IComponentSystem
where TComponent : Component { }
// The following are what should should actually be inherited from
public abstract class AComponentSystem : IComponentSystem { }
public abstract class AComponentSystem<TComponent> : AComponentSystem
where TComponent : Component { }
Below is an example component/system created:
public abstract class ITag : Component { } // This is to allow generating the code in a different binary. Hard to explain in the question, I'll clarify if need be
public class Tag : ITag { }
public abstract class ITagSystem : AComponentSystem<ITag> { }
public class TagSystem : ITagSystem { }
Below are some excerpts of actually trying to use the code/morph between the different objects (please note that the code isn't meant to be used in this way, but I'm writing unit tests to ensure compatibility between layers)
// This is the main system that will be passed around
TagSystem tagSys = new TagSystem();
// This is OK
ITagSystem ITagSys = (ITagSystem)ITagSys;
// This is OK
AComponentSystem A_TagSys = (AComponentSystem)tagSys;
// This is OK
AComponentSystem<ITag> ATag_TagSys = (AComponentSystem<ITag>)tagSys;
// This is OK
IComponentSystem I_TagSys = (IComponentSystem)tagSys;
// This is OK
IComponentSystem<ITag> ITag_TagSys = (IComponentSystem<ITag>)tagSys;
// Even the following is OK (which is why I am confused)
IComponentSystem<Tag> new_ITag_TagSys = (IComponentSystem<Tag>)tagSys;
//***This is where it blows up*** (1)
AComponentSystem<Tag> new_ATag_TagSys = (AComponentSystem<Tag>)tagSys;
I have another interface/class, SystemManager, which is defined thusly:
public interface ISystemManager
{
TComponent AddNewComponentToEntity<TComponent, TComponentSystem>(Entity e) // Please don't ask about Entity, it shouldn't be required for this snippet and I already feel like I've posted a lot)
where TComponent : Component, new() // Required for some reason or I get an error
where TComponentSystem : IComponentSystem<TComponent>;
}
Now, the specific block of code that I have here will throw an error as well:
//*** blows up here as well ***(2)
ISystemManager sysMan = new SystemManager(); // defined elsewhere
sysMan.AddNewComponentToEntity<Tag, ITagSystem>(entity);
As far as the errors that I receive, error (1) is:
Cannot convert type 'TagSystem' to 'AComponentSystem<Tag>'
Error (2) is below:
The type 'ITagSystem' cannot be used as type parameter 'TComponentSystem' in the generic type or method 'ISystemManager.AddNewComponentToEntity<TComponent,TComponentSystem>(Entity)'. There is no implicit reference conversion from 'ITagSystem' to 'IComponentSystem<Tag>'.
Now, as far as my question goes, it is thusly:
Why can I not convert TagSystem to AComponentSystem<Tag>? This seems like a valid morph.
Why is ITagSystem not converting to IComponentSystem<Tag>? It appears that Tag should still conform to ITag, which is supported.
Is there any way I could change my hierarchy while preserving my need for that many layers of abstraction?
Thank you to anyone for reading this and assisting me.
Note: Yes, this is for an EntityFramework driven game engine. I'm building it mainly as an exercise for myself, and so I can quickly spin up 3d projects for myself. Yes, I've built a few game projects before, no I'm not interested in "finishing" a game, I'm just tinkering and having fun.
Without a simpler and yet more-complete code example, it's impossible to provide specific advice in your specific scenario. However, the basic problem is that the types are indeed not convertible, just as the compiler says.
Why can I not convert TagSystem to AComponentSystem<Tag>? This seems like a valid morph.
TagSystem doesn't inherit AComponentSystem<Tag>. It inherits AComponentSystem<ITag>. These two types are not actually the same. Just because Tag inherits/implements ITag, that does not mean that AComponentSystem<Tag> automatically inherits/implements AComponentSystem<ITag>. If it did, then that would mean that a method or property of AComponentSystem<Tag> that normally would return a value of type Tag, could wind up being used in a situation where a Tag value is expected, but some other implementation of ITag is actually returned. This is because you would be able to cast to AComponentSystem<Tag>, and then use that reference to return the non-Tag implementation of ITag, to some code that only wanted Tag.
This is bad for what I hope are obvious reasons, so the compiler doesn't allow you to do that.
Why is ITagSystem not converting to IComponentSystem<Tag>? It appears that Tag should still conform to ITag, which is supported.
Without a good Minimal, Complete, and Verifiable code example, it's difficult to answer this part of your question, as the types you've shown don't appear consistent with the code you've shown. ITagSystem is declared as inheriting AComponentSystem<ITag>, which in turn implements only IComponentSystem, not IComponentSystem<TComponent>.
So based on the code shown, there's no reason even naively to think that the conversion could work. But let's assume for a moment there's a typo in the type declarations you've shown. Then the answer is basically the same as above: implementing IComponentSystem<ITag> is not the same as implementing IComponentSystem<Tag>.
Is there any way I could change my hierarchy while preserving my need for that many layers of abstraction?
Possibly. It depends on what these types actually do. Since C# 4, we've been able to specify generic type parameters on interfaces with covariance and contravariance. With a type parameter thus restricted, and interface members to match, the interface then can support specific casting scenarios like you're trying to do.
But note that this only works when the interface members really are compatible with such conversions. The compiler still won't let you do anything unsafe.
There are a lot of questions on Stack Overflow already discussing this. Technically your question could even be considered a duplicate of those. I hope the above addresses your immediate concerns, and gives you enough information to do more research and see if generic interface variance will work in your situation. If you need more help, I recommend you post a new question and make sure to include a good MCVE that clearly illustrates your question in the simplest way possible.
TagSystem distantly inherits AComponentSystem<ITag>, but you are trying to convert it to AComponentSystem<Tag>. (Note the lack of an "I" in the generic type.) Those two generic types of AComponentSystem<> are completely different, and you cannot freely cast between the two.
Same as point 1, just because Tag is a child of ITag doesn't mean that IComponentSystem<Tag> is a child of IComponentSystem<ITag>.
The answer is almost certainly yes, though exactly how depends entirely on how you are going to use it. You might also want to ask yourself if you really need this many layers of abstraction.
To give a better example of my first point, take for example a common generic type: the List. If generics followed the same inheritance rules as normal classes, then List<Car> would be a subtype of List<Vehicle>. But the difference between the two is that the first list can only hold cars, while the second list can hold any vehicle. So if these lists were parent and child, you would be able to do the following:
List<Car> cars = new List<Car>();
List<Vehicle> vehicles = (List<Vehicle>)cars;
vehicles.Add(new Truck());
You see the problem? The general rules of inheritance just allowed us to add a non-Car object to out list of cars. Or they would, provided that is a legal cast, which it isn't. In reality, List<Car> and List<Vehicle> are not related in any way, but are actually completely separate classes with no direct relation whatsoever.
Related
I have two questions regarding the use of an abstract class on left side of object instantiation.
AbstractClass MyClass = new ConcreteClass();
1 - What is this called? (when you declare the abstract class on the left.)
e.g.
Car MyNiceCar = new NiceCar();
I know this relates to Polymorphism, but I'm specifically asking how to describe/verbalize the scenario when declare the abstract class on the left.
2 - And why do it? i.e. Why would you do:
Car MyNiceCar = new NiceCar();
And not:
NiceCar MyNiceCar = new NiceCar();
?
Would the answer to question 2 possibly be so that i can do the following?
Car MyNiceCar = new NiceCar();
.
. //do some logic to decide if I can have a nicer car.
.
MyNiceCar = new EvenNicerCar();
1) You're creating a base class reference to your Derived class.
Edit:
Other words for BaseClass: SuperClass, ParentClass
Other words for DerivedClass: SubClass, ChildClass
Don't ask why there are so many words for each. It's kinda a Spaces vs Tabs type thing.
2) You do it so that you can use virtual functions/properties that you know all the derived classes will have. You want to do something that a Car can do, and you don't care if its a CrapCar, NiceCar or SuperNiceCar
Car car = new MyNiceCar();
car.honk(); //meep!
car = new SuperNiceCar();
car.honk(); //beep beep!
However, you can't go the other way around.
SuperNiceCar may support UseTurbo(), but MyNiceCar does not.
But you don't care, you just want the car to honk, so you cast it as a Car, because you know all Cars can honk.
See also
1 - What is this called?
This is a type of polymorphism that's called "inclusion polymorphism". It allows you to create restrictions on the type of variable that can be used in your code, while still allowing some type flexibility. Java and C#, for instance, have generics that allow various types and references to use the same code. However, these often run into run-time issues that could otherwise be caught by a static code analyzer. It's generally considered to be less risky to rely on the static analyzer (assuming your IDE has a good one) than to wait and find out your code has bugs in it after your release.
2 - And Why do it?
In addition to the reason I gave above, one of the most common applications of this is the polymorphic array.
Consider the following:
// Both classes contain an Accelerate() function
NiceCar MyNiceCar = new NiceCar();
EvenNicerCar MyEvenNicerCar = new EvenNicerCar();
// We're forced to use these methods separately
MyNiceCar.Accelerate();
MyEvenNicerCar.Accelerate();
////////////////////////////////////////////////////////////////////////////////////////////////////
// We can make this code much smaller and less prone to copy/paste errors using polymorphism!
Car[] MyPolymorphicArray = new Car[] { new NiceCar(), new EvenNicerCar() };
foreach(c in MyPolymorphicArray) { c.Accelerate(); }
Using this type of syntax, you can see that I'm able to make the code smaller, more-manageable, type-safe, and our static code analyzer will complain if we get it wrong, rather than waiting until runtime to find out. When you use this type of architecture, make sure you require the methods intended to be used by the instances to either be in an interface or in the parent class of that object in order to help avoid implementation errors. Additionally, take note that if you do this, the Accelerate() method may only need to be written in the parent class, which helps make the code even smaller.
Following on from two excellent answers from #Mars and #chris-mauer which both answered Question 2 of my post perfectly. And allowed me to study this concept further.
I want to include that the answer to Question 1 of my post as follows. I asked:
AbstractClass MyClass = new ConcreteClass();
1 - What is this called? (when you declare the abstract class on the left.)
From the article below, I believe the correct answer is:
Upcasting
For more on the overall concept, which is Inclusion Polymorphism, I studied the following article: http://www.msdotnet.co.in/2014/05/how-to-implement-polymorphism-concepts.html
I am designing a scenario where two PostSharp aspects are working with each other. I have one aspect (FirstAspect in the code below) that is meant to introduce an interface, and then another aspect (SecondAspect in the code below) is supposed to work with the interface that was introduced by the first aspect.
However, it does not seem that the interface that is introduced by the first aspect is ever available to the second aspect.
Here is the code that I am currently working with:
public class Tests
{
[Fact]
public void Verify()
{
// Not really all that significant as the current code does not compile correctly:
var sut = new MyClass();
Assert.True( sut is IInterface );
}
public interface IInterface
{
void HelloWorld();
}
[IntroduceInterface( typeof(IInterface) )]
public class FirstAspect : InstanceLevelAspect, IInterface, IAspectProvider
{
public void HelloWorld() {}
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
// Implementing IAspectProvider appears to ensure this aspect is processed first.
// This may be a bug.
// Please see: http://support.sharpcrafters.com/discussions/problems/3365-runtimeinitialize-does-not-follow-ordering-rules#comment_40824072
// for more information.
yield break;
}
}
[AspectTypeDependency( AspectDependencyAction.Order, AspectDependencyPosition.After, typeof(FirstAspect) )]
public class SecondAspect : InstanceLevelAspect, IAspectProvider
{
public IEnumerable<AspectInstance> ProvideAspects( object targetElement )
{
var type = (Type)targetElement;
if ( !typeof(IInterface).GetTypeInfo().IsAssignableFrom( type ) )
{
// This is currently being thrown, as MyClass does not implement
// IInterface when the AppDomain is first loaded and initialized:
throw new InvalidOperationException( $"Does not implement {typeof(IInterface)}" );
}
// How to access the weaved elements from FirstAspect? ...
yield break;
}
}
[FirstAspect, SecondAspect]
class MyClass {}
}
When I build, the InvalidOperationException in the SecondAspect.ProvideAspects is thrown, as the interface that was introduced by FirstAspect is not available to SecondAspect at the time the call is made. That is, even though the interface has been weaved into the MyClass type, the type as it stands within the current AppDomain as loaded is not marked as having the interface implemented.
What I am looking for is the ability to access and locate all known and weaved interfaces and members on a target element during build time.
I looked into ReflectionSearch, and this is close to what I am looking for, but it does not appear to account for weaved elements at the time calls into this API are made. For instance, making a call to ReflectionSearch.GetMembersOfType does not yield the expected IInterface.HelloWorld on MyClass (which is introduced by FirstAspect in the example above).
Is there another API I should be using to access introduced/weaved elements by PostSharp during build-time? Is this even possible?
So this question looks a little old, but I have a similar issue which I still need an answer to (which is: how do I introduce an attribute to an introduced method without applying the attribute to the implementation and copying it). That said, I may have to ask my own question, as there are some common steps for the pattern you're asking about which may solve your dilemma, but do not solve mine. It looks like you've already experimented with some of this, but for the sake of others that come along, I'll detail it out.
In short, don't use "reflection" types to specify aspect dependency. PostSharp provides attributes which you can use to require aspects to be applied or to require specific order (See: Coping with Several Aspects on the Same Target for an overview), as well as a method for importing members already provided by other aspects (This StackOverflow Answer, while not marked, is the correct answer to that user's question and also shows a way to use the ImportMemberAttribute together with aspect dependency). The ImportMemberAttribute is capable of importing members from other aspects as long as the order is correct; the IsRequired property on this attribute will cause a build error if the member does not exist and was not introduced by an aspect.
Now, if you want your second aspect to be able to apply to all classes that implement an interface, whether the interface was applied by your first aspect or not, you would set the AspectTypeDependencyAttribute with AspectDependencyAction.Order, but not set an AspectTypeDependencyAttribute with AspectDependencyAction.Required; if you only want the second aspect to apply to targets advised by the first then you can apply multiple dependency attributes to specify both the requirement and the order and no Aspect Provider would be required (the above answer also shows an alternative implementation applying Advice to multiple Pointcuts in a single Aspect). Similarly, if you want your first aspect to always require your second aspect you can apply an additional AspectTypeDependencyAttribute to specify requirement in the other direction (i.e. if both require the other you want the requirement specified on both).
Aspect "Priority" can also be used to determine the order aspects are applied, although whenever possible you should use the dependencies instead because they also server as contract documentation.
This is all assuming you don't actually need to use an Aspect Provider (since your comments imply it was done for ordering). You would not want one Aspect Provider to depend on the results of another Aspect Provider (this would violate separation of concerns), you would instead have a single Aspect Provider yield multiple aspects for each target. You can, however, use AspectTypeDependencyAttribute on Aspect Providers as well so, for instance, you can have a Type Level Aspect Provider that orders after a type level aspect that introduces an interface and then in the provider you can loop through methods on the type and inject aspects that depend on the first aspect (e.g. an interface introduction follower by a provider that applies method interception advice to members that can now call methods introduced by the first aspect).
Hope that clears things up for you (or, given the time since the question was asked, anyone else that runs into this issue). Some of this information may also be outdated or inaccurate (for all I know, it may now be possible to detect injected interfaces on the target types passed to aspect providers, under some or any condition), but I believe the patterns expressed are still the preferred practice proposed by PostSharp.
i've been doing some research on interfaces and a simple layman's explanation for what it truly is. when searching through seas of books For some reason people love using overly complex explanations and jargon to explain truly simple concepts (guess it makes them feel big) and i have a gut feeling it's the same in this case.
so from what i could grasp, it seems like interfaces are nothing more than a way to reserve method names, their return type if any, and the type and amount of arguments they accept. so when a class implements an interface (or interfaces) it is forced to define the body of each method from the interface(s). Am i on the nose with this one or do i need to keep digging?
p.s. i know javascript doesn't have support for interfaces, but i still need to understand the concept because there are quite a few places where it's shown how to emulate to an extent.
For some reason people love using overly complex explanations and jargon to explain truly simple concepts (guess it makes them feel big)
Consider eschewing the editorial comments that impute bad motives to people who are trying to help you. That's a really bad way to try to get people to help you.
It seems like interfaces are nothing more than a way to reserve method names, their return type if any, and the type and number of arguments they require. So when a class implements an interface (or interfaces) it is forced to define the body of each method from the interface(s). Am i on the nose with this one or do i need to keep digging?
You are on the right track but you err in the details. In C#, for example, an implementing class is not required to provide a body. The method which corresponds to the interface method could, for example, be an abstract method in an abstract class, which would then not have a body. And in C# an interface can require members other than methods; properties, events and indexers, for example.
A more concise and typical way to express the idea that interfaces impose a requirement that a type supply members that match certain signatures is to say that the interface represents a contract that must be fulfilled by its implementer. But that might be too complex and jargonish for your gut to stomach.
I explain the concept to lay people using an analogy that most people understand - plastic molding.
The interface defines the shape of an object in the exact same way a mold will provide the shape of the finished product.
You could inject a mold with White plastic, blue plastic, something exotic like an Epoxy or clay.
What matters is, no matter what they are actually made of, they all have the same exact consistent shape to the purchaser of the product.
For code, this means no matter what code is used to implement the interface, they all follow the same consistent contract/shape to the end user.
I hope that might help a little.
Edit -
To extend the analogy to Abstract classes, imagine the next step in the molding process. You run a White, blue, and red plastic production run, but then each item needs to be painted at a separate factory, we just ship them out.
The item is not finished, but it does have its shape defined. Someone later will come and fill out the details that our factory left blank.
These items cannot be sold until they get that last painting step.
In code, the abstract implementation of the interface provides some (or none) of the implementation, but leaves another descendant class to complete the contract, and in the same way no one can create an instance of the class until the contract has been completed.
In the same way though, you can still refer to an abstract class in code, just like you can refer to the unpainted mold item as a "White molded thing" wither or not it is painted!
Edit 2
Here's a short example
void Main()
{
//IMold mold = new IMold(); // error - can't create instance of an interface
//Fruit fruit = new Fruit(); // error - can't create instance of an abstract class
Apple apple1 = new Apple(); // good
Orange orange1 = new Orange(); // good
Fruit apple2 = (Fruit)apple1; // good - Apples are fruit
Fruit orange2 = (Fruit)orange1; // good - oranges are fruit
IFruitMold apple3 = (IFruitMold)apple2; // good - Apples fit the Mold
IFruitMold orange3 = (IFruitMold)orange2; // good - Oranges also fit the mold
//now I can do this:
//Notice that `fruits` is of type IList<T> but the new is List<T>
//This is the exact concept we are talking about
//IList<T> is some kind of set of items that can be added or subtracted from
//but we don't have to care about the implementation details of *HOW* this is done
IList<IFruitMold> fruits = new List<IFruitMold>();
fruits.add(apple3);
fruits.add(orange3);
foreach( var fruit in fruits )
{
fruit.PlasticColor.Dump(); // ok I can read
fruit.PlasticColor = ""; // error - no Set defined in the interface
// depending on the **implementation details** of what type of fruit this is true or false
// we don't care in the slightest, we just care that we have some IFruitMold instances
fruit.RequiresPainting.Dump();
}
}
interface IFruitMold
{
string PlasticColor { get; }
bool RequiresPainting { get; }
}
abstract class Fruit : IFruitMold
{
private string m_PlasticColor = string.Empty;
public string PlasticColor { get; private set; }
public abstract bool RequiresPainting { get; }
}
//notice that we only define the abstract portion of the base class
//it defined PlasticColor for us already!
//the keyword `override` is required - it is to make it clear that
//this member is overriding a member from it's parent.
class Apple : Fruit
{
public override bool RequiresPainting { get { return true; } }
}
class Orange : Fruit
{
public override bool RequiresPainting { get { return false; } }
}
Yes, in a nutshell interfaces are there to declare and promise everyone else that a class will have certain methods.
This is good when you create generalized methods and function, where you want a more abstract design. All you want to know is that your function can receive an object that had methods A B and C.
Interface is just a simple empty class, that show the contract on how you real class should look. I think you have the concept ok.
They don't reserve anything (I don't understand what you mean by that), is just a way so when you build your class around the interface, you have a prior knowledge of how will your class look like. And also you can know before which methods will it have.
when a class implements an interface (or interfaces) it is forced to define the body of each method from the interface(s).
Yes. Interfaces are contracts. They let others know that your class implements certain functionality.
I would say its more than reserving the method name it is a way of making a contract that the method will exist and the caller will not need to know what it does but it will still be available to be called
A good example would be a pen and pencil both can implement an Iwriter interface with a write method but whoever calls the write method doesn't need to know that one uses ink and one uses lead the caller will just know that it is going to write words on the paper.
Interfaces provide a uniform way of interaction with a set of objects.
No matter what the object is, if it implements the interface we know that it will respond to a method defined in the interface. In this way, we can create objects that represent different things in a project and still interact with them in the same way. The actual implementation of the methods defined in the interface can be completely different, but they will take the same inputs and provide the same type of output.
Basically an interface is a contract which can define properties (getters and setters) or methods (with whatever parameters you require). If an object 'implements' the interface it needs to define a concrete implementation for ALL the properties and methods defined in the interface.
For unit testing or Inversion of Control containers interfaces really come into there own as you can call methods/properties on the interface without knowing anything about the object which actually implements it.
Interface is used to provide common functionality among a set of completely unrelated objects.
Lets say we have a bunch of animal objects and we need to separate pets from that bunch. The task of separation becomes really simple if we enforce a contract such that all the animals which are pets needs to implement IPet interface.
Summary
Let's say I have two C# 4.0 classes, one inheriting from the other:
class ParentKey {}
class ChildKey : ParentKey {}
I want the compiler to issue an error if I try this:
ChildKey c = new ChildKey();
ParentKey p = c; // I want compiler error here!
Essentially, I want to use inheritance for reusability purposes, but I want to avoid polymorphic behavior (or more specifically, assign compatibility) that normally comes with it. Similar to C++ private inheritance.
Example
Specifically, I'd like to avoid accidentally mixing ParentKey and ChildKey when used as keys of some container (since their implementations of GetHashCode() or Equals() might be incompatible). For example:
Dictionary<ParentKey, object> d = new Dictionary<ParentKey, object>();
d.Add(new ChildKey(), new object()); // I want compiler error here!
What I Tried
Now, I know I can use composition to avoid the inheritance altogether, but I'd like to avoid the verbosity that comes with this solution (my ParentKey can be quite complex, and there may be many levels of inheritance hierarchy).
Another solution is to always use tailor-made IEqualityComparer, or to explicitly create new ParentKey based on the ChildKey prior passing to the container, but both of these are easy to forget, and may be comparatively hard to diagnose at run-time.
Attempting to make the conversion explicit...
class ChildKey : ParentKey {
public static explicit operator ParentKey(ChildKey c) {
// ...
}
}
...yielded compiler error CS0553: user-defined conversions to or from a base class are not allowed.
Struct inheritance would be ideal here (so the "end" portion of ChildKey is "cut-off" when passed to something that is declared as ParentKey), but this is not supported in C# either.
Am I missing something obvious here? Any ideas? Thanks.
You're working directly against the by-design purpose of the type system, which is to make it always possible to assign a more-derived type to a variable of a less-derived type. (Moreoever: suppose you did somehow manage to prevent implicit reference conversions from Derived to Base -- what stops you from converting Derived to object and then explicitly converting object to Base? It seems perverse to prohibit something at compile time that we cannot prevent at runtime.)
I agree that from a language design perspective, it is possible to create a language which avoids conflating code reuse via inheritance with subtype polymorphism. However, we chose to conflate those two things a long, long time ago. You're going to have to either live with that choice, or use a different language that gives you the feature you want. (*)
My advice: stop spitting into the wind. Either use composition, or carefully craft your Equals and GetHashCode methods so that everyone plays together nicely.
(All that said, I have often shared your frustration that reuse via composition has so much verbose "ceremony" around it. It would be great if we could find a way to lower the syntactic burden of composition.)
(*) I am definitely not an expert on Eiffel; that said, your idea seems to me to be like the Eiffel concept of non-conforming inheritance. Perhaps an expert on Eiffel would like to comment on this?
How about:
class BaseKey
{
// all functionality here
}
class ParentKey : BaseKey
{}
class ChildKey : BaseKey
{}
?
public struct Exclusive<T>
{
public Exclusive(T item)
{
if (c.GetType () != typeof(ParentKey))
throw new Exception (); // I want compiler error here!
Item = item;
}
public T Item{get; private set;}
// todo: add implicit cast to T
// todo: add forcing non-null to get_Item
}
This is a shortcoming of the C# (and C++) language, I hope it will be fixed (but doubt it ..)
In my (not common) opinion polymorphism is an anti pattern, basically a bad idea that somehow became popular, this becomes more and more obvious the more functional code you write.
On the other hand, extension is an invaluable coding mechanism and trying to replicate it with composition just so you can avoid polymorphism is tedious and bug prone and doesn't scale.
(as a side note, IMO it would not be hard to add this to the language, ie an "extends" keyword Class ChildKey extends ParentKey {} etc)
What I do is use the "curiously recurring template pattern"
abstract class KeyBase<TDerived> { /* common functionality here */ }
class Key : KeyBase<Key> { /* inherit common functionality */ }
Of course this does not stop a user from doing
Key c = new Key();
KeyBase<Key> p = c;
But it has a few advantages:
It becomes more explicit from from the template argument that the intention is extension and that no KeyBase<Key> variables should be declared.
KeyBase methods can now accept and return TDerived, this is especially useful when dealing with immutable classes
You can easily create different Key types (KeyEx) which have identical API but are different types (typeof(Key)!=typeof(KeyEx)).
Every so often, I run into a case where I want a collection of classes all to possess similar logic. For example, maybe I want both a Bird and an Airplane to be able to Fly(). If you're thinking "strategy pattern", I would agree, but even with strategy, it's sometimes impossible to avoid duplicating code.
For example, let's say the following apply (and this is very similar to a real situation I recently encountered):
Both Bird and Airplane need to hold an instance of an object that implements IFlyBehavior.
Both Bird and Airplane need to ask the IFlyBehavior instance to Fly() when OnReadyToFly() is called.
Both Bird and Airplane need to ask the IFlyBehavior instance to Land() when OnReadyToLand() is called.
OnReadyToFly() and OnReadyToLand() are private.
Bird inherits Animal and Airplane inherits PeopleMover.
Now, let's say we later add Moth, HotAirBalloon, and 16 other objects, and let's say they all follow the same pattern.
We're now going to need 20 copies of the following code:
private IFlyBehavior _flyBehavior;
private void OnReadyToFly()
{
_flyBehavior.Fly();
}
private void OnReadyToLand()
{
_flyBehavior.Land();
}
Two things I don't like about this:
It's not very DRY (the same nine lines of code are repeated over and over again). If we discovered a bug or added a BankRight() to IFlyBehavior, we would need to propogate the changes to all 20 classes.
There's not any way to enforce that all 20 classes implement this repetitive internal logic consistently. We can't use an interface because interfaces only permit public members. We can't use an abstract base class because the objects already inherit base classes, and C# doesn't allow multiple inheritance (and even if the classes didn't already inherit classes, we might later wish to add a new behavior that implements, say, ICrashable, so an abstract base class is not always going to be a viable solution).
What if...?
What if C# had a new construct, say pattern or template or [fill in your idea here], that worked like an interface, but allowed you to put private or protected access modifiers on the members? You would still need to provide an implementation for each class, but if your class implemented the PFlyable pattern, you would at least have a way to enforce that every class had the necessary boilerplate code to call Fly() and Land(). And, with a modern IDE like Visual Studio, you'd be able to automatically generate the code using the "Implement Pattern" command.
Personally, I think it would make more sense to just expand the meaning of interface to cover any contract, whether internal (private/protected) or external (public), but I suggested adding a whole new construct first because people seem to be very adamant about the meaning of the word "interface", and I didn't want semantics to become the focus of people's answers.
Questions:
Regardless of what you call it, I'd like to know whether the feature I'm suggesting here makes sense. Do we need some way to handle cases where we can't abstract away as much code as we'd like, due to the need for restrictive access modifiers or for reasons outside of the programmer's control?
Update
From AakashM's comment, I believe there is already a name for the feature I'm requesting: a Mixin. So, I guess my question can be shortened to: "Should C# allow Mixins?"
The problem you describe could be solved using the Visitor pattern (everything can be solved using the Visitor pattern, so beware! )
The visitor pattern lets you move the implementation logic towards a new class. That way you do not need a base class, and a visitor works extremely well over different inheritance trees.
To sum up:
New functionality does not need to be added to all different types
The call to the visitor can be pulled up to the root of each class hierarchy
For a reference, see the Visitor pattern
Cant we use extension methods for this
public static void OnReadyToFly(this IFlyBehavior flyBehavior)
{
_flyBehavior.Fly()
}
This mimics the functionality you wanted (or Mixins)
Visual Studio already offers this in 'poor mans form' with code snippets. Also, with the refactoring tools a la ReSharper (and maybe even the native refactoring support in Visual Studio), you get a long way in ensuring consistency.
[EDIT: I didn't think of Extension methods, this approach brings you even further (you only need to keep the _flyBehaviour as a private variable). This makes the rest of my answer probably obsolete...]
However; just for the sake of the discussion: how could this be improved? Here's my suggestion.
One could imagine something like the following to be supported by a future version of the C# compiler:
// keyword 'pattern' marks the code as eligible for inclusion in other classes
pattern WithFlyBehaviour
{
private IFlyBehavior_flyBehavior;
private void OnReadyToFly()
{
_flyBehavior.Fly();
}
[patternmethod]
private void OnReadyToLand()
{
_flyBehavior.Land();
}
}
Which you could use then something like:
// probably the attribute syntax can not be reused here, but you get the point
[UsePattern(FlyBehaviour)]
class FlyingAnimal
{
public void SetReadyToFly(bool ready)
{
_readyToFly = ready;
if (ready) OnReadyToFly(); // OnReadyToFly() callable, although not explicitly present in FlyingAnimal
}
}
Would this be an improvement? Probably. Is it really worth it? Maybe...
You just described aspect oriented programming.
One popular AOP implementation for C# seems to be PostSharp (Main site seems to be down/not working for me though, this is the direct "About" page).
To follow up on the comment: I'm not sure if PostSharp supports it, but I think you are talking about this part of AOP:
Inter-type declarations provide a way
to express crosscutting concerns
affecting the structure of modules.
Also known as open classes, this
enables programmers to declare in one
place members or parents of another
class, typically in order to combine
all the code related to a concern in
one aspect.
Could you get this sort of behavior by using the new ExpandoObject in .NET 4.0?
Scala traits were developed to address this kind of scenario. There's also some research to include traits in C#.
UPDATE: I created my own experiment to have roles in C#. Take a look.
I will use extension methods to implement the behaviour as the code shows.
Let Bird and Plane objects implement a property for IFlyBehavior object for an interface IFlyer
public interface IFlyer
{
public IFlyBehavior FlyBehavior
}
public Bird : IFlyer
{
public IFlyBehaviour FlyBehavior {get;set;}
}
public Airplane : IFlyer
{
public IFlyBehaviour FlyBehavior {get;set;}
}
Create an extension class for IFlyer
public IFlyerExtensions
{
public void OnReadyToFly(this IFlyer flyer)
{
flyer.FlyBehavior.Fly();
}
public void OnReadyToLand(this IFlyer flyer)
{
flyer.FlyBehavior.Land();
}
}