Abstract Method in Non Abstract Class
Asked Answered
D

9

59

I want to know the reason behind the design of restricting Abstract Methods in Non Abstract Class (in C#).

I understand that the class instance won't have the definition and thus they wont be callable, but when static methods are defined,they are excluded from the instance too. Why abstract methods are not handled that way, any specific reason for the same?

They could be allowed in concrete class and the deriving class can be forced to implement methods, basically that is what, is done in case of abstract methods in an abstract class.

Dagda answered 25/9, 2012 at 10:29 Comment(8)
I hope I'm not the only one saying.. "Wut?"Agraffe
What is your use case where you want to define abstract method in a non-abstract class?Haemin
Please add an example of a class where such a concept would be useful.Bowser
Take any abstract class, say with one abstract method and many concrete methods. If I dont have restriction, cant this abstract class be removed and still the same goal is achieved?Dagda
If you have your heart set on this, perhaps you can consider making the method virtual instead and have it throw a NotImplementedException (or do nothing, or return a default value). Then document that inherited classes must implement the method. But in general, I agree with the others; this sounds like you're trying to use the wrong tool for the job.Evulsion
Do you think of something similar to a partial method where it's OK to call the method even if no "part" of the class (or struct) provides an implementation of that partial method? The compiler simply removes ("optimizes away") the call to the partial method in that case. Is that what you would want to happen if someone called the "abstract" version of the method, in your supposed scenario?Dioptometer
Partial is optional (partial class/method can have other parts defined or might not), I am not stressing on optional status for abstract methods, it should be mandatory for child classes.Dagda
A case I've just come accross is inheriting from UserControl to add a few known members to a control with several super classes. As this class on it's own is useless, I made it abstract but then the designer of the superclasses refused to use it as it couldn;t be created. I tried to make the methods abstract (so they have to be overridden) and it threw the compile error mentioned in the subject. I've settled with a virtual method and throwing NotImplementedException with a suitable message.Angelita
J
58

First, I think that what you're asking doesn't logically make sense. If you have an abstract method, it basically means that the method is unfinished (as @ChrisSinclair pointed out). But that also means the whole class is unfinished, so it also has to be abstract.

Or another way to put it: if you had an abstract method on a class that wasn't abstract, that would mean you had a method that cannot be called. But that means the method is not useful, you could remove it and it would all work the same.

Now, I'll try to be more concrete by using an example: imagine the following code:

Animal[] zoo = new Animal[] { new Monkey(), new Fish(), new Animal() };

foreach (Animal animal in zoo)
    animal.MakeSound();

Here, Animal is the non-abstract base class (which is why I can put it directly into the array), Monkey and Fish are derived from Animal and MakeSound() is the abstract method. What should this code do? You didn't state that clearly, but I can imagine few options:

  1. You can't call MakeSound() on a variable typed as Animal, you can call it only using a variable typed as one of the derived classes, so this is a compile error.

    This is not a good solution, because the whole point of abstract is to be able to treat instances of derived classes as the base class, and still get behaviour that's specific to the derived class. If you want this, just put a normal (no abstract, virtual or override) method into each derived class and don't do anything with the base class.

  2. You can't call MakeSound() on an object whose runtime type is actually Animal, so this is a runtime error (an exception).

    This is also not a good solution. C# is a statically typed language and so it tries to catch errors like “you can't call this method” at compile time (with obvious exceptions like reflection and dynamic), so making this into a runtime error wouldn't fit with the rest of the language. Besides, you can do this easily by creating a virtual method in the base class that throws an exception.

To sum up, you want something that doesn't make much sense, and smells of bad design (a base class that behaves differently than its derived classes) and can be worked around quite easily. These are all signs of a feature that should not be implemented.

Jehad answered 25/9, 2012 at 11:43 Comment(1)
Make sense to me and point 1 gives me the answer why there is abstract at "class level" and why abstract classes should be restricted making instances. Thanks vick.Dagda
T
15

So, you want to allow

class C { abstract void M(); }

to compile. Suppose it did. What do you then want to happen when someone does

new C().M();

? You want an execution-time error? Well, in general C# prefers compile-time errors to execution-time errors. If you don't like that philosophy, there are other languages available...

Tema answered 25/9, 2012 at 10:34 Comment(8)
I stated that issue and given example of static methods being handled by compiler. My question was on compiler design for abstract methods, basically why they chose abstract class specifically for these methods?Dagda
@AshishJain Because an abstract class cannot be directly instantiated. It is "unfinished", just like an interface cannot be directly instantiated because what the empty methods/properties do is undefined. It forces programmers who wish to use them to inherit and implement all abstract methods before being able to instantiate. EDIT: Static methods are a different concept. They belong to the Type and not the object instance. Abstract methods are on the instance level and require to be implemented (also note that static methods require to be implemented -- no "abstract static" exists)Evulsion
If you want execution-time error, you can do that already: create a virtual method that throws an exception.Jehad
Static methods are a different case, since they aren't on an instance in any case. I don't know what you mean by "why they chose abstract class specifically for these methods?". I've shown you the potential problem if a concrete class were allowed to have abstract methods. What would you rather happened?Tema
@Tema Even more fun if the abstract method had a return type instead of void. :) At least a void method can do nothing, but what does a return type do? default value? Yeah, I don't know what else would happen. Abstract is there for a reason, anything else can be handled by virtual as we suggested.Evulsion
@Tema I state it this way: Problem Statement was to provide abstract method functionality (if there was some other intention too, then its fine to provide a new concept "abstract class"). Now this problem could be solved by compiler designers in "n" ways (I am terming it as "n" because there could be other ways too), one of them is the current implementation. I am reasoning on alternate way adoption, why JAVA/C# (may be more languages) adopted to provide an additional type "abstract at class level i.e. abstract classes" and not chose to handle it at method level?Dagda
You still haven't suggested what 'handle at method level' might actually mean. What do you want to happen, in the above situation?Tema
Meaning there is no concept of "abstract class", rather there would be abstract keyword applicable to methods/properties/indexers etc only. And for providing a type blueprint there is interface. I am sure there would be a reason "virtual" is not applicable at class level while "abstract" is.Dagda
D
4

I think you've answered your own question, an abstract method isn't defined initially. Therefore the class cannot be instanciated. You're saying it should ignore it, but by definition when adding an abstract method you're saying "every class created from this must implement this {abstract method}" hence the class where you define the abstract class must also be abstract because the abstract method is still undefined at that point.

Delsiedelsman answered 25/9, 2012 at 10:36 Comment(0)
C
3

You can achieve what you want using "virtual" methods but using virtual methods can lead to more runtime business logic errors as a developer is not "forced" to implement the logic in the child class.

I think there's a valid point here. An abstract method is the perfect solution as it would "enforce" the requirement of defining the method body in children.

I have come across many many situations where the parent class had to (or it would be more efficient to) implement some logic but "Only" children could implement rest of the logic"

So if the opportunity was there I would happily mix abstract methods with complete methods.

@AakashM, I appreciate C# prefers compile time errors. So do I. And so does anybody. This is about thinking out-of-the-box.

And supporting this will not affect that.

Let's think out of the box here, rather than saying "hurrah" to big boy decisions.

C# compiler can detect and deny someone of using an abstract class directly because it uses the "abstract" keyword.

C# also knows to force any child class to implement any abstract methods. How? because of the use of the "abstract" keyword.

This is pretty simple to understand to anyone who has studied the internals of a programming language.

So, why can't C# detect an "abstract" keyword next to a method in a normal class and handle it at the COMPILE TIME.

The reason is it takes "reworking" and the effort is not worth supporting the small demand.

Specially in an industry that lacks people who think out of the boxes that big boys have given them.

Courtier answered 3/10, 2013 at 8:36 Comment(0)
C
3

The abstract class may contain abstract member. There is the only method declaration if any method has an abstract keyword we can't implement in the same class. So the abstract class is incompleted. That is why the object is not created for an abstract class.

Non-abstract class can't contain abstract member.

Example:

namespace InterviewPreparation
{
   public abstract class baseclass
    {
        public abstract void method1(); //abstract method
        public abstract void method2(); //abstract method
        public void method3() { }  //Non- abstract method----->It is necessary to implement here.
    }
    class childclass : baseclass
    {
        public override void method1() { }
        public override void method2() { }
    }
    public class Program    //Non Abstract Class
    {
        public static void Main()
        {
            baseclass b = new childclass(); //create instance
            b.method1();
            b.method2();
            b.method3();
        }
    }

}
Cirenaica answered 21/7, 2018 at 19:30 Comment(0)
D
1

It's still not clear why you would want that, but an alternative approach could be to force derived classes to provide a delegate instance. Something like this

class MyConcreteClass
{
  readonly Func<int, DateTime, string> methodImpl;

  // constructor requires a delegate instance
  public MyConcreteClass(Func<int, DateTime, string> methodImpl)
  {
    if (methodImpl == null)
      throw new ArgumentNullException();

    this.methodImpl = methodImpl;
  }

  ...
}

(The signature string MethodImpl(int, DateTime) is just an example, of course.)

Otherwise, I can recommend the other answers to explain why your wish probably isn't something which would make the world better.

Dioptometer answered 25/9, 2012 at 11:29 Comment(1)
Its fine to accept that alternatives are not best or even have severe drawbacks. But why the current implementation of abstract clases (why not keep abstract methods/properties/indexers etc like virtual) is best and was the concept of "abstract classes" inevitable (due to its advantages over other ways), keeping in mind interfaces are already there?Dagda
F
1

So the answers above are correct: having abstract methods makes the class inherently abstract. If you cannot instance part of a class, then you cannot instance the class itself. However, the answers above didn't really discuss your options here.

First, this is mainly an issue for public static methods. If the methods aren't intended to be public, then you could have protected non-abstract methods, which are allowed in an abstract class declaration. So, you could just move these static methods to a separate static class without much issue.

As an alternative, you could keep those methods in the class, but then instead of having abstract methods, declare an interface. Essentially, you have a multiple-inheritance problem as you want the derived class to inherit from two conceptually different objects: a non-abstract parent with public static members, and an abstract parent with abstract methods. Unlike some other frameworks, C# does permit multiple inheritance. Instead, C# offers a formal interface declaration that is intended to fill this purpose. Moreover, the whole point of abstract methods, really, is just to impose a certain conceptual interface.

Filiano answered 14/7, 2017 at 13:2 Comment(0)
P
0

I have a scenario very similar to what the OP is trying to achieve. In my case the method that I want to make abstract would be a protected method and would only be known to the base class. So the "new C().M();" does not apply because the method in question is not public. I want to be able to instantiate and call public methods on the base class (therefore it needs to be non-abstract), but I need these public methods to call a protected implementation of the protected method in the child class and have no default implementation in the parent. In a manner of speaking, I need to force descendants to override the method. I don't know what the child class is at compile time due to dependency injection.

My solution was to follow the rules and use a concrete base class and a virtual protected method. For the default implementation, though, I throw a NotImplementedException with the error "The implementation for method name must be provided in the implementation of the child class."

protected virtual void MyProtectedMethod() 
{ 
  throw new NotImplementedException("The implementation for MyProtectedMethod must be provided in the implementation of the child class."); 
}

In this way a default implementation can never be used and implementers of descendant implementations will quickly see that they missed an important step.

Plash answered 8/11, 2017 at 14:14 Comment(3)
So you replace a compiler error with a runtime exception? If your class is not abstract you risk at one point or another that your not implemented method is called on an instance of your class and throws an exception. If you mean abstract then simply use abstract and don't try to work around it.Scythia
A runtime error is a reasonable tradeoff given that the framework/language provides for no other mechanism to achieve what the OP is asking for. In my case, I am confident that if I hit the runtime error, I will find it very early in the development process. Either the child class is never used or it's used all the time (core utility). I am just offering a alternate solution to the need to define a method in a concrete class that is required to be overridden in any child class.Plash
Ed it's not clear to me how my post is not directly addressing the question in the OP by offering a workaround to the limitation of the framework/language??? Please contact me directly if you feel my post is so inappropriate.Plash
A
0

It can make sense to have abstract members of non-abstract class.

Today we define virtual methods, and we put inside them :

throw new NotImplementedException(); 

Having abstract members, is similar to that logic of having virtual & not yet implemented in the case of design patterns like :

  • Prototype
  • Template Method

Sometimes, we just not need default variation of the declared member, and we wait only for external implementations through overrides.

Anarch answered 24/5, 2024 at 9:33 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.