How does the combination Inference Rule and Overloaded Operations Rules work?

Hi community,

I'm currently working on an expression language. For this purpose I utilized the existing expression language from https://github.com/gsdlab/claferMPS/tree/master/code/languages/org.clafer.mps (thx to Markus Voelter). It works pretty fine with one exception: It seems that the overloaded operations rules are not evaluated.

Scenario:
Let's say there is a concept called "BinaryExpression" that has two children of concept "Expression" called "left" and "right". If I write an equation like...
3.0 * 7.0
prettyPrint(); ... I get an type system error with "operator * cannot be applied to double and double". This error occurs if the types of the operands can be calculated but the type of the operation is null. The operation's type is calculated in the following type inference rule:

rule typeof_BinaryExpression {            
  applicable for concept = BinaryExpression as be        
  overrides false          
            
  do {      
    when concrete (typeof(be.left) as leftType) { 
      when concrete (typeof(be.right) as rightType) { 
 
        node<> optype = operation type(be, leftType, rightType); 
        info "optype is " + optype; 
        if (optype != null) { 
          typeof(be) :==: optype; 
        } else { 
          if (leftType == null) { 
            error "left side was not set" -> be; 
          } 
          if (rightType == null) { 
            error "right side was not set" -> be; 
          } 
          if (leftType != null && rightType != null) { 
            error "operator " + be.concept.conceptAlias + " cannot be applied to " + leftType/.getPresentation() + " and " + rightType/.getPresentation() -> be; 
          } 
        } 
      } 
    }
  }         
}           
prettyPrint();
But "operation type(...)" always evaluates to null (no matter if it is a multiplication, division, subtraction or addition, etc.).
The overloaded operation rules look as follows:

operation concepts: BinaryArithmeticExpression        
left operand type: new node<PrimitiveType>() is exact: false use strong subtyping false            
right operand type: new node<PrimitiveType>() is exact: false use strong subtyping false           
is applicable:          
<no isApplicable>       
operation type:         
(operation, leftOperandType, rightOperandType)->node<> { 
  if (operation.isStaticallyEvaluatable()) { return NumberEvaluationHelper.staticType(leftOperandType, rightOperandType, operation); } 
   
  // Check if both operants have the same type 
  if (leftOperandType.concept.isExactly(# rightOperandType.concept)) { return leftOperandType; } 
  node<> commenSuperType = AssignableSuperTypeHelper.getCommonSuperType(leftOperandType, rightOperandType); 
  return commenSuperType; 
}    
prettyPrint();

Has anybody an idea why this happens?

Thank you very much in advance!
LaAck
4 comments
I'd suggest that you first check whether the overloaded operation rules actually get called and what value is returned.
This should help narrow down the cause of the trouble.

Vaclav
0
Hi Vaclav,

thank you very much for your reply. I'm very sorry, I forget to put this piece of information in my issue description. I already checked whether the overloaded operation rules are called or not. Actually they are NOT called. So I checked whether the operation concept and the operand types fit. During runtime the following arguments given to the function "operation type(be,leftType,rightType)":
  • be: MultiExpression which is a subconcept of BinaryArithmeticExpression
  • leftType: node<DoubleType> where DoubleType is a subconcept of PrimitiveType
  • rightType: same as leftType

To my current understanding the overloaded operation rule should be called. Do you have any ideas why it is not?

Thank you again in advance,
LaAck
0
Hi,

here's one thing that you need to be careful about here - the overloaded operations rules matches to a type or its super-type, not its super-concept!
It seems to me that you are mixing two hierarchies - the hierarchy of concepts and the hierarchy of types. Instead of matching against "new node<PrimitiveType>()" you should be checking against a type, that is declared as a super-type of your DoubleType in some sub-typing rule.

I hope this helps shed some light into the issue.

Cheers,

Vaclav
0
Hi,

awesome, this solved the issue! Thank you very much. In my defense I have to say, that I just re-used the expression language I mentioned in my first post about this issue. ;) Anyway. The final solution was to introduce another sub-typing rule which declares DoubleType to be a sub-type of PrimitiveType. I thought that, as long the concept DoubleType inherits from PrimitiveType, the type system rules are also inherited (if they are not overridden by a sub-concepts type inference rule). According to your explanations I think this was my error in reasoning.

So thank you very much again!

Best regards,
LaAck
0

Please sign in to leave a comment.