0

Let's say I have an abstract Node class and BinaryOperation class derived from Node and three classes IntegerConstant, RealConstant and CharacterConstant also derived from Node.

The general design for the BinaryOperation class would look like this:

public class BinaryOperation : Node
{
    public Node Operand1 { get; private set; }
    public Node Operand2 { get; private set; }
    //...
}

I also have parsing methods for those classes, each of them returning given type. So IsIntegerConstant() is of type IntegerConstant and so on.

Now when parsing an operand in expression I could easily check the type like this:

Node operand1 = IsIntegerConstant() ??
                IsRealConstant() ??
                IsCharacterConstant();

However C# does not allow that. Because compiler cannot determine the type of the expression in operand1 assignment. What should I do? Should I make all of the parsing methods return type Node or cast each method to Node. Or maybe create separate BinaryOperation class members for each of the operand types?

  • Don't all you need to do is cast one call in the nullable to Node for the type inference to work? Annoying, but better than changing your design substantially to make the syntax a little cleaner. – Telastyn Aug 29 '17 at 20:15
  • Yes, that's what I thought. But seriously this makes the code really ugly, while I it will be used a lot in the parsing methods. – 107MP Aug 29 '17 at 20:20
2

What should I do? Should I make all of the parsing methods return type Node or cast each method to Node.

I'd suggest adding, to use here in your example, a more general operand-parsing wrapper that returns Node whose implementation internally determines the type of the operand perhaps using such cascading.

Or maybe create separate BinaryOperation class members for each of the operand types?

No, don't do that! This seems like class explosion to me. You'd need a subclass for each left operand subclass X a subclass for each right operand subclass — a whole matrix of classes, for what I can only see as little-to-no value.


What do you do if all including the last IsCharacterConstant() fails? It seems that operand1 becomes null in that case, ignoring the parse input — rather than getting some useful error. You might try:

Node operand1 = IsIntegerConstant() ??
                IsRealConstant() ??
                IsCharacterConstant() ??
                ReportError("... this operator must have a constant left operand ...");

where ReportError has declared return type of Node, thus satisfying the C# inference algorithm.


I'm not familiar with this parsing technique; it seems very specific, are you thinking it will support your long term needs? Do you not support parenthesis or nested binary operations?

I ask because the question of type inference ugliness becomes moot if a more general parsing method is needed anyway — as a more general method might parse an operand to a Node, making this cascading not so broadly visible across your code base, if not eliminating it.

  • This parses postfix expressions. When it comes to null-checking, I didn't mention it but I check it just after assigning. – 107MP Aug 29 '17 at 21:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.