Why inherit a class and not add properties?












36














I found an inheritance tree in our (rather large) code base that goes something like this:



public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class OrderDateInfo : NamedEntity { }


From what I could gather, this is primarily used to bind stuff on front-end.



For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



Are there any downsides to this approach?










share|improve this question


















  • 24




    Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
    – Caleth
    Dec 12 '18 at 11:42






  • 8




    For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
    – Neil
    Dec 12 '18 at 15:10
















36














I found an inheritance tree in our (rather large) code base that goes something like this:



public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class OrderDateInfo : NamedEntity { }


From what I could gather, this is primarily used to bind stuff on front-end.



For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



Are there any downsides to this approach?










share|improve this question


















  • 24




    Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
    – Caleth
    Dec 12 '18 at 11:42






  • 8




    For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
    – Neil
    Dec 12 '18 at 15:10














36












36








36


9





I found an inheritance tree in our (rather large) code base that goes something like this:



public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class OrderDateInfo : NamedEntity { }


From what I could gather, this is primarily used to bind stuff on front-end.



For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



Are there any downsides to this approach?










share|improve this question













I found an inheritance tree in our (rather large) code base that goes something like this:



public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class OrderDateInfo : NamedEntity { }


From what I could gather, this is primarily used to bind stuff on front-end.



For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



Are there any downsides to this approach?







object-oriented-design inheritance






share|improve this question













share|improve this question











share|improve this question




share|improve this question










asked Dec 12 '18 at 11:39









robotron

35538




35538








  • 24




    Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
    – Caleth
    Dec 12 '18 at 11:42






  • 8




    For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
    – Neil
    Dec 12 '18 at 15:10














  • 24




    Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
    – Caleth
    Dec 12 '18 at 11:42






  • 8




    For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
    – Neil
    Dec 12 '18 at 15:10








24




24




Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
– Caleth
Dec 12 '18 at 11:42




Upside not mentioned: You can distinguish methods that are only relevant to OrderDateInfos from those that are relevant to other NamedEntitys
– Caleth
Dec 12 '18 at 11:42




8




8




For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
– Neil
Dec 12 '18 at 15:10




For the same reason that if you happened to have, say, an Identifier class having nothing to do with NamedEntity but requiring both an Id and Name property, you wouldn't use NamedEntity instead. The context and proper usage of a class is more than just the properties and methods which it holds.
– Neil
Dec 12 '18 at 15:10










5 Answers
5






active

oldest

votes


















12















For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



Are there any downsides to this approach?




The approach isn't bad, but there are better solutions available. In short, an interface would be a much better solution for this. The main reason why interfaces and inheritance are different here is because you can only inherit from one class, but you can implement many interfaces.



For example, consider that you have named entities, and audited entities. You have several entities:



One is not an audited entity nor a named entity. That's simple:



public class One 
{ }


Two is a named entity but not an audited entity. That's essentially what you have now:



public class NamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class Two : NamedEntity
{ }


Three is both a named and audited entry. This is where you run into a problem. You can create an AuditedEntity base class, but you can't make Three inherit both AuditedEntity and NamedEntity:



public class AuditedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}

public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
{ }


However, you might think of a workaround by having AuditedEntity inherit from NamedEntity. This is a clever hack to ensure that every class only needs to inherit (directly) from one other class.



public class AuditedEntity : NamedEntity
{
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
}

public class Three : AuditedEntity
{ }


This still works. But what you've done here is stated that every audited entity is inherently also a named entity. Which brings me to my last example. Four is an audited entity but not a named entity. But you can't let Four inherit from AuditedEntity as you would then also be making it a NamedEntity due to the inheritance between AuditedEntityandNamedEntity`.



Using inheritance, there is no way to make both Three and Four work unless you start duplicating classes (which opens up a whole new set of problems).



Using interfaces, this can easily be achieved:



public interface INamedEntity
{
int Id { get; set; }
string Name { get; set; }
}

public interface IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}

public class One
{ }

public class Two : INamedEntity
{
public int Id { get; set; }
public string Name { get; set; }
}

public class Three : INamedEntity, IAuditedEntity
{
public int Id { get; set; }
public string Name { get; set; }
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}

public class Four : IAuditedEntity
{
DateTime CreatedOn { get; set; }
DateTime UpdatedOn { get; set; }
}


The only minor drawback here is that you still have to implement the interface. But you get all the benefits from having a common reusable type, without any of the drawbacks that emerge when you need variations on multiple common types for a given entity.



But your polymorphism remains intact:



var one = new One();
var two = new Two();
var three = new Three();
var four = new Four();

public void HandleNamedEntity(INamedEntity namedEntity) {}
public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

HandleNamedEntity(one); //Error - not a named entity
HandleNamedEntity(two);
HandleNamedEntity(three);
HandleNamedEntity(four); //Error - not a named entity

HandleAuditedEntity(one); //Error - not an audited entity
HandleAuditedEntity(two); //Error - not an audited entity
HandleAuditedEntity(three);
HandleAuditedEntity(four);





On the other hand, there is a number of such classes that simply have no additional properties.




This is a variation on the marker interface pattern, where you implement an empty interface purely to be able to use the interface type to check if a given class is "marked" with this interface.

You're using inherited classes instead of implemented interfaces, but the goal is the same, so I'm going to refer to it as a "marked class".



At face value, there's nothing wrong with marker interfaces/classes. They are syntactically and technically valid, and there are no inherent drawbacks to using them provided that the marker is universally true (at compile time) and not conditional.



This is exactly how you should differentiate between different exceptions, even when those exceptions do not actually have any additional properties/methods compared to the base method.



So there's nothing inherently wrong with doing so, but I would advise using this cautiously, making sure that you're not just trying to cover up an existing architectural mistake with badly designed polymorphism.






share|improve this answer



















  • 4




    "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
    – Kenneth K.
    Dec 13 '18 at 15:50










  • like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
    – opa
    Dec 14 '18 at 23:10





















62














This is something that I use to prevent polymorphism from being used.



Say you have 15 different classes that have NamedEntity as a base class somewhere in their inheritance chain and you are writing a new method that is only applicable to OrderDateInfo.



You "could" just write the signature as



void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)



And hope and pray no one abuses the type system to shove a FooBazNamedEntity in there.



Or you "could" just write void MyMethod(OrderDateInfo foo). Now that is enforced by the compiler. Simple, elegant and doesn't rely on people not making mistakes.



Also, as @candied_orange pointed out, exceptions are a great case of this. Very rarely (and I mean very, very, very rarely) do you ever want to catch everything with catch (Exception e). More likely you want to catch a SqlException or a FileNotFoundException or a custom exception for your application. Those classes often times don't provide any more data or functionality than the base Exception class, but they allow you to differentiate what they represent without having to inspect them and check a type field or search for specific text.



Overall, it's a trick to get the type system to allow you to use a narrower set of types than you could if you used a base class. I mean, you could define all your variables and arguments as having the type Object, but that would just make your job harder, wouldn't it?






share|improve this answer



















  • 4




    Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
    – Adam B
    Dec 12 '18 at 17:33






  • 9




    @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
    – Becuzz
    Dec 12 '18 at 17:42






  • 17




    @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
    – Logarr
    Dec 12 '18 at 17:44






  • 8




    @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
    – candied_orange
    Dec 12 '18 at 21:00






  • 5




    @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
    – Sebastian Redl
    Dec 13 '18 at 7:45



















27














This is my favorite use of inheritance. I use it mostly for exceptions that could use better, more specific, names



The usual issue of inheritance leading to long chains and causing the yo-yo problem doesn't apply here since there is nothing to motivate you to chain.






share|improve this answer



















  • 1




    Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
    – David Arno
    Dec 12 '18 at 14:25










  • Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
    – radarbob
    Dec 13 '18 at 8:08










  • I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
    – Logan Pickup
    Dec 17 '18 at 2:34



















1














IMHO the class design is wrong. It should be.



public class EntityName
{
public int Id { get; set; }
public string Text { get; set; }
}

public class OrderDateInfo
{
public EntityName Name { get; set; }
}


OrderDateInfo HAS A Name is a more natural relation and creates two easy to understand classes that wouldn't have provoked the original question.



Any method that accepted NamedEntity as a parameter should only have been interested in the Id and Name properties, so any such methods should be changed to accept EntityName instead.



The only technical reason I'd accept for the original design is for property binding, which the OP mentioned. A crap framework wouldn't be able to cope with the extra property and bind to object.Name.Id. But if your binding framework can't cope with that then you have some more tech debt to add to the list.



I'd go along with @Flater's answer, but with lots of interfaces containing properties you end up writing a lot of boilerplate code, even with C#'s lovely automatic properties. Imagine doing it in Java!






share|improve this answer





























    1














    Classes expose behavior, and Data Structures expose data.



    I see the class keywords, but I don't see any behavior. This means that I would start viewing this class as a data structure. In this vein, I'm going rephrase your question as




    Why have a common top level data structure?




    So you can use the top level data type. This permits leveraging the type system to ensure a policy across large sets of different data structures by ensuring the properties are all there.




    Why have a data structure that includes the top level one, but adds nothing?




    So you can use the lower level data type. This permits putting hints into the typing system to express the variable's purpose



    Top level data structure - Named
    property: name;

    Bottom level data structure - Person


    In the hierarchy above, we find it convenient to specify that a Person is named, so people can obtain and alter their name. While it might be reasonable to add extra properties to the Person data structure the problem that we are solving doesn't require a perfect modeling of the Person, and so we neglected to add common properties like age, etc.



    So it's a leveraging of the typing system to express the intent of this Named item in a way that doesn't break with updates (like documentation) and can be extended at a latter date with ease (if you find you truly need the age field later).






    share|improve this answer




















      protected by gnat Dec 13 '18 at 16:09



      Thank you for your interest in this question.
      Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



      Would you like to answer one of these unanswered questions instead?














      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      12















      For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



      Are there any downsides to this approach?




      The approach isn't bad, but there are better solutions available. In short, an interface would be a much better solution for this. The main reason why interfaces and inheritance are different here is because you can only inherit from one class, but you can implement many interfaces.



      For example, consider that you have named entities, and audited entities. You have several entities:



      One is not an audited entity nor a named entity. That's simple:



      public class One 
      { }


      Two is a named entity but not an audited entity. That's essentially what you have now:



      public class NamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Two : NamedEntity
      { }


      Three is both a named and audited entry. This is where you run into a problem. You can create an AuditedEntity base class, but you can't make Three inherit both AuditedEntity and NamedEntity:



      public class AuditedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
      { }


      However, you might think of a workaround by having AuditedEntity inherit from NamedEntity. This is a clever hack to ensure that every class only needs to inherit (directly) from one other class.



      public class AuditedEntity : NamedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : AuditedEntity
      { }


      This still works. But what you've done here is stated that every audited entity is inherently also a named entity. Which brings me to my last example. Four is an audited entity but not a named entity. But you can't let Four inherit from AuditedEntity as you would then also be making it a NamedEntity due to the inheritance between AuditedEntityandNamedEntity`.



      Using inheritance, there is no way to make both Three and Four work unless you start duplicating classes (which opens up a whole new set of problems).



      Using interfaces, this can easily be achieved:



      public interface INamedEntity
      {
      int Id { get; set; }
      string Name { get; set; }
      }

      public interface IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class One
      { }

      public class Two : INamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Three : INamedEntity, IAuditedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class Four : IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }


      The only minor drawback here is that you still have to implement the interface. But you get all the benefits from having a common reusable type, without any of the drawbacks that emerge when you need variations on multiple common types for a given entity.



      But your polymorphism remains intact:



      var one = new One();
      var two = new Two();
      var three = new Three();
      var four = new Four();

      public void HandleNamedEntity(INamedEntity namedEntity) {}
      public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

      HandleNamedEntity(one); //Error - not a named entity
      HandleNamedEntity(two);
      HandleNamedEntity(three);
      HandleNamedEntity(four); //Error - not a named entity

      HandleAuditedEntity(one); //Error - not an audited entity
      HandleAuditedEntity(two); //Error - not an audited entity
      HandleAuditedEntity(three);
      HandleAuditedEntity(four);





      On the other hand, there is a number of such classes that simply have no additional properties.




      This is a variation on the marker interface pattern, where you implement an empty interface purely to be able to use the interface type to check if a given class is "marked" with this interface.

      You're using inherited classes instead of implemented interfaces, but the goal is the same, so I'm going to refer to it as a "marked class".



      At face value, there's nothing wrong with marker interfaces/classes. They are syntactically and technically valid, and there are no inherent drawbacks to using them provided that the marker is universally true (at compile time) and not conditional.



      This is exactly how you should differentiate between different exceptions, even when those exceptions do not actually have any additional properties/methods compared to the base method.



      So there's nothing inherently wrong with doing so, but I would advise using this cautiously, making sure that you're not just trying to cover up an existing architectural mistake with badly designed polymorphism.






      share|improve this answer



















      • 4




        "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
        – Kenneth K.
        Dec 13 '18 at 15:50










      • like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
        – opa
        Dec 14 '18 at 23:10


















      12















      For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



      Are there any downsides to this approach?




      The approach isn't bad, but there are better solutions available. In short, an interface would be a much better solution for this. The main reason why interfaces and inheritance are different here is because you can only inherit from one class, but you can implement many interfaces.



      For example, consider that you have named entities, and audited entities. You have several entities:



      One is not an audited entity nor a named entity. That's simple:



      public class One 
      { }


      Two is a named entity but not an audited entity. That's essentially what you have now:



      public class NamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Two : NamedEntity
      { }


      Three is both a named and audited entry. This is where you run into a problem. You can create an AuditedEntity base class, but you can't make Three inherit both AuditedEntity and NamedEntity:



      public class AuditedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
      { }


      However, you might think of a workaround by having AuditedEntity inherit from NamedEntity. This is a clever hack to ensure that every class only needs to inherit (directly) from one other class.



      public class AuditedEntity : NamedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : AuditedEntity
      { }


      This still works. But what you've done here is stated that every audited entity is inherently also a named entity. Which brings me to my last example. Four is an audited entity but not a named entity. But you can't let Four inherit from AuditedEntity as you would then also be making it a NamedEntity due to the inheritance between AuditedEntityandNamedEntity`.



      Using inheritance, there is no way to make both Three and Four work unless you start duplicating classes (which opens up a whole new set of problems).



      Using interfaces, this can easily be achieved:



      public interface INamedEntity
      {
      int Id { get; set; }
      string Name { get; set; }
      }

      public interface IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class One
      { }

      public class Two : INamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Three : INamedEntity, IAuditedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class Four : IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }


      The only minor drawback here is that you still have to implement the interface. But you get all the benefits from having a common reusable type, without any of the drawbacks that emerge when you need variations on multiple common types for a given entity.



      But your polymorphism remains intact:



      var one = new One();
      var two = new Two();
      var three = new Three();
      var four = new Four();

      public void HandleNamedEntity(INamedEntity namedEntity) {}
      public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

      HandleNamedEntity(one); //Error - not a named entity
      HandleNamedEntity(two);
      HandleNamedEntity(three);
      HandleNamedEntity(four); //Error - not a named entity

      HandleAuditedEntity(one); //Error - not an audited entity
      HandleAuditedEntity(two); //Error - not an audited entity
      HandleAuditedEntity(three);
      HandleAuditedEntity(four);





      On the other hand, there is a number of such classes that simply have no additional properties.




      This is a variation on the marker interface pattern, where you implement an empty interface purely to be able to use the interface type to check if a given class is "marked" with this interface.

      You're using inherited classes instead of implemented interfaces, but the goal is the same, so I'm going to refer to it as a "marked class".



      At face value, there's nothing wrong with marker interfaces/classes. They are syntactically and technically valid, and there are no inherent drawbacks to using them provided that the marker is universally true (at compile time) and not conditional.



      This is exactly how you should differentiate between different exceptions, even when those exceptions do not actually have any additional properties/methods compared to the base method.



      So there's nothing inherently wrong with doing so, but I would advise using this cautiously, making sure that you're not just trying to cover up an existing architectural mistake with badly designed polymorphism.






      share|improve this answer



















      • 4




        "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
        – Kenneth K.
        Dec 13 '18 at 15:50










      • like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
        – opa
        Dec 14 '18 at 23:10
















      12












      12








      12







      For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



      Are there any downsides to this approach?




      The approach isn't bad, but there are better solutions available. In short, an interface would be a much better solution for this. The main reason why interfaces and inheritance are different here is because you can only inherit from one class, but you can implement many interfaces.



      For example, consider that you have named entities, and audited entities. You have several entities:



      One is not an audited entity nor a named entity. That's simple:



      public class One 
      { }


      Two is a named entity but not an audited entity. That's essentially what you have now:



      public class NamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Two : NamedEntity
      { }


      Three is both a named and audited entry. This is where you run into a problem. You can create an AuditedEntity base class, but you can't make Three inherit both AuditedEntity and NamedEntity:



      public class AuditedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
      { }


      However, you might think of a workaround by having AuditedEntity inherit from NamedEntity. This is a clever hack to ensure that every class only needs to inherit (directly) from one other class.



      public class AuditedEntity : NamedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : AuditedEntity
      { }


      This still works. But what you've done here is stated that every audited entity is inherently also a named entity. Which brings me to my last example. Four is an audited entity but not a named entity. But you can't let Four inherit from AuditedEntity as you would then also be making it a NamedEntity due to the inheritance between AuditedEntityandNamedEntity`.



      Using inheritance, there is no way to make both Three and Four work unless you start duplicating classes (which opens up a whole new set of problems).



      Using interfaces, this can easily be achieved:



      public interface INamedEntity
      {
      int Id { get; set; }
      string Name { get; set; }
      }

      public interface IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class One
      { }

      public class Two : INamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Three : INamedEntity, IAuditedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class Four : IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }


      The only minor drawback here is that you still have to implement the interface. But you get all the benefits from having a common reusable type, without any of the drawbacks that emerge when you need variations on multiple common types for a given entity.



      But your polymorphism remains intact:



      var one = new One();
      var two = new Two();
      var three = new Three();
      var four = new Four();

      public void HandleNamedEntity(INamedEntity namedEntity) {}
      public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

      HandleNamedEntity(one); //Error - not a named entity
      HandleNamedEntity(two);
      HandleNamedEntity(three);
      HandleNamedEntity(four); //Error - not a named entity

      HandleAuditedEntity(one); //Error - not an audited entity
      HandleAuditedEntity(two); //Error - not an audited entity
      HandleAuditedEntity(three);
      HandleAuditedEntity(four);





      On the other hand, there is a number of such classes that simply have no additional properties.




      This is a variation on the marker interface pattern, where you implement an empty interface purely to be able to use the interface type to check if a given class is "marked" with this interface.

      You're using inherited classes instead of implemented interfaces, but the goal is the same, so I'm going to refer to it as a "marked class".



      At face value, there's nothing wrong with marker interfaces/classes. They are syntactically and technically valid, and there are no inherent drawbacks to using them provided that the marker is universally true (at compile time) and not conditional.



      This is exactly how you should differentiate between different exceptions, even when those exceptions do not actually have any additional properties/methods compared to the base method.



      So there's nothing inherently wrong with doing so, but I would advise using this cautiously, making sure that you're not just trying to cover up an existing architectural mistake with badly designed polymorphism.






      share|improve this answer















      For me, this makes sense as it gives a concrete name to the class, instead of relying on the generic NamedEntity. On the other hand, there is a number of such classes that simply have no additional properties.



      Are there any downsides to this approach?




      The approach isn't bad, but there are better solutions available. In short, an interface would be a much better solution for this. The main reason why interfaces and inheritance are different here is because you can only inherit from one class, but you can implement many interfaces.



      For example, consider that you have named entities, and audited entities. You have several entities:



      One is not an audited entity nor a named entity. That's simple:



      public class One 
      { }


      Two is a named entity but not an audited entity. That's essentially what you have now:



      public class NamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Two : NamedEntity
      { }


      Three is both a named and audited entry. This is where you run into a problem. You can create an AuditedEntity base class, but you can't make Three inherit both AuditedEntity and NamedEntity:



      public class AuditedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : NamedEntity, AuditedEntity // <-- Compiler error!
      { }


      However, you might think of a workaround by having AuditedEntity inherit from NamedEntity. This is a clever hack to ensure that every class only needs to inherit (directly) from one other class.



      public class AuditedEntity : NamedEntity
      {
      public DateTime CreatedOn { get; set; }
      public DateTime UpdatedOn { get; set; }
      }

      public class Three : AuditedEntity
      { }


      This still works. But what you've done here is stated that every audited entity is inherently also a named entity. Which brings me to my last example. Four is an audited entity but not a named entity. But you can't let Four inherit from AuditedEntity as you would then also be making it a NamedEntity due to the inheritance between AuditedEntityandNamedEntity`.



      Using inheritance, there is no way to make both Three and Four work unless you start duplicating classes (which opens up a whole new set of problems).



      Using interfaces, this can easily be achieved:



      public interface INamedEntity
      {
      int Id { get; set; }
      string Name { get; set; }
      }

      public interface IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class One
      { }

      public class Two : INamedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      }

      public class Three : INamedEntity, IAuditedEntity
      {
      public int Id { get; set; }
      public string Name { get; set; }
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }

      public class Four : IAuditedEntity
      {
      DateTime CreatedOn { get; set; }
      DateTime UpdatedOn { get; set; }
      }


      The only minor drawback here is that you still have to implement the interface. But you get all the benefits from having a common reusable type, without any of the drawbacks that emerge when you need variations on multiple common types for a given entity.



      But your polymorphism remains intact:



      var one = new One();
      var two = new Two();
      var three = new Three();
      var four = new Four();

      public void HandleNamedEntity(INamedEntity namedEntity) {}
      public void HandleAuditedEntity(IAuditedEntity auditedEntity) {}

      HandleNamedEntity(one); //Error - not a named entity
      HandleNamedEntity(two);
      HandleNamedEntity(three);
      HandleNamedEntity(four); //Error - not a named entity

      HandleAuditedEntity(one); //Error - not an audited entity
      HandleAuditedEntity(two); //Error - not an audited entity
      HandleAuditedEntity(three);
      HandleAuditedEntity(four);





      On the other hand, there is a number of such classes that simply have no additional properties.




      This is a variation on the marker interface pattern, where you implement an empty interface purely to be able to use the interface type to check if a given class is "marked" with this interface.

      You're using inherited classes instead of implemented interfaces, but the goal is the same, so I'm going to refer to it as a "marked class".



      At face value, there's nothing wrong with marker interfaces/classes. They are syntactically and technically valid, and there are no inherent drawbacks to using them provided that the marker is universally true (at compile time) and not conditional.



      This is exactly how you should differentiate between different exceptions, even when those exceptions do not actually have any additional properties/methods compared to the base method.



      So there's nothing inherently wrong with doing so, but I would advise using this cautiously, making sure that you're not just trying to cover up an existing architectural mistake with badly designed polymorphism.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 13 '18 at 11:25









      Community

      1




      1










      answered Dec 13 '18 at 7:14









      Flater

      6,74521221




      6,74521221








      • 4




        "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
        – Kenneth K.
        Dec 13 '18 at 15:50










      • like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
        – opa
        Dec 14 '18 at 23:10
















      • 4




        "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
        – Kenneth K.
        Dec 13 '18 at 15:50










      • like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
        – opa
        Dec 14 '18 at 23:10










      4




      4




      "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
      – Kenneth K.
      Dec 13 '18 at 15:50




      "you can only inherit from one class, but you can implement many interfaces." That's not true of every language, though. Some languages do allow multiple class inheritance.
      – Kenneth K.
      Dec 13 '18 at 15:50












      like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
      – opa
      Dec 14 '18 at 23:10






      like Kenneth said, two pretty popular languages have the ability for multiple inheritance, C++ and Python. class three in your example of the pitfalls of not using interfaces is actually valid in C++ for example, in fact this works properly for all four examples. In fact this all seems to be a limitation of C# as a language rather than a cautionary tale of not using inheritance when you should be using interfaces.
      – opa
      Dec 14 '18 at 23:10















      62














      This is something that I use to prevent polymorphism from being used.



      Say you have 15 different classes that have NamedEntity as a base class somewhere in their inheritance chain and you are writing a new method that is only applicable to OrderDateInfo.



      You "could" just write the signature as



      void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)



      And hope and pray no one abuses the type system to shove a FooBazNamedEntity in there.



      Or you "could" just write void MyMethod(OrderDateInfo foo). Now that is enforced by the compiler. Simple, elegant and doesn't rely on people not making mistakes.



      Also, as @candied_orange pointed out, exceptions are a great case of this. Very rarely (and I mean very, very, very rarely) do you ever want to catch everything with catch (Exception e). More likely you want to catch a SqlException or a FileNotFoundException or a custom exception for your application. Those classes often times don't provide any more data or functionality than the base Exception class, but they allow you to differentiate what they represent without having to inspect them and check a type field or search for specific text.



      Overall, it's a trick to get the type system to allow you to use a narrower set of types than you could if you used a base class. I mean, you could define all your variables and arguments as having the type Object, but that would just make your job harder, wouldn't it?






      share|improve this answer



















      • 4




        Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
        – Adam B
        Dec 12 '18 at 17:33






      • 9




        @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
        – Becuzz
        Dec 12 '18 at 17:42






      • 17




        @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
        – Logarr
        Dec 12 '18 at 17:44






      • 8




        @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
        – candied_orange
        Dec 12 '18 at 21:00






      • 5




        @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
        – Sebastian Redl
        Dec 13 '18 at 7:45
















      62














      This is something that I use to prevent polymorphism from being used.



      Say you have 15 different classes that have NamedEntity as a base class somewhere in their inheritance chain and you are writing a new method that is only applicable to OrderDateInfo.



      You "could" just write the signature as



      void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)



      And hope and pray no one abuses the type system to shove a FooBazNamedEntity in there.



      Or you "could" just write void MyMethod(OrderDateInfo foo). Now that is enforced by the compiler. Simple, elegant and doesn't rely on people not making mistakes.



      Also, as @candied_orange pointed out, exceptions are a great case of this. Very rarely (and I mean very, very, very rarely) do you ever want to catch everything with catch (Exception e). More likely you want to catch a SqlException or a FileNotFoundException or a custom exception for your application. Those classes often times don't provide any more data or functionality than the base Exception class, but they allow you to differentiate what they represent without having to inspect them and check a type field or search for specific text.



      Overall, it's a trick to get the type system to allow you to use a narrower set of types than you could if you used a base class. I mean, you could define all your variables and arguments as having the type Object, but that would just make your job harder, wouldn't it?






      share|improve this answer



















      • 4




        Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
        – Adam B
        Dec 12 '18 at 17:33






      • 9




        @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
        – Becuzz
        Dec 12 '18 at 17:42






      • 17




        @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
        – Logarr
        Dec 12 '18 at 17:44






      • 8




        @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
        – candied_orange
        Dec 12 '18 at 21:00






      • 5




        @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
        – Sebastian Redl
        Dec 13 '18 at 7:45














      62












      62








      62






      This is something that I use to prevent polymorphism from being used.



      Say you have 15 different classes that have NamedEntity as a base class somewhere in their inheritance chain and you are writing a new method that is only applicable to OrderDateInfo.



      You "could" just write the signature as



      void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)



      And hope and pray no one abuses the type system to shove a FooBazNamedEntity in there.



      Or you "could" just write void MyMethod(OrderDateInfo foo). Now that is enforced by the compiler. Simple, elegant and doesn't rely on people not making mistakes.



      Also, as @candied_orange pointed out, exceptions are a great case of this. Very rarely (and I mean very, very, very rarely) do you ever want to catch everything with catch (Exception e). More likely you want to catch a SqlException or a FileNotFoundException or a custom exception for your application. Those classes often times don't provide any more data or functionality than the base Exception class, but they allow you to differentiate what they represent without having to inspect them and check a type field or search for specific text.



      Overall, it's a trick to get the type system to allow you to use a narrower set of types than you could if you used a base class. I mean, you could define all your variables and arguments as having the type Object, but that would just make your job harder, wouldn't it?






      share|improve this answer














      This is something that I use to prevent polymorphism from being used.



      Say you have 15 different classes that have NamedEntity as a base class somewhere in their inheritance chain and you are writing a new method that is only applicable to OrderDateInfo.



      You "could" just write the signature as



      void MyMethodThatShouldOnlyTakeOrderDateInfos(NamedEntity foo)



      And hope and pray no one abuses the type system to shove a FooBazNamedEntity in there.



      Or you "could" just write void MyMethod(OrderDateInfo foo). Now that is enforced by the compiler. Simple, elegant and doesn't rely on people not making mistakes.



      Also, as @candied_orange pointed out, exceptions are a great case of this. Very rarely (and I mean very, very, very rarely) do you ever want to catch everything with catch (Exception e). More likely you want to catch a SqlException or a FileNotFoundException or a custom exception for your application. Those classes often times don't provide any more data or functionality than the base Exception class, but they allow you to differentiate what they represent without having to inspect them and check a type field or search for specific text.



      Overall, it's a trick to get the type system to allow you to use a narrower set of types than you could if you used a base class. I mean, you could define all your variables and arguments as having the type Object, but that would just make your job harder, wouldn't it?







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 13 '18 at 7:38









      Laiv

      6,58311140




      6,58311140










      answered Dec 12 '18 at 12:53









      Becuzz

      3,88111422




      3,88111422








      • 4




        Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
        – Adam B
        Dec 12 '18 at 17:33






      • 9




        @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
        – Becuzz
        Dec 12 '18 at 17:42






      • 17




        @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
        – Logarr
        Dec 12 '18 at 17:44






      • 8




        @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
        – candied_orange
        Dec 12 '18 at 21:00






      • 5




        @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
        – Sebastian Redl
        Dec 13 '18 at 7:45














      • 4




        Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
        – Adam B
        Dec 12 '18 at 17:33






      • 9




        @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
        – Becuzz
        Dec 12 '18 at 17:42






      • 17




        @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
        – Logarr
        Dec 12 '18 at 17:44






      • 8




        @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
        – candied_orange
        Dec 12 '18 at 21:00






      • 5




        @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
        – Sebastian Redl
        Dec 13 '18 at 7:45








      4




      4




      Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
      – Adam B
      Dec 12 '18 at 17:33




      Pardon my newness but I’m curious why it wouldn’t be a better approach to make OrderDateInfo HAVE a NamedEntity object as a property?
      – Adam B
      Dec 12 '18 at 17:33




      9




      9




      @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
      – Becuzz
      Dec 12 '18 at 17:42




      @AdamB That's a valid design choice. Whether it is better or not depends on what it will be used for among other things. In the exception case, I can't create a new class with an exception property because then the language (C# for me) won't let me throw it. There might be other design considerations that would preclude using composition rather than inheritance. Many times composition is better. It just depends on your system.
      – Becuzz
      Dec 12 '18 at 17:42




      17




      17




      @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
      – Logarr
      Dec 12 '18 at 17:44




      @AdamB For the same reason that when you inherit from a base class and DO add methods or properties the base lacks, you don't make a new class and put the base one as a property. There's a difference between a Human BEING a mammal, and HAVING a mammal.
      – Logarr
      Dec 12 '18 at 17:44




      8




      8




      @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
      – candied_orange
      Dec 12 '18 at 21:00




      @Logarr true there is a difference between me being a mammal and having a mammal. But if I stay true to my inner mammal you'll never know the difference. You might wonder why I can give so many different kinds of milk on a whim.
      – candied_orange
      Dec 12 '18 at 21:00




      5




      5




      @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
      – Sebastian Redl
      Dec 13 '18 at 7:45




      @AdamB You can do that, and this is known as composition-over-inheritance. But you would rename NamedEntity for this, e.g. to EntityName, so that the composition makes sense when described.
      – Sebastian Redl
      Dec 13 '18 at 7:45











      27














      This is my favorite use of inheritance. I use it mostly for exceptions that could use better, more specific, names



      The usual issue of inheritance leading to long chains and causing the yo-yo problem doesn't apply here since there is nothing to motivate you to chain.






      share|improve this answer



















      • 1




        Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
        – David Arno
        Dec 12 '18 at 14:25










      • Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
        – radarbob
        Dec 13 '18 at 8:08










      • I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
        – Logan Pickup
        Dec 17 '18 at 2:34
















      27














      This is my favorite use of inheritance. I use it mostly for exceptions that could use better, more specific, names



      The usual issue of inheritance leading to long chains and causing the yo-yo problem doesn't apply here since there is nothing to motivate you to chain.






      share|improve this answer



















      • 1




        Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
        – David Arno
        Dec 12 '18 at 14:25










      • Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
        – radarbob
        Dec 13 '18 at 8:08










      • I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
        – Logan Pickup
        Dec 17 '18 at 2:34














      27












      27








      27






      This is my favorite use of inheritance. I use it mostly for exceptions that could use better, more specific, names



      The usual issue of inheritance leading to long chains and causing the yo-yo problem doesn't apply here since there is nothing to motivate you to chain.






      share|improve this answer














      This is my favorite use of inheritance. I use it mostly for exceptions that could use better, more specific, names



      The usual issue of inheritance leading to long chains and causing the yo-yo problem doesn't apply here since there is nothing to motivate you to chain.







      share|improve this answer














      share|improve this answer



      share|improve this answer








      edited Dec 13 '18 at 5:23









      Kevin

      6751415




      6751415










      answered Dec 12 '18 at 12:34









      candied_orange

      52.4k1697185




      52.4k1697185








      • 1




        Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
        – David Arno
        Dec 12 '18 at 14:25










      • Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
        – radarbob
        Dec 13 '18 at 8:08










      • I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
        – Logan Pickup
        Dec 17 '18 at 2:34














      • 1




        Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
        – David Arno
        Dec 12 '18 at 14:25










      • Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
        – radarbob
        Dec 13 '18 at 8:08










      • I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
        – Logan Pickup
        Dec 17 '18 at 2:34








      1




      1




      Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
      – David Arno
      Dec 12 '18 at 14:25




      Hmm, good point re exceptions. I was going to say it was a horrible thing to do. But you have persuaded me otherwise with an excellent use case.
      – David Arno
      Dec 12 '18 at 14:25












      Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
      – radarbob
      Dec 13 '18 at 8:08




      Yo-Yo Ho and a bottle of rum. Tis rare the orlop is yar. It oft leaks for want of proper oakum 'tween the planks. To Davey Jones locker with the land lubbers what built it. TRANSLATION: It is rare a inheritance chain is so good that the base class can abstractly/effectively be ignored.
      – radarbob
      Dec 13 '18 at 8:08












      I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
      – Logan Pickup
      Dec 17 '18 at 2:34




      I think it's worth pointing out that a new class inheriting from another does add a new property - the name of the new class. This is exactly what you use when creating exceptions with better names.
      – Logan Pickup
      Dec 17 '18 at 2:34











      1














      IMHO the class design is wrong. It should be.



      public class EntityName
      {
      public int Id { get; set; }
      public string Text { get; set; }
      }

      public class OrderDateInfo
      {
      public EntityName Name { get; set; }
      }


      OrderDateInfo HAS A Name is a more natural relation and creates two easy to understand classes that wouldn't have provoked the original question.



      Any method that accepted NamedEntity as a parameter should only have been interested in the Id and Name properties, so any such methods should be changed to accept EntityName instead.



      The only technical reason I'd accept for the original design is for property binding, which the OP mentioned. A crap framework wouldn't be able to cope with the extra property and bind to object.Name.Id. But if your binding framework can't cope with that then you have some more tech debt to add to the list.



      I'd go along with @Flater's answer, but with lots of interfaces containing properties you end up writing a lot of boilerplate code, even with C#'s lovely automatic properties. Imagine doing it in Java!






      share|improve this answer


























        1














        IMHO the class design is wrong. It should be.



        public class EntityName
        {
        public int Id { get; set; }
        public string Text { get; set; }
        }

        public class OrderDateInfo
        {
        public EntityName Name { get; set; }
        }


        OrderDateInfo HAS A Name is a more natural relation and creates two easy to understand classes that wouldn't have provoked the original question.



        Any method that accepted NamedEntity as a parameter should only have been interested in the Id and Name properties, so any such methods should be changed to accept EntityName instead.



        The only technical reason I'd accept for the original design is for property binding, which the OP mentioned. A crap framework wouldn't be able to cope with the extra property and bind to object.Name.Id. But if your binding framework can't cope with that then you have some more tech debt to add to the list.



        I'd go along with @Flater's answer, but with lots of interfaces containing properties you end up writing a lot of boilerplate code, even with C#'s lovely automatic properties. Imagine doing it in Java!






        share|improve this answer
























          1












          1








          1






          IMHO the class design is wrong. It should be.



          public class EntityName
          {
          public int Id { get; set; }
          public string Text { get; set; }
          }

          public class OrderDateInfo
          {
          public EntityName Name { get; set; }
          }


          OrderDateInfo HAS A Name is a more natural relation and creates two easy to understand classes that wouldn't have provoked the original question.



          Any method that accepted NamedEntity as a parameter should only have been interested in the Id and Name properties, so any such methods should be changed to accept EntityName instead.



          The only technical reason I'd accept for the original design is for property binding, which the OP mentioned. A crap framework wouldn't be able to cope with the extra property and bind to object.Name.Id. But if your binding framework can't cope with that then you have some more tech debt to add to the list.



          I'd go along with @Flater's answer, but with lots of interfaces containing properties you end up writing a lot of boilerplate code, even with C#'s lovely automatic properties. Imagine doing it in Java!






          share|improve this answer












          IMHO the class design is wrong. It should be.



          public class EntityName
          {
          public int Id { get; set; }
          public string Text { get; set; }
          }

          public class OrderDateInfo
          {
          public EntityName Name { get; set; }
          }


          OrderDateInfo HAS A Name is a more natural relation and creates two easy to understand classes that wouldn't have provoked the original question.



          Any method that accepted NamedEntity as a parameter should only have been interested in the Id and Name properties, so any such methods should be changed to accept EntityName instead.



          The only technical reason I'd accept for the original design is for property binding, which the OP mentioned. A crap framework wouldn't be able to cope with the extra property and bind to object.Name.Id. But if your binding framework can't cope with that then you have some more tech debt to add to the list.



          I'd go along with @Flater's answer, but with lots of interfaces containing properties you end up writing a lot of boilerplate code, even with C#'s lovely automatic properties. Imagine doing it in Java!







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Dec 13 '18 at 15:06









          batwad

          1112




          1112























              1














              Classes expose behavior, and Data Structures expose data.



              I see the class keywords, but I don't see any behavior. This means that I would start viewing this class as a data structure. In this vein, I'm going rephrase your question as




              Why have a common top level data structure?




              So you can use the top level data type. This permits leveraging the type system to ensure a policy across large sets of different data structures by ensuring the properties are all there.




              Why have a data structure that includes the top level one, but adds nothing?




              So you can use the lower level data type. This permits putting hints into the typing system to express the variable's purpose



              Top level data structure - Named
              property: name;

              Bottom level data structure - Person


              In the hierarchy above, we find it convenient to specify that a Person is named, so people can obtain and alter their name. While it might be reasonable to add extra properties to the Person data structure the problem that we are solving doesn't require a perfect modeling of the Person, and so we neglected to add common properties like age, etc.



              So it's a leveraging of the typing system to express the intent of this Named item in a way that doesn't break with updates (like documentation) and can be extended at a latter date with ease (if you find you truly need the age field later).






              share|improve this answer


























                1














                Classes expose behavior, and Data Structures expose data.



                I see the class keywords, but I don't see any behavior. This means that I would start viewing this class as a data structure. In this vein, I'm going rephrase your question as




                Why have a common top level data structure?




                So you can use the top level data type. This permits leveraging the type system to ensure a policy across large sets of different data structures by ensuring the properties are all there.




                Why have a data structure that includes the top level one, but adds nothing?




                So you can use the lower level data type. This permits putting hints into the typing system to express the variable's purpose



                Top level data structure - Named
                property: name;

                Bottom level data structure - Person


                In the hierarchy above, we find it convenient to specify that a Person is named, so people can obtain and alter their name. While it might be reasonable to add extra properties to the Person data structure the problem that we are solving doesn't require a perfect modeling of the Person, and so we neglected to add common properties like age, etc.



                So it's a leveraging of the typing system to express the intent of this Named item in a way that doesn't break with updates (like documentation) and can be extended at a latter date with ease (if you find you truly need the age field later).






                share|improve this answer
























                  1












                  1








                  1






                  Classes expose behavior, and Data Structures expose data.



                  I see the class keywords, but I don't see any behavior. This means that I would start viewing this class as a data structure. In this vein, I'm going rephrase your question as




                  Why have a common top level data structure?




                  So you can use the top level data type. This permits leveraging the type system to ensure a policy across large sets of different data structures by ensuring the properties are all there.




                  Why have a data structure that includes the top level one, but adds nothing?




                  So you can use the lower level data type. This permits putting hints into the typing system to express the variable's purpose



                  Top level data structure - Named
                  property: name;

                  Bottom level data structure - Person


                  In the hierarchy above, we find it convenient to specify that a Person is named, so people can obtain and alter their name. While it might be reasonable to add extra properties to the Person data structure the problem that we are solving doesn't require a perfect modeling of the Person, and so we neglected to add common properties like age, etc.



                  So it's a leveraging of the typing system to express the intent of this Named item in a way that doesn't break with updates (like documentation) and can be extended at a latter date with ease (if you find you truly need the age field later).






                  share|improve this answer












                  Classes expose behavior, and Data Structures expose data.



                  I see the class keywords, but I don't see any behavior. This means that I would start viewing this class as a data structure. In this vein, I'm going rephrase your question as




                  Why have a common top level data structure?




                  So you can use the top level data type. This permits leveraging the type system to ensure a policy across large sets of different data structures by ensuring the properties are all there.




                  Why have a data structure that includes the top level one, but adds nothing?




                  So you can use the lower level data type. This permits putting hints into the typing system to express the variable's purpose



                  Top level data structure - Named
                  property: name;

                  Bottom level data structure - Person


                  In the hierarchy above, we find it convenient to specify that a Person is named, so people can obtain and alter their name. While it might be reasonable to add extra properties to the Person data structure the problem that we are solving doesn't require a perfect modeling of the Person, and so we neglected to add common properties like age, etc.



                  So it's a leveraging of the typing system to express the intent of this Named item in a way that doesn't break with updates (like documentation) and can be extended at a latter date with ease (if you find you truly need the age field later).







                  share|improve this answer












                  share|improve this answer



                  share|improve this answer










                  answered Dec 13 '18 at 16:34









                  Edwin Buck

                  45236




                  45236

















                      protected by gnat Dec 13 '18 at 16:09



                      Thank you for your interest in this question.
                      Because it has attracted low-quality or spam answers that had to be removed, posting an answer now requires 10 reputation on this site (the association bonus does not count).



                      Would you like to answer one of these unanswered questions instead?



                      Popular posts from this blog

                      How to change which sound is reproduced for terminal bell?

                      Can I use Tabulator js library in my java Spring + Thymeleaf project?

                      Title Spacing in Bjornstrup Chapter, Removing Chapter Number From Contents