I have to design a solution for a task, and I would like to use something theoretically similar to C#'s ExpressionVisitor.
For curiosity I opened the .NET sources for ExpressionVisitor
to have a look at it. From that time I've been wondering why the .NET team implemented the visitor as they did.
For example MemberInitExpression.Accept
looks like this:
protected internal override Expression Accept(ExpressionVisitor visitor) {
return visitor.VisitMemberInit(this);
}
My - probably noob - question is: does it make any sense? I mean shouldn't the Accept method itself be responsible of how it implements the visiting within itself? I mean I've expected something like this (removing the internal
visibility to be overridable from outside):
protected override Expression Accept(ExpressionVisitor visitor) {
return this.Update(
visitor.VisitAndConvert(this.NewExpression, "VisitMemberInit"),
visitor.Visit(this.Bindings, VisitMemberBinding)
);
}
But this code is in the base ExpressionVisitor
's VisitMemberInit
method, which gets called from MemberInitExpression.Accept
. So seems like not any benefit of the Accept
implementation here.
Why not just process the tree in the base ExpressionVisitor
, and forget about all the Accept
methods?
I hope you understand my points, and hope someone could shed some light on the motivation behind this implementation. Probably I don't understand the Visitor pattern at all?...
One of the most significant features of C language is its support for dynamic memory management (DMA). It means that you can utilize and manage the size of the data structure in C during runtime. C also provides several predefined functions to work with memory allocation.
Through this example, we are brought to learn about what they call the Six C's of motivation: choice, challenge, control, collaboration, constructing meaning, and consequences.
Motivation is derived from the word 'motive,' which denotes a person's needs, desires, wants, or urges. It is the process of motivating individuals to take action in order to achieve a goal. The psychological elements fueling people's behavior in the context of job goals might include a desire for money.
The C language was actually created to move the UNIX kernel code from assembly to a higher level language, which would do the same tasks with fewer lines of code. Oracle database development started in 1977, and its code was rewritten from assembly to C in 1983. It became one of the most popular databases in the world.
A visitor can override the way any expression is visited. If your proposal was implemented in all places the visitor never would be called. All the visitation logic would be in the overrides of Accept
. Non-BCL code cannot override this method.
If you write visitor.Visit((Expression)this.SomeExpression)
(like you do in the question) then how are you going to perform dynamic dispatch on the type of SomeExpression
? Now the visitor has to perform the dynamic dispatch. Note, that your 2nd code snippet makes the simplifying assumption that all sub-expressions to be visited have known type. Try to write the code for BinaryExpression
to see what I mean.
Maybe I did not understand something but this proposal does not make sense.
The purpose of the Accept
method is a performance optimization. Each accept is a virtual call which is rather cheap. The alternative would be to have a huge switch in the visitor over the expression type (which is an enum). That's probably slower.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With