Issue 13082: current abstract syntax of ImperativeOCL introduces a couple of unclear situations (qvt-rtf) Source: (, ) Nature: Enhancement Severity: Significant Summary: Major Problem: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. Further Problems: (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. (3) Several OCL equivalence rules break when ImperativeOCL is present. Detailed problem description: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. In the abstract syntax, ImperativeOCL expressions / statements are inherited from OclExpression. Therefore, conventional OCL expressions may (and will) contain sub-expressions that are actually ImperativeOCL expressions. In conventional OCL, the interpretation of an expression under a given environment is a value. In ImperativeOCL, the interpretation of an expression is a value and a new environment (state,variables). This extended interpretation is not given for conventional OCL expressions, leading to undefined operational semantics of those expressions. Example: Given the following compute expression: compute(z:Boolean) { var x : Boolean := true var y : Boolean := true if ((x:=false) and (y:=false)) { ... } z := y } What is the value of this expression: is it true or false (It depends on whether the 'and' operator is evaluated short-circuit or strict). The situation is similar for the evaluation of the other logical connectives, forAll, and exists when these expressions contain imperative sub-expressions. (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. Some of the new language features in ImperativeOCL such as forEach and the imperative conditional are not really necessary. Their effect can already be achieved using conventional OCL expressions: For example: company.employees->forEach(c) { c.salary := c.salary * 1.1} has the same effect as company.employees->iterate(c; r:OclAny=Undefined | c.salary := c.salary * 1.1 ) and if ( x < 0 ) { x := 0 } else { x := 1 } endif is the same as if x < 0 then x := 0 else x := 1 endif (3) Several OCL equivalence rules break when ImperativeOCL is present. In conventional OCL, several equivalence rules well known from logic hold. Allowing OCL expression to contain imperative sub-expressions breaks these equivalence rules. Examples: let x=e1 in e2 equiv. e2 { all occurences of x replaced by e1 } e1 and e2 equiv. e2 and e1 These equivalences do not necessarily hold if e1 or e2 are allowed to have side-effects. Proposed solution: (A) - (The cheap solution.) State textually that conventional OCL expressions (as described in the OMG OCL spec.) are not allowed to have side effects unless used as part of a top level ImperativeOCL expression. Therefore, even in a system supporting ImperativeOCL, class invariants, and pre- and postconditions (e.g.) will not be allowed to contain ImperativeOCL sub-expressions. State explicitly that the redundant flow control statements have been introduced (solely) to write concise imperative programs and that the side-effect free forms of conditional evaluation ( 'if-then-else-endif' and 'iterate' ) shall not be used to program side-effects (instead, the ImperativeOCL forms shall be used). (B) - (Major rework.) Rework the abstract syntax to reuse OCL expressions by composition rather than by inheritance. Imperative expressions ( => rename to 'statements' ) then may contain sub-statements and OCL expressions; OCL expressions are reused unchanged from the OCL spec (no imperative sub-expressions, no side-effects). These issues have been discussed on the MoDELS 2008 OCL Workshop, more details can be found at http://www.fots.ua.ac.be/events/ocl2008/PDF/OCL2008_9.pdf Resolution: current abstract syntax of ImperativeOCL introduces a couple of unclear situations Major Problem: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. Further Problems: (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. (3) Several OCL equivalence rules break when ImperativeOCL is present. Detailed problem description: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. In the abstract syntax, ImperativeOCL expressions / statements are inherited from OclExpression. Therefore, conventional OCL expressions may (and will) contain sub-expressions that are actually ImperativeOCL expressions. In conventional OCL, the interpretation of an expression under a given environment is a value. In ImperativeOCL, the interpretation of an expression is a value and a new environment (state,variables). This extended interpretation is not given for conventional OCL expressions, leading to undefined operational semantics of those expressions. Example: Given the following compute expression: compute(z:Boolean) { var x : Boolean := true var y : Boolean := true if ((x:=false) and (y:=false)){ ... } z := y } What is the value of this expression: is it true or false (It depends on whether the 'and' operator is evaluated short-circuit or strict). The situation is similar for the evaluation of the other logical connectives, forAll, and exists when these expressions contain imperative sub-expressions. (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. Some of the new language features in ImperativeOCL such as forEach and the imperative conditional are not really necessary. Their effect can already be achieved using conventional OCL expressions: For example: company.employees->forEach(c){ c.salary := c.salary * 1.1} has the same effect as company.employees->iterate(c; r:OclAny=Undefined | c.salary := c.salary * 1.1 ) and if ( x < 0 ){ x := 0 } else{ x := 1 } endif is the same as if x < 0 then x := 0 else x := 1 endif (3) Several OCL equivalence rules break when ImperativeOCL is present. In conventional OCL, several equivalence rules well known from logic hold. Allowing OCL expression to contain imperative sub-expressions breaks these equivalence rules. Examples: let x=e1 in e2 equiv. e2{ all occurences of x replaced by e1 } e1 and e2 equiv. e2 and e1 These equivalences do not necessarily hold if e1 or e2 are allowed to have side-effects. Proposed solution: (A) - (The cheap solution.) State textually that conventional OCL expressions (as described in the OMG OCL spec.) are not allowed to have side effects unless used as part of a top level ImperativeOCL expression. Therefore, even in a system supporting ImperativeOCL, class invariants, and pre- and postconditions (e.g.) will not be allowed to contain ImperativeOCL sub-expressions. State explicitly that the redundant flow control statements have been introduced (solely) to write concise imperative programs and that the side-effect free forms of conditional evaluation ( 'if-then-else-endif' and 'iterate' ) shall not be used to program side-effects (instead, the ImperativeOCL forms shall be used). (B) - (Major rework.) Rework the abstract syntax to reuse OCL expressions by composition rather than by inheritance. Imperative expressions ( => rename to 'statements' ) then may contain sub-statements and OCL expressions; OCL expressions are reused unchanged from the OCL spec (no imperative sub-expressions, no side-effects). These issues have been discussed on the MoDELS 2008 OCL Workshop, more details can be found at [1]http://www.fots.ua.ac.be/events/ocl2008/PDF/OCL2008_9.pdf Discussion - 1 short circuit semantics It is possible to weasel out of this narrowly described problem by observing that OCL only supports short-circuit semantics once it is proven that no invalid lurks beyond the short-circuit. An extension to this could inhibit short-circuit semantics if any imperative expression is involved. Discussion - (2) redundant control flow The first suggestion is contradictory. The replacement for forEach is noticeably longer and uses a side effect within an iterate, which the author argues against elsewhere. The second suggestion incorrectly assumes that an else clause is present. The imperative if (SwitchExp) allows one-sided functionality including selective control flow adjustment. Discussion - (3) broken equivalence The example is unreadable, but the point is unarguable; imperative semantics within functional semantics subvert the functional. (A) - (The cheap solution.) is simple and adopted here. (B) - (Major rework.) is a breaking structural change and so forked off to [2]http://solitaire.omg.org/browse/QVT13-87 for consideration by QVT 2.0. ---------------------------------------------------------------------------------------- [1] http://www.fots.ua.ac.be/events/ocl2008/PDF/OCL2008_9.pdf [2] http://solitaire.omg.org/browse/QVT13-87 Revised Text: In 8.2.2.1 Add Note also that since an ImperativeExpression can introduce side effects, it may not be used in a side effect free OclExpression even though its inheritance from OclExpression might suggest that it can. When side effects are required, imperative constructs such as ImperativeLoopExp, SwitchExp or VariableInitExp should be used in place of LoopExp, IfExp or LetExp. Constraint Every containment ancestor of an ImperativeExpression that is an OclExpression must also be an ImperatveExpression. context ImperativeExpression inv IsInImperativeContext: let ancestors = self->closure(oclContainer()) in ancestors->forAll(oclIsKindOf(OclExpression) implies oclIsKindOf(ImperativeExpression)) Actions taken: November 15, 2008: received issue December 22, 2015: Resolved March 29, 2016: closed issue Discussion: A rework may be necessary to clarify whether the claim that QVT (and consequently QVTo ) is an extension of OCL needs to be amended. Disposition: Deferred End of Annotations:===== s is issue # 13082 Name: Fabian Büttner Company: University of Bremen mailFrom: green@tzi.de current abstract syntax of ImperativeOCL introduces a couple of unclear situations Major Problem: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. Further Problems: (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. (3) Several OCL equivalence rules break when ImperativeOCL is present. Detailed problem description: (1) The current abstract syntax of ImperativeOCL introduces a couple of unclear situations. This may lead to incompatible QVT implementations. In the abstract syntax, ImperativeOCL expressions / statements are inherited from OclExpression. Therefore, conventional OCL expressions may (and will) contain sub-expressions that are actually ImperativeOCL expressions. In conventional OCL, the interpretation of an expression under a given environment is a value. In ImperativeOCL, the interpretation of an expression is a value and a new environment (state,variables). This extended interpretation is not given for conventional OCL expressions, leading to undefined operational semantics of those expressions. Example: Given the following compute expression: compute(z:Boolean) { var x : Boolean := true var y : Boolean := true if ((x:=false) and (y:=false)) { ... } z := y } What is the value of this expression: is it true or false (It depends on whether the 'and' operator is evaluated short-circuit or strict). The situation is similar for the evaluation of the other logical connectives, forAll, and exists when these expressions contain imperative sub-expressions. (2) Control flow constructs introduced by ImperativeOCL are redundant compared with existing conventional OCL constructs. Some of the new language features in ImperativeOCL such as forEach and the imperative conditional are not really necessary. Their effect can already be achieved using conventional OCL expressions: For example: company.employees->forEach(c) { c.salary := c.salary * 1.1} has the same effect as company.employees->iterate(c; r:OclAny=Undefined | c.salary := c.salary * 1.1 ) and if ( x < 0 ) { x := 0 } else { x := 1 } endif is the same as if x < 0 then x := 0 else x := 1 endif (3) Several OCL equivalence rules break when ImperativeOCL is present. In conventional OCL, several equivalence rules well known from logic hold. Allowing OCL expression to contain imperative sub-expressions breaks these equivalence rules. Examples: let x=e1 in e2 equiv. e2 { all occurences of x replaced by e1 } e1 and e2 equiv. e2 and e1 These equivalences do not necessarily hold if e1 or e2 are allowed to have side-effects. Proposed solution: (A) - (The cheap solution.) State textually that conventional OCL expressions (as described in the OMG OCL spec.) are not allowed to have side effects unless used as part of a top level ImperativeOCL expression. Therefore, even in a system supporting ImperativeOCL, class invariants, and pre- and postconditions (e.g.) will not be allowed to contain ImperativeOCL sub-expressions. State explicitly that the redundant flow control statements have been introduced (solely) to write concise imperative programs and that the side-effect free forms of conditional evaluation ( 'if-then-else-endif' and 'iterate' ) shall not be used to program side-effects (instead, the ImperativeOCL forms shall be used). (B) - (Major rework.) Rework the abstract syntax to reuse OCL expressions by composition rather than by inheritance. Imperative expressions ( => rename to 'statements' ) then may contain sub-statements and OCL expressions; OCL expressions are reused unchanged from the OCL spec (no imperative sub-expressions, no side-effects). These issues have been discussed on the MoDELS 2008 OCL Workshop, more details can be found at http://www.fots.ua.ac.be/events/ocl2008/PDF/OCL2008_9.pdf