Virtual methods question

J

John Rivers

Sometimes an overriding method needs to call the base method at the
beginning:

override void Blah() {
base.Blah();
// do stuff
}//method

sometimes at the end:

override void Blah() {
// do stuff
base.Blah();
}//method

sometimes in the middle:

override void Blah() {
// do stuff
base.Blah();
// do more stuff
}//method

but sometimes you need to insert the overriding code in the middle of
the base function:
(or split the base method code in two)

abstract void Blah();

void BlahEntry() {
// do stuff
Blah(); // virtual
// do more stuff
}//method

then sometimes you would like to reverse the order or intercept the
virtual calls:
(I am just making up syntax to show the point)

abstract void Blah();

intercept void Blah() {
Log("blah called");
}//method

or even

intercept entry void Blah() {
Log("blah entry");
}//method

intercept exit void Blah() {
Log("blah exit");
}//method

the reason for the post is that as I develop applications I find that
achieving the above
with csharp is not straightforward - especially when you are a few
levels down the hierarchy
and cannot change certain base classes

is this a common feeling or am I missing some tricks?
 
W

Willem van Rumpt

John said:
the reason for the post is that as I develop applications I find that
achieving the above
with csharp is not straightforward - especially when you are a few
levels down the hierarchy
and cannot change certain base classes

is this a common feeling or am I missing some tricks?

If I understand you correctly (the made up syntax doesn't really help,
sorry), you have a need to have control over the order in which
overriden and base methods are called and/or have some sort of method
entry / exit hooks.

Well, you can't. You have control over when the base method is called
from within the override, not the other way around. The class you're
working with has to be designed and coded to allow for "OnEntry" /
"OnExit" calls, you can't just magically insert them (not in a "normal"
way at least).

It's not a csharp issue, it's a design issue, common to all languages.

If the class design is under your control, you have the option to change
the design to allow for it. Whether you should is another question though.
 
H

Harlan Messinger

Willem said:
If I understand you correctly (the made up syntax doesn't really help,
sorry), you have a need to have control over the order in which
overriden and base methods are called and/or have some sort of method
entry / exit hooks.

Well, you can't. You have control over when the base method is called
from within the override, not the other way around. The class you're
working with has to be designed and coded to allow for "OnEntry" /
"OnExit" calls, you can't just magically insert them (not in a "normal"
way at least).

It's not a csharp issue, it's a design issue, common to all languages.

If the class design is under your control, you have the option to change
the design to allow for it. Whether you should is another question though.
Following up on this, when you do have control over the base class, and
there is something in the nature of the base class's method where it
naturally divides up into logical sections like

public virtual void MyMethod()
{
//do some stuff
//derived classes might have their own
//extra bits that they might want to do here
//do some more stuff
}

then it would make sense to write it as

public void MyMethod()
//not necessarily virtual, depends on other intended uses
{
//do some stuff
MyMethodDetails();
//do some more stuff
}

protected virtual void MyMethodDetails()
{
/* empty */
}

so that your derived classes can override MyMethodDetails instead of
MyMethod.
 
J

John Rivers

Harlan: thanks for your post

when you deriving from an external library it can be hard to know when
to call the base method - sometimes there is a catch22

I like your public / protected idea
especially useful / confusing when both methods are virtual and
overridden

I guess the other approach is a shim? - a class that derives from the
same class as the target

class FrogBase;
class FrogShim : FrogBase;
class Frog : FrogBase;

and you can:

FrogBase frog = new FrogShim(new Frog());

and maybe generics would be good:

class FrogShim<T> : FrogBase where T : FrogBase {
}//class

but whichever way you do it - it is not pretty

I am sure there is room for an "intercept" concept - just like virtual
but with the order reversed
you could use "derived.Blah()" syntax which the compiler just elides
if their is no derived ...
and the rule would be that intercept methods have to use the same
overload

bit like the "bubble up" versus "bubble down" choice you get in IE
DHTML events
 
P

Peter Duniho

John said:
Harlan: thanks for your post

when you deriving from an external library it can be hard to know when
to call the base method - sometimes there is a catch22

There's no Catch 22. In a properly designed library, there will be no
specific requirement on when the base method must be called. Instead,
it will be up to the derived class to make that choice, and the choice
will be based on issues constrained to the derived class itself.

Even in a poorly designed library, if there is such a requirement, it
should be well-documented and followed by the derived class.

In neither case does this relate to the pattern Harlan is talking about.
In particular, his example specifically describes a situation where
the virtual method itself, base _and_ derived, needs to be called in a
particular point within a sequence of calls. In other words, the
scenario you seemed to be describing in your initial post.
[...]
I guess the other approach is a shim? - a class that derives from the
same class as the target

class FrogBase;
class FrogShim : FrogBase;
class Frog : FrogBase;

and you can:

FrogBase frog = new FrogShim(new Frog());

and maybe generics would be good:

class FrogShim<T> : FrogBase where T : FrogBase {
}//class

but whichever way you do it - it is not pretty

Nor necessary.
I am sure there is room for an "intercept" concept - just like virtual
but with the order reversed

Why are you so sure? What can you do with that concept that is not
possible now using the language features we already have?
you could use "derived.Blah()" syntax which the compiler just elides
if their is no derived ...

That's exactly what a virtual method is. If the derived class doesn't
override it, there's no method call. If you don't want to provide an
implementation, make the base virtual method abstract. If you want your
class to not be abstract, just provide an empty implementation.

Pete
 
J

John Rivers

Peter

the idea of the "intercept"

is that the call order be reversed

with virtual method the most derived method gets called first
and can call base.blah() if and when it wants

imagine the other way around on a hierarchy like

C : B
B : A
A

calling intercept Blah() on an instance of C

would call A.Blah()
which could call derived.Blah()

which would call B.Blah()
which could call derived.Blah()

which would call C.Blah()

another idea which I feel is missing:

onenter Blah() {}

onexit Blah() {}

which would allow you to attach code to the beginning and end of a
method

the current language is fine if you have and had complete control over
your class hierarchy from day 1
but in real life that never happens and seems a bad assumption to make
in a language design

I guess that is why so much effort is going into stuff like Unity and
detours and all those other intercept frameworks - trying to bolt on a
solution

I think it should be part of the language
as without it you have to do backflips to achieve simple things
 
P

Peter Duniho

John said:
Peter

the idea of the "intercept"

is that the call order be reversed

with virtual method the most derived method gets called first
and can call base.blah() if and when it wants

That's exactly what happens if the override calls the base method last.

Alternatively, if the base class includes the functionality that has to
happen last in the wrapper method Harlan describes, that's also exactly
what happens.
[...]
the current language is fine if you have and had complete control over
your class hierarchy from day 1
but in real life that never happens and seems a bad assumption to make
in a language design

It is possible to design a class for growth. It's true that if you
cannot even manage that much, it can be difficult to fix the problem
later. But frankly, if you approach programming with a "slap a patch on
it" mentality, you're going to have problems, whether or not the
language encourages that mentality or not.

Fortunately, C# does not encourage that mentality.
[...]
I think it should be part of the language
as without it you have to do backflips to achieve simple things

Even if we assume a precise definition for "backflips", you've yet to
demonstrate that C# requires you to do backflips to achieve simple things.

Pete
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top