Issue 12953: Exact type of Set{} and missing Set(MyType){} literal definitions (ocl2-rtf) Source: France Telecom R&D (Mr. Mariano Belaunde, mariano.belaunde(at)orange.com) Nature: Uncategorized Issue Severity: Summary: Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. Resolution: Discussion of this issue suggested a number of options: Option 1: The type of Set{} is Set(OclVoid) This does not work because Set{}->including(1) is an error since "1" or indeed anything other than null or invalid does not conform to OclVoid. Option 2: The type of Set{} is Set(OclAny) This does not work because acc : Set(Integer) = Set{}->including(1) is an error since Set(OclAny) is not compatible with Set(Integer). Option 3: The type of Set{} is a new built-in type EmptySet(ET) where ET is determined in some way. This does not work because given the RHS of acc : Set(Integer) = Set{}->including(1.0)- >including(Classifier)->excluding(1.0)->excluding(Classifier) it is difficult to see how ET could be determined more precisely than OclAny causing the same problem as Option 2. Option 4: The type of Set{} is Set(null) Since Set{} and Set(null) have no precise OCL 2.1 semantics there is some discretion in defining them, but eventually a dynamic type validation is needed for acc : Set(String) = Set(null){getInitialValue()}. The impact on evaluation could be mitigated by synthesis of an oclAsType() in the Abstract Syntax Tree, but it is not 18 possible to provide a static type for the CollectionLiteralExp. This option could work but requires revision of abstract syntax and evaluation specifications. Option 5: The type of Set{} is back-propagated For instance in acc : Set(Real) = Set{}->including(1)->including(-1) the type of Set{} is Set(Real) since that is the eventual result type. This involves unusual reverse semantics. Option 6: The type of Set{} is Set(T) with T chosen for well-formedness of the expression in which the Set{} is used. For instance in acc : Set(Real) = Set{}->including(1)->including(-1) the type of Set{} is initially Set(T) where T <= OclVoid. Propagation of the type to Set(T)::including(UnlimitedNatural) requires T <= UnlimitedNatural. Propagation to Set(T)::including(Integer) requires T <= Integer. Finally, propagation to the initializer requires Real <= T. Therefore any Real <= T <= Integer is well-formed. The lower bound, Set(Real), is preferred since it avoids many type conversions. It is also the same result as Option 5. Option 6 involves only additional forward static semantics, has no impact on evaluation, no impact on parsing, and gives the intuitively correct OCL 2.1 results. ----- In order to impose a user-specified element type and so get static type checking of user intent, a collection element type can be specified as: acc : Set(Integer) = Set(Integer){} It is difficult to parse this in OCL 2.1 because Set is not a reserved word and so lookahead is required to determine whether Set(someName) is the start of a StringLiteralExpCS or an OperationCallExpCS, with someName perhaps being a complicated nested type/value ambiguity. Issue 14357 introduces the concept of a restricted word preventing the unqualified use of Set as an operation name. The extension is then straightforward. Revised Text: In 7.5.11 after A bag: Bag {1, 3, 4, 3, 5 } add The element type may be specified in parentheses. This ensures that the types of elements can be statically checked. Bag(Real) {1, 3, 4, 3, 5 } In 8.3.7 CollectionLiteralExp replace Note that the definition below implicitly states that empty collections have OclVoid as their elementType. by Note that the definition below defines only an upper bound on the elementType. The usage of the CollectionLiteralExp defines a lower bound. If the elementType is not explicitly specified, the elementType must be chosen to ensure the well-formedness of the elements of the CollectionLiteralExp and the usage of the CollectionLiteralExp. For instance in acc : Set(Real) = Set{1}->excluding(-1) Set{1} is well formed for any type Set(T) where T ? UnlimitedNatural. Well-formedness of the excluding operation call requires T ? Integer, and well-formedness of the initializer requires Real ? T. The overall expression is therefore only well-formed if Real ? T ? Integer. Either Set(Real) or Set(Integer) are wellformed. The most general type, Set(Real), is recommended since it minimizes type conversions and can often be easily deduced by considering the result type. In 8.3.7 CollectionLiteralExp replace inv: type.oclAsType (CollectionType).elementType = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) by inv: let elementType : Type = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) in elementType.conformsTo(type.oclAsType (CollectionType).elementType) In 9.3 CollectionLiteralExpCS replace CollectionLiteralExpCS ::= CollectionTypeIdentifierCS ‘{‘ CollectionLiteralPartsCS? ‘}’ Abstract syntax mapping CollectionLiteralExpCS.ast : CollectionLiteralExp Synthesized attributes CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast CollectionLiteralExpCS.ast.kind = CollectionTypeIdentifierCS.ast Inherited attributes CollectionTypeIdentifierCS.env = CollectionLiteralExpCS.env CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env Disambiguating rules [1] In a literal the collection type may not be Collection. CollectionTypeIdentifierCS.ast <> ‘Collection’ by [A] CollectionLiteralExpCS ::= CollectionTypeIdentifierCS ‘{‘ CollectionLiteralPartsCS? ‘}’ [B] CollectionLiteralExpCS ::= collectionTypeCS ‘{‘ CollectionLiteralPartsCS? ‘}’ Abstract syntax mapping CollectionLiteralExpCS.ast : CollectionLiteralExp Synthesized attributes [A] CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast [A] CollectionLiteralExpCS.ast.kind = CollectionTypeIdentifierCS.ast [B] CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast [B] CollectionLiteralExpCS.ast.kind = collectionTypeCS.ast.kind [B] CollectionLiteralExpCS.ast.type = collectionTypeCS.ast Inherited attributes [A] CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env [A] CollectionTypeIdentifierCS.env = CollectionLiteralExpCS.env [B] CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env [B] collectionTypeCS.env = CollectionLiteralExpCS.env Disambiguating rules [A] [1] In a literal the collection type may not be Collection. CollectionTypeIdentifierCS.ast <> ‘Collection’ [B] [1] In a literal the collection type may not be Collection. collectionTypeCS.ast <> CollectionType Actions taken: October 10, 2008: received issue April 25, 2011: closed issue Discussion: Resolution of this issue requires some extra analysis Disposition: Deferred End of Annotations:===== s is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. From: "Christian W. Damus" To: ocl2-rtf@omg.org Subject: Re: issue 12953 -- OCL 2 RTF issue Date: Fri, 10 Oct 2008 15:36:37 -0400 X-Mailer: Apple Mail (2.929.2) X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - s014.panelboxmanager.com X-AntiAbuse: Original Domain - omg.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - zeligsoft.com X-Source: X-Source-Args: X-Source-Dir: I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com Subject: RE: issue 12953 -- OCL 2 RTF issue: Empty versus Void Date: Fri, 17 Oct 2008 19:59:33 +0200 X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: issue 12953 -- OCL 2 RTF issue: Empty versus Void thread-index: AckrD9A9rUgZh4g7R9KaYSzx8Y1v9QFanFng From: To: , X-OriginalArrivalTime: 17 Oct 2008 17:59:35.0407 (UTC) FILETIME=[1D68F7F0:01C93082] Hi Christian, I hope you enjoy your vacations this week. Here's some comments on your message about issue 12953. >>> I think it is sufficient to define the type of Set{} as Set(Void). I'm not sure considering that the type of Set{} is Set(Void) is really intuitive... I would naturally think that the type of Set{} is a set of "any" object (Set(Object) in MOF reflection terms or Set(OclAny) with AnyType extended to represent all objects). By the way, the fact that "Void" conforms to all types, does not mean all other types conforms to Void. Do you agree? So if Bag(A) means a Bag containing instances of A or subtypes of A (or more precisely types conforming to A), Then Bag(Void) should be a collection of only null values (????). I tend to think that a more consistent interpretation of validity of acc : Bag(A) = Bag{} is that Bag{} is, in this specific case, a shorthand for Bag(A){} ! A second - maybe better - interpretation would be: the type of Bag{} is a special Bag(Empty) type, which should not be confused with the Bag(Void) meaning a different thing (Bag with null values inside...) I think that in previous OCL 1.x, it was possible to interpret Bag{} as being of type Bag(Void) because it was prohibited to have invalid values in collections. And so Void and Empty were considered the same as a conceptual simplification. But now, with the differentiation between null and invalid and the possibility to have collections containing null values, then interpreting Bag{} as being of type Bag(Void) sounds like a bug (???). What's your opinion? (I am, maybe, a bit confused). Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 10 octobre 2008 21:37 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com From: "Christian W. Damus" To: ocl2-rtf@omg.org Subject: Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Date: Fri, 17 Oct 2008 15:31:50 -0400 X-Mailer: Apple Mail (2.929.2) X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - s014.panelboxmanager.com X-AntiAbuse: Original Domain - omg.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - zeligsoft.com X-Source: X-Source-Args: X-Source-Dir: Hi, Mariano, Yes, I will enjoy my vacation next week very much. Certainly other types do not conform to Void, otherwise we would have a generalization cycle. The perspective I have on the collection types is entirely driven by type conformance, avoiding as much as possible interpretations of syntax as short-hand for a more complete syntax. We need to be able to do: Sequence{1..10}->iterate(i; acc : Set(String) = Set{} | acc->including(i.toString())) and Set{}->including('a string') in which the result type of both expressions is Set(String), and I think we can do it without a syntax for explicitly constructing a collection of a given element type. It just requires that the type of Set{} be Set(Void) In the first expression, we initialize the variable acc which has type Set(String) with the value Set{}. If Set{} were of type Set(OclAny), then this would not be valid, because Set(OclAny) does not conform to Set(String). Rather, it is the other way around. Also, we need constructions starting with Set{} to be able to result in a value of type Set(String). One example is the including() operation in the second expression, which when the argument is of type String will only result in Set(String) if the source collection is of type Set(T) where T conforms to String. When T is Void (the source collection having type Set(Void)) makes this work nicely. OCL 2.0 also prohibits invalid in collections, so I'm not sure of the relevance of that. Also, introducing another type Empty exclusively for use in collections further muddies the type system. What does this type mean as a classifier of values sharing common features? It would seem to have the same meaning as Void, so why not just use Void? On the subject of null elements: clearly, Bag(Void) can only contain nulls, but nobody would ever declare a variable or property of type Bag(Void) because it just wouldn't be useful. But, that's not the point. The point is what is the type of the Bag{} literal expression that makes this expression consistent with the collection type system. Cheers, Christian On 17-Oct-08, at 1:59 PM, wrote: Hi Christian, I hope you enjoy your vacations this week. Here's some comments on your message about issue 12953. >>> I think it is sufficient to define the type of Set{} as Set(Void). I'm not sure considering that the type of Set{} is Set(Void) is really intuitive... I would naturally think that the type of Set{} is a set of "any" object (Set(Object) in MOF reflection terms or Set(OclAny) with AnyType extended to represent all objects). By the way, the fact that "Void" conforms to all types, does not mean all other types conforms to Void. Do you agree? So if Bag(A) means a Bag containing instances of A or subtypes of A (or more precisely types conforming to A), Then Bag(Void) should be a collection of only null values (????). I tend to think that a more consistent interpretation of validity of acc : Bag(A) = Bag{} is that Bag{} is, in this specific case, a shorthand for Bag(A){} ! A second - maybe better - interpretation would be: the type of Bag{} is a special Bag(Empty) type, which should not be confused with the Bag(Void) meaning a different thing (Bag with null values inside...) I think that in previous OCL 1.x, it was possible to interpret Bag{} as being of type Bag(Void) because it was prohibited to have invalid values in collections. And so Void and Empty were considered the same as a conceptual simplification. But now, with the differentiation between null and invalid and the possibility to have collections containing null values, then interpreting Bag{} as being of type Bag(Void) sounds like a bug (???). What's your opinion? (I am, maybe, a bit confused). Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 10 octobre 2008 21:37 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com Subject: RE: issue 12953 -- OCL 2 RTF issue: Empty versus Void Date: Mon, 27 Oct 2008 19:00:42 +0100 X-MS-Has-Attach: X-MS-TNEF-Correlator: Thread-Topic: issue 12953 -- OCL 2 RTF issue: Empty versus Void thread-index: Ackwj3Qoi2jaAGt/T+yHNm57QnN30wHt3sfw From: To: , X-OriginalArrivalTime: 27 Oct 2008 18:00:44.0077 (UTC) FILETIME=[EE78ADD0:01C9385D] Hi Christian, Hereafter further discussion on issue 12953 (empty versus collection of void). Notice this resolution of this issue is not part of the coming first ballot. >>> The point is what is the type of the Bag{} literal expression that makes this expression consistent >>> with the collection type system. Exactly, and here's where I have a concern to consider that the type of Bag{} is Bag(Void). Bag(Void) is a type for bags that contain null values, whereas Bag{} is a specific value meaning a Bag with no contents. Since having null values and having no values are two different things, it would be strange that these two situations are represented by the same type... If you can demonstrate that it is consistent to say that the type of Bag{} is Bag(Void), I would be happy, but currently i'm not convinced. It looks more to me as being an hazardous or opportunistic simplification. Don't you agree? Regarding the possible interpretation of Bag{} to mean Bag(SomeType){}, I agree this is not ideal. We should better avoid having a syntactic interpretation for Bag{}, since this could have non trivial impact on OCL parsers. >>> Also, introducing another type Empty exclusively for use in collections further >>> muddies the type system. What does this type mean as a classifier of values >>> sharing common features? It would seem to have the same meaning as Void, Sorry, I made a little mistake. Saying the type of Bag{} is "Bag(Empty)" does not make sence, since "empty" is not a kind of element in a collection. But saying the type of Bag{} is "EmptyBag", this would make much more sence. An EmptyBag would be a type representing empty bags, and as a matter of fact there is unique possible value named Bag{} (similarily to Void having a unique null value). This EmptyBag type is compatible to all Bags - and in that sence is not equal to Void which is compatible with all types. Now, concerning the expression:: Bag{}->including('a string') We need to have a clear way to state its validity. Looking at the definition of "Bag::including" operation in the OCL spec, I see the signature: including (object : T) : Bag(T) Do you know what is the correct interpretation of this signature???, and how is computed the type of these expression calls? - Is the type T in the return type necessarily the same type of the elements of the source collection? - Or is the type T the "best" type between the type of the source elements and the argument type? The problem with first interpretation is that the expression Bag{null,null}->including("A string") would yield to a value {null,null,"A string"} incompatible with Bag(Void), since a collection of voids cannot contain a String. The problem wuth the second is that, contrary to ordinary operations, the statically computed type of the call expression would not be derived from the signature, as we could expect, but instead be derived from very specific rules. Do you know if in the spec there is an unambigous definition of the type of this kind of expressions? Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 17 octobre 2008 21:32 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Hi, Mariano, Yes, I will enjoy my vacation next week very much. Certainly other types do not conform to Void, otherwise we would have a generalization cycle. The perspective I have on the collection types is entirely driven by type conformance, avoiding as much as possible interpretations of syntax as short-hand for a more complete syntax. We need to be able to do: Sequence{1..10}->iterate(i; acc : Set(String) = Set{} | acc->including(i.toString())) and Set{}->including('a string') in which the result type of both expressions is Set(String), and I think we can do it without a syntax for explicitly constructing a collection of a given element type. It just requires that the type of Set{} be Set(Void) In the first expression, we initialize the variable acc which has type Set(String) with the value Set{}. If Set{} were of type Set(OclAny), then this would not be valid, because Set(OclAny) does not conform to Set(String). Rather, it is the other way around. Also, we need constructions starting with Set{} to be able to result in a value of type Set(String). One example is the including() operation in the second expression, which when the argument is of type String will only result in Set(String) if the source collection is of type Set(T) where T conforms to String. When T is Void (the source collection having type Set(Void)) makes this work nicely. OCL 2.0 also prohibits invalid in collections, so I'm not sure of the relevance of that. Also, introducing another type Empty exclusively for use in collections further muddies the type system. What does this type mean as a classifier of values sharing common features? It would seem to have the same meaning as Void, so why not just use Void? On the subject of null elements: clearly, Bag(Void) can only contain nulls, but nobody would ever declare a variable or property of type Bag(Void) because it just wouldn't be useful. But, that's not the point. The point is what is the type of the Bag{} literal expression that makes this expression consistent with the collection type system. Cheers, Christian On 17-Oct-08, at 1:59 PM, wrote: Hi Christian, I hope you enjoy your vacations this week. Here's some comments on your message about issue 12953. >>> I think it is sufficient to define the type of Set{} as Set(Void). I'm not sure considering that the type of Set{} is Set(Void) is really intuitive... I would naturally think that the type of Set{} is a set of "any" object (Set(Object) in MOF reflection terms or Set(OclAny) with AnyType extended to represent all objects). By the way, the fact that "Void" conforms to all types, does not mean all other types conforms to Void. Do you agree? So if Bag(A) means a Bag containing instances of A or subtypes of A (or more precisely types conforming to A), Then Bag(Void) should be a collection of only null values (????). I tend to think that a more consistent interpretation of validity of acc : Bag(A) = Bag{} is that Bag{} is, in this specific case, a shorthand for Bag(A){} ! A second - maybe better - interpretation would be: the type of Bag{} is a special Bag(Empty) type, which should not be confused with the Bag(Void) meaning a different thing (Bag with null values inside...) I think that in previous OCL 1.x, it was possible to interpret Bag{} as being of type Bag(Void) because it was prohibited to have invalid values in collections. And so Void and Empty were considered the same as a conceptual simplification. But now, with the differentiation between null and invalid and the possibility to have collections containing null values, then interpreting Bag{} as being of type Bag(Void) sounds like a bug (???). What's your opinion? (I am, maybe, a bit confused). Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 10 octobre 2008 21:37 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com From: "Christian W. Damus" To: ocl2-rtf@omg.org Subject: Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Date: Mon, 27 Oct 2008 17:00:21 -0400 X-Mailer: Apple Mail (2.929.2) X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - s014.panelboxmanager.com X-AntiAbuse: Original Domain - omg.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - zeligsoft.com X-Source: X-Source-Args: X-Source-Dir: Hi, Mariano, Thanks for your feed-back. I definitely have a new understanding of the problem. I still think the void element-type is consistent, but now for a different reason than before, which may be invalid. See some more replies in-line, below. Cheers, Christian On 27-Oct-08, at 2:00 PM, wrote: Hi Christian, Hereafter further discussion on issue 12953 (empty versus collection of void). Notice this resolution of this issue is not part of the coming first ballot. >>> The point is what is the type of the Bag{} literal expression that makes this expression consistent >>> with the collection type system. Exactly, and here's where I have a concern to consider that the type of Bag{} is Bag(Void). Bag(Void) is a type for bags that contain null values, whereas Bag{} is a specific value meaning a Bag with no contents. Since having null values and having no values are two different things, it would be strange that these two situations are represented by the same type... My interpretation is based on this definition in the OCL 2.0 spec, from the constraints on the CollectionLiteralExp metaclass (Section 8.3.7): -----8<----- [2] The type of a collection literal expression is determined by the collection kind selection and the common supertype of all elements. Note that the definition below implicitly states that empty collections have OclVoid as their elementType. context CollectionLiteralExp inv: kind = CollectionKind::Set implies type.oclIsKindOf (SetType ) inv: kind = CollectionKind::Sequence implies type.oclIsKindOf (SequenceType) inv: kind = CollectionKind::Bag implies type.oclIsKindOf (BagType ) inv: type.oclAsType (CollectionType).elementType = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) ----->8----- in which the type of a collection literal is built by progressively taking common supertypes, starting with OclVoid. I think that perhaps I went too far in applying the same process elsewhere. If you can demonstrate that it is consistent to say that the type of Bag{} is Bag(Void), I would be happy, but currently i'm not convinced. It looks more to me as being an hazardous or opportunistic simplification. Don't you agree? Actually, I don't agree. I think it is better for the language and tools if an empty collection literal is just another case of a more general pattern, as indicated by the constraint cited above. The computation of the collection literal's type is internally consistent. The problem, I think, is in the interpretation of the collection operation signatures, as you pointed out. Regarding the possible interpretation of Bag{} to mean Bag(SomeType){}, I agree this is not ideal. We should better avoid having a syntactic interpretation for Bag{}, since this could have non trivial impact on OCL parsers. >>> Also, introducing another type Empty exclusively for use in collections further >>> muddies the type system. What does this type mean as a classifier of values >>> sharing common features? It would seem to have the same meaning as Void, Sorry, I made a little mistake. Saying the type of Bag{} is "Bag(Empty)" does not make sence, since "empty" is not a kind of element in a collection. But saying the type of Bag{} is "EmptyBag", this would make much more sence. An EmptyBag would be a type representing empty bags, and as a matter of fact there is unique possible value named Bag{} (similarily to Void having a unique null value). This EmptyBag type is compatible to all Bags - and in that sence is not equal to Void which is compatible with all types. Ah, I see. That's an interesting idea. Some programming languages actually implement this approach. However, what would be the element type of these collection types? Would it be unspecified (null, not OclVoid)? That adds more special cases. It would also, perhaps, be necessary to redefine all of the inherited operations in these empty types. Now, concerning the expression:: Bag{}->including('a string') We need to have a clear way to state its validity. Maybe not. Perhaps this should just be an ill-formed expression, because String does not conform to Void. There are, after all, two plausible alternatives: (1) Bag{'a string'} (2) let b : Bag(String) = Bag{} in b->including('a string') Note that (2) works because Bag(OclVoid) conforms to Bag(String). Looking at the definition of "Bag::including" operation in the OCL spec, I see the signature: including (object : T) : Bag(T) Do you know what is the correct interpretation of this signature???, and how is computed the type of these expression calls? Heh heh ... no. This is a problem, because T is not explicitly defined in these definitions. - Is the type T in the return type necessarily the same type of the elements of the source collection? - Or is the type T the "best" type between the type of the source elements and the argument type? I have interpreted these signatures as generic operations, in which T is a template parameter of the operation unrelated to the element type T. T in an operation like Set::including would be constrained to be a supertype of the source set-type's element type. An invocation (avoiding the empty-collection problem) of (3) Set{null}->including('a string') would resolve the T type parameter to String as the best-fitting supertype of the element type that makes the same T substitution also work for the result type, which then Set(String). In the case of (4) Set{1}->including('a String') the only substitution for T that works is OclAny. This has been my assumption, admittedly baseless. However, it may be that the problem is not in the relation of T in the operation signature to the element type T, but in determining what is the element type T in the first place. One of the properties of collection types is the conformance of, say, Set(T) to Set(S) when T conforms to S. Thus, an instance of Set(T) is an instance of Set(S), so why not choose the operation signatures with the S binding instead of T when it is required by an operation call? Considering the (4), above, we can take it that the type of Set{1} is Set(Integer) according to the definition of CollectionLiteralExp. Set(Integer) conforms to Set(OclAny) according to the rules of collection-type conformance (Section 8.2.1). Therefore, we can invoke the including(object : OclAny) operation signature from Set(OclAny) on an instance of Set(Integer). Basically, I am arguing that the expression (6) below follows from the expression (5), which I think is rock-solid according to the current spec. I'm just not sure that this equivalence argument is valid. (5) let temp : Set(OclAny) = Set{1} in temp->including('a string') (6) Set{1}->including('a string') If we accept this argument, then my interpretation of (7) Set{}->including('a string') must be consistent. The problem with first interpretation is that the expression Bag{null,null}->including("A string") would yield to a value {null,null,"A string"} incompatible with Bag(Void), since a collection of voids cannot contain a String. Agreed. The problem wuth the second is that, contrary to ordinary operations, the statically computed type of the call expression would not be derived from the signature, as we could expect, but instead be derived from very specific rules. Right, but that is just a special case of OCL failing to account for the templateable-ness of operations in UML models. As it stands, template types and operations in a UML model (excepting those in the OCL Standard Library) are unusable with OCL. In any case, I'm not sure that it is necessary for these operations to be templates (as the collection types are) in order for this to work. Do you know if in the spec there is an unambigous definition of the type of this kind of expressions? Section A.2.5.6, for example, seems to correlate the type parameter t of the source element type, parameter types, and result types of the Set operations. However, the correlation of t to the "actual element type" of a collection instance is unclear. Because a Set(Integer) is a Set(OclAny), it is unclear which signatures apply. Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 17 octobre 2008 21:32 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Hi, Mariano, Yes, I will enjoy my vacation next week very much. Certainly other types do not conform to Void, otherwise we would have a generalization cycle. The perspective I have on the collection types is entirely driven by type conformance, avoiding as much as possible interpretations of syntax as short-hand for a more complete syntax. We need to be able to do: Sequence{1..10}->iterate(i; acc : Set(String) = Set{} | acc->including(i.toString())) and Set{}->including('a string') in which the result type of both expressions is Set(String), and I think we can do it without a syntax for explicitly constructing a collection of a given element type. It just requires that the type of Set{} be Set(Void) In the first expression, we initialize the variable acc which has type Set(String) with the value Set{}. If Set{} were of type Set(OclAny), then this would not be valid, because Set(OclAny) does not conform to Set(String). Rather, it is the other way around. Also, we need constructions starting with Set{} to be able to result in a value of type Set(String). One example is the including() operation in the second expression, which when the argument is of type String will only result in Set(String) if the source collection is of type Set(T) where T conforms to String. When T is Void (the source collection having type Set(Void)) makes this work nicely. OCL 2.0 also prohibits invalid in collections, so I'm not sure of the relevance of that. Also, introducing another type Empty exclusively for use in collections further muddies the type system. What does this type mean as a classifier of values sharing common features? It would seem to have the same meaning as Void, so why not just use Void? On the subject of null elements: clearly, Bag(Void) can only contain nulls, but nobody would ever declare a variable or property of type Bag(Void) because it just wouldn't be useful. But, that's not the point. The point is what is the type of the Bag{} literal expression that makes this expression consistent with the collection type system. Cheers, Christian On 17-Oct-08, at 1:59 PM, wrote: Hi Christian, I hope you enjoy your vacations this week. Here's some comments on your message about issue 12953. >>> I think it is sufficient to define the type of Set{} as Set(Void). I'm not sure considering that the type of Set{} is Set(Void) is really intuitive... I would naturally think that the type of Set{} is a set of "any" object (Set(Object) in MOF reflection terms or Set(OclAny) with AnyType extended to represent all objects). By the way, the fact that "Void" conforms to all types, does not mean all other types conforms to Void. Do you agree? So if Bag(A) means a Bag containing instances of A or subtypes of A (or more precisely types conforming to A), Then Bag(Void) should be a collection of only null values (????). I tend to think that a more consistent interpretation of validity of acc : Bag(A) = Bag{} is that Bag{} is, in this specific case, a shorthand for Bag(A){} ! A second - maybe better - interpretation would be: the type of Bag{} is a special Bag(Empty) type, which should not be confused with the Bag(Void) meaning a different thing (Bag with null values inside...) I think that in previous OCL 1.x, it was possible to interpret Bag{} as being of type Bag(Void) because it was prohibited to have invalid values in collections. And so Void and Empty were considered the same as a conceptual simplification. But now, with the differentiation between null and invalid and the possibility to have collections containing null values, then interpreting Bag{} as being of type Bag(Void) sounds like a bug (???). What's your opinion? (I am, maybe, a bit confused). Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 10 octobre 2008 21:37 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com From: "Christian W. Damus" To: ocl2-rtf@omg.org Subject: Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Date: Fri, 31 Oct 2008 16:59:36 -0400 X-Mailer: Apple Mail (2.929.2) X-AntiAbuse: This header was added to track abuse, please include it with any abuse report X-AntiAbuse: Primary Hostname - s014.panelboxmanager.com X-AntiAbuse: Original Domain - omg.org X-AntiAbuse: Originator/Caller UID/GID - [47 12] / [47 12] X-AntiAbuse: Sender Address Domain - zeligsoft.com X-Source: X-Source-Args: X-Source-Dir: Hi, Mariano, Find some more replies in-line, below. I don't mean to be difficult; I think I'm missing some important point. Thanks, Christian On 28-Oct-08, at 5:33 AM, wrote: Hi Christian, Thanks for your detailed response. The algorithm defined for computing the type of literals is very clear and effectively gives the type Bag(Void) to the literal Bag{}. The point here is that this way of computing the types of literals is "questionable" since the OCL spec 2.0 allows collection values to contain null values. BTW, saying that it is consistent or not is maybe a matter of judgement (that's why I'm just now saying "questionable") I'm probably missing something that I should be able to see, but how is the fact that collections can contain null relevant? Any collection type can contain null, because OclVoid conforms to all possible element types. Collections are immutable, so attempting to add anything that isn't null to a collection of the very restrictive type Bag(OclVoid) isn't a concern. I agree trying to go into a more precise typing (introducing these empty collections types) may have a non-trivial impact in the specification. So, we need to be careful here. So let's see if we can live with the simplification in the type system which is implied by the rule taken from 8.3.7. Agreed. So, an important point seems to agree on a correct interpretation of signatures of parameterized operations as well as the way the type of such call expressions are to be computed. I agree that this seems to be the crux of the matter. I think that an answer may lie in the inheritance hierarchy of the collection types. UML's template mechanism follows the template-instantiation model (C++-like, if you will), not the generic-type-variables model (Java-like). Thus, given the type Set(T) and substituting Cat for T, we actually get a new type Set(Cat) that is distinct from Set(T). Under normal template instantiation, Cat would substitute for T in the operation parameters, too, unless the operations define their own template signatures (I suppose they would have to, for operations like Collection::product that have a T2 type). However, this is not the template mechanism that we are proposing for the OCL collection types. If we assume similar semantics as UML's template instantiation in the OCL collection types, then I think we get a consistent picture. OCL's rules of type conformance for the collection types give the Set(Cat) type an inheritance graph (from subtype to supertype) that looks like this: Set(Cat) Set(Mammal) Set(Animal) Set(OclAny) Collection(OclAny) Collection(Animal) Collection(OclAny) Collection(Mammal) Collection(Animal) Collection(OclAny) Collection(Cat) Collection(Mammal) Collection(Animal) Collection(OclAny) All of Set(Cat), Set(Mammal), Set(Animal), Set(OclAny), Collection(Cat), Collection(Mammal), Collection(Animal), and Collection(OclAny) are distinct types from their templates Set(T) and Collection(T). Also, they all define distinct operation signatures. So, for example, Set(Cat) has all of the following operations available: - including(Cat) - including(Mammal) - including(Animal) - including(OclAny) Thus, we can construct a Set(Mammal) instance by Set{aCat}->including(aDog) because this operation call resolves to the including(Mammal) operation, not including(Cat). I think this may be a leap of logic that is not justified? Besides that we have anyway the core question raised by the issue: even if we decide to keep the rule for computing types of literals as it is (the type of Set{} is Set(Void)), is it consistent to allow OCL writers the capacilty to declare also empty literals with an explicit element type? (just as we Right. Sorry if I have taken the discussion off-topic. do in ordinary languages like Java). If yes, what advantages/disadvantages would it bring to Yes, but Java isn't a functional, side-effect-free language like OCL, with immutable collection types. OCL is more similar to a language like Haskell in this regard. the language? (avoiding explicit castings in tricky expressions like Set{}->including(aCat)->including(aDog) -- I want to build a set of Mammals This example doesn't have explicit casting. Neither does the more straight-forward Set{aCat, aDog} when building typed collections???, reuse in QVT context ??? and so on) QVT is an interesting question. It can't change the immutability of OCL's collections, but I understand that it has mutable dictionary and list types, which make a case for constructors with explicit element types. Of course, QVT can define its own constructor syntax for mutable collections. Cheers, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : lundi 27 octobre 2008 22:00 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Hi, Mariano, Thanks for your feed-back. I definitely have a new understanding of the problem. I still think the void element-type is consistent, but now for a different reason than before, which may be invalid. See some more replies in-line, below. Cheers, Christian On 27-Oct-08, at 2:00 PM, wrote: Hi Christian, Hereafter further discussion on issue 12953 (empty versus collection of void). Notice this resolution of this issue is not part of the coming first ballot. >>> The point is what is the type of the Bag{} literal expression that makes this expression consistent >>> with the collection type system. Exactly, and here's where I have a concern to consider that the type of Bag{} is Bag(Void). Bag(Void) is a type for bags that contain null values, whereas Bag{} is a specific value meaning a Bag with no contents. Since having null values and having no values are two different things, it would be strange that these two situations are represented by the same type... My interpretation is based on this definition in the OCL 2.0 spec, from the constraints on the CollectionLiteralExp metaclass (Section 8.3.7): -----8<----- [2] The type of a collection literal expression is determined by the collection kind selection and the common supertype of all elements. Note that the definition below implicitly states that empty collections have OclVoid as their elementType. context CollectionLiteralExp inv: kind = CollectionKind::Set implies type.oclIsKindOf (SetType ) inv: kind = CollectionKind::Sequence implies type.oclIsKindOf (SequenceType) inv: kind = CollectionKind::Bag implies type.oclIsKindOf (BagType ) inv: type.oclAsType (CollectionType).elementType = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) ----->8----- in which the type of a collection literal is built by progressively taking common supertypes, starting with OclVoid. I think that perhaps I went too far in applying the same process elsewhere. If you can demonstrate that it is consistent to say that the type of Bag{} is Bag(Void), I would be happy, but currently i'm not convinced. It looks more to me as being an hazardous or opportunistic simplification. Don't you agree? Actually, I don't agree. I think it is better for the language and tools if an empty collection literal is just another case of a more general pattern, as indicated by the constraint cited above. The computation of the collection literal's type is internally consistent. The problem, I think, is in the interpretation of the collection operation signatures, as you pointed out. Regarding the possible interpretation of Bag{} to mean Bag(SomeType){}, I agree this is not ideal. We should better avoid having a syntactic interpretation for Bag{}, since this could have non trivial impact on OCL parsers. >>> Also, introducing another type Empty exclusively for use in collections further >>> muddies the type system. What does this type mean as a classifier of values >>> sharing common features? It would seem to have the same meaning as Void, Sorry, I made a little mistake. Saying the type of Bag{} is "Bag(Empty)" does not make sence, since "empty" is not a kind of element in a collection. But saying the type of Bag{} is "EmptyBag", this would make much more sence. An EmptyBag would be a type representing empty bags, and as a matter of fact there is unique possible value named Bag{} (similarily to Void having a unique null value). This EmptyBag type is compatible to all Bags - and in that sence is not equal to Void which is compatible with all types. Ah, I see. That's an interesting idea. Some programming languages actually implement this approach. However, what would be the element type of these collection types? Would it be unspecified (null, not OclVoid)? That adds more special cases. It would also, perhaps, be necessary to redefine all of the inherited operations in these empty types. Now, concerning the expression:: Bag{}->including('a string') We need to have a clear way to state its validity. Maybe not. Perhaps this should just be an ill-formed expression, because String does not conform to Void. There are, after all, two plausible alternatives: (1) Bag{'a string'} (2) let b : Bag(String) = Bag{} in b->including('a string') Note that (2) works because Bag(OclVoid) conforms to Bag(String). Looking at the definition of "Bag::including" operation in the OCL spec, I see the signature: including (object : T) : Bag(T) Do you know what is the correct interpretation of this signature???, and how is computed the type of these expression calls? Heh heh ... no. This is a problem, because T is not explicitly defined in these definitions. - Is the type T in the return type necessarily the same type of the elements of the source collection? - Or is the type T the "best" type between the type of the source elements and the argument type? I have interpreted these signatures as generic operations, in which T is a template parameter of the operation unrelated to the element type T. T in an operation like Set::including would be constrained to be a supertype of the source set-type's element type. An invocation (avoiding the empty-collection problem) of (3) Set{null}->including('a string') would resolve the T type parameter to String as the best-fitting supertype of the element type that makes the same T substitution also work for the result type, which then Set(String). In the case of (4) Set{1}->including('a String') the only substitution for T that works is OclAny. This has been my assumption, admittedly baseless. However, it may be that the problem is not in the relation of T in the operation signature to the element type T, but in determining what is the element type T in the first place. One of the properties of collection types is the conformance of, say, Set(T) to Set(S) when T conforms to S. Thus, an instance of Set(T) is an instance of Set(S), so why not choose the operation signatures with the S binding instead of T when it is required by an operation call? Considering the (4), above, we can take it that the type of Set{1} is Set(Integer) according to the definition of CollectionLiteralExp. Set(Integer) conforms to Set(OclAny) according to the rules of collection-type conformance (Section 8.2.1). Therefore, we can invoke the including(object : OclAny) operation signature from Set(OclAny) on an instance of Set(Integer). Basically, I am arguing that the expression (6) below follows from the expression (5), which I think is rock-solid according to the current spec. I'm just not sure that this equivalence argument is valid. (5) let temp : Set(OclAny) = Set{1} in temp->including('a string') (6) Set{1}->including('a string') If we accept this argument, then my interpretation of (7) Set{}->including('a string') must be consistent. The problem with first interpretation is that the expression Bag{null,null}->including("A string") would yield to a value {null,null,"A string"} incompatible with Bag(Void), since a collection of voids cannot contain a String. Agreed. The problem wuth the second is that, contrary to ordinary operations, the statically computed type of the call expression would not be derived from the signature, as we could expect, but instead be derived from very specific rules. Right, but that is just a special case of OCL failing to account for the templateable-ness of operations in UML models. As it stands, template types and operations in a UML model (excepting those in the OCL Standard Library) are unusable with OCL. In any case, I'm not sure that it is necessary for these operations to be templates (as the collection types are) in order for this to work. Do you know if in the spec there is an unambigous definition of the type of this kind of expressions? Section A.2.5.6, for example, seems to correlate the type parameter t of the source element type, parameter types, and result types of the Set operations. However, the correlation of t to the "actual element type" of a collection instance is unclear. Because a Set(Integer) is a Set(OclAny), it is unclear which signatures apply. Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 17 octobre 2008 21:32 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue: Empty versus Void Hi, Mariano, Yes, I will enjoy my vacation next week very much. Certainly other types do not conform to Void, otherwise we would have a generalization cycle. The perspective I have on the collection types is entirely driven by type conformance, avoiding as much as possible interpretations of syntax as short-hand for a more complete syntax. We need to be able to do: Sequence{1..10}->iterate(i; acc : Set(String) = Set{} | acc->including(i.toString())) and Set{}->including('a string') in which the result type of both expressions is Set(String), and I think we can do it without a syntax for explicitly constructing a collection of a given element type. It just requires that the type of Set{} be Set(Void) In the first expression, we initialize the variable acc which has type Set(String) with the value Set{}. If Set{} were of type Set(OclAny), then this would not be valid, because Set(OclAny) does not conform to Set(String). Rather, it is the other way around. Also, we need constructions starting with Set{} to be able to result in a value of type Set(String). One example is the including() operation in the second expression, which when the argument is of type String will only result in Set(String) if the source collection is of type Set(T) where T conforms to String. When T is Void (the source collection having type Set(Void)) makes this work nicely. OCL 2.0 also prohibits invalid in collections, so I'm not sure of the relevance of that. Also, introducing another type Empty exclusively for use in collections further muddies the type system. What does this type mean as a classifier of values sharing common features? It would seem to have the same meaning as Void, so why not just use Void? On the subject of null elements: clearly, Bag(Void) can only contain nulls, but nobody would ever declare a variable or property of type Bag(Void) because it just wouldn't be useful. But, that's not the point. The point is what is the type of the Bag{} literal expression that makes this expression consistent with the collection type system. Cheers, Christian On 17-Oct-08, at 1:59 PM, wrote: Hi Christian, I hope you enjoy your vacations this week. Here's some comments on your message about issue 12953. >>> I think it is sufficient to define the type of Set{} as Set(Void). I'm not sure considering that the type of Set{} is Set(Void) is really intuitive... I would naturally think that the type of Set{} is a set of "any" object (Set(Object) in MOF reflection terms or Set(OclAny) with AnyType extended to represent all objects). By the way, the fact that "Void" conforms to all types, does not mean all other types conforms to Void. Do you agree? So if Bag(A) means a Bag containing instances of A or subtypes of A (or more precisely types conforming to A), Then Bag(Void) should be a collection of only null values (????). I tend to think that a more consistent interpretation of validity of acc : Bag(A) = Bag{} is that Bag{} is, in this specific case, a shorthand for Bag(A){} ! A second - maybe better - interpretation would be: the type of Bag{} is a special Bag(Empty) type, which should not be confused with the Bag(Void) meaning a different thing (Bag with null values inside...) I think that in previous OCL 1.x, it was possible to interpret Bag{} as being of type Bag(Void) because it was prohibited to have invalid values in collections. And so Void and Empty were considered the same as a conceptual simplification. But now, with the differentiation between null and invalid and the possibility to have collections containing null values, then interpreting Bag{} as being of type Bag(Void) sounds like a bug (???). What's your opinion? (I am, maybe, a bit confused). Regards, Mariano -------------------------------------------------------------------------------- De : Christian W. Damus [mailto:cdamus@zeligsoft.com] Envoyé : vendredi 10 octobre 2008 21:37 À : ocl2-rtf@omg.org Objet : Re: issue 12953 -- OCL 2 RTF issue I think it is sufficient to define the type of Set{} as Set(Void). Set(Void) conforms to any other set type because Void conforms to all other types, so an empty set can be used, for example, as the value of a variable initialization of any Set type. An expression such as Set{}->including("some string") results in Set(String) according to the least-common-supertype rule. But, this construction isn't useful, anyway, because one would simply write Set{"some string"} Did you have a specific case in mind that is unambiguous or ill-formed? For the reasons above, I don't see a need for a collection literal syntax that specifies the element type explicitly. This can only serve to constrain the types of elements that might be added to or removed from a collection, but as collections are immutable and operations always compute new collections of types computed by the arguments, this does not apply. Cheers, Christian On 10-Oct-08, at 1:50 PM, Juergen Boldt wrote: Date: Fri, 10 Oct 2008 13:49:57 -0400 To: issues@omg.org, ocl2-rtf@omg.org From: Juergen Boldt Subject: Fwd: OCL RTF 2.1: New 10 issues This is issue # 12953 From: ISSUE: Exact type of Set{} and missing Set(MyType){} literal definitions. Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. ********* Juergen Boldt Director, Member Services Object Management Group 140 Kendrick St Building A Suite 300 Needham, MA 02494 USA tel: +1 781 444 0404 x 132 fax: +1 781 444 0320 email: juergen@omg.org www.omg.org -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com -- Christian W. Damus Senior Software Developer, Zeligsoft Inc. Component Lead, Eclipse MDT OCL and EMF-QTV E-mail: cdamus@zeligsoft.com X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApoEAB/l5ErUnw4U/2dsb2JhbADVcIQ/BIFe Date: Mon, 26 Oct 2009 06:55:33 +0000 From: Ed Willink User-Agent: Thunderbird 2.0.0.22 (Windows/20090605) To: "'ocl2-rtf@omg.org'" Subject: Re: Issue 12953: Exact type of Set{} and missing Set(MyType){} literal definitions (ocl2-rtf) X-Plusnet-Relay: 9e22ac13d70eabafa3840ca25f152dae Hi Attached is a resolution for the semantics of Set{} with introduction of a Set(ElementType){initializers} syntax for precision. After consideration of the interesting earlier discussion it seems that there is no obvious type for Set{}. The type of Set{} should therefore be anything that doesn't give errors. So defining the type as Set(T) with T chosen to suit well-formedness bounds rather than equalities realises this. Regards Ed Willink 12953-SetLiterals.odt Disposition: Resolved OMG Issue No: 12953 Title: Exact type of Set{} and missing Set(MyType){} literal definitions Source: France Telecom R&D (Mr. Mariano Belaunde, mariano.belaunde@orange-ftgroup.com) Summary: It is not clear what is the concrete type of Set{}. Is it Set(Object)??, Set(Void)?? Also it seems there is no way to explicitly define an empty collection with a given type for the elements. Discussion: Discussion of this issue suggested a number of options: Option 1: The type of Set{} is Set(OclVoid) This does not work because Set{}->including(1) is an error since "1" or indeed anything other than null or invalid does not conform to OclVoid. Option 2: The type of Set{} is Set(OclAny) This does not work because acc : Set(Integer) = Set{}->including(1) is an error since Set(OclAny) is not compatible with Set(Integer). Option 3: The type of Set{} is a new built-in type EmptySet(ET) where ET is determined in some way. This does not work because given the RHS of acc : Set(Integer) = Set{}->including(1.0)->including(Classifier)->excluding(1.0)->excluding(Classifier) it is difficult to see how ET could be determined more precisely than OclAny causing the same problem as Option 2. Option 4: The type of Set{} is Set(null) Since Set{} and Set(null) have no precise OCL 2.1 semantics there is some discretion in defining them, but eventually a dynamic type validation is needed for acc : Set(String) = Set(null){getInitialValue()}. The impact on evaluation could be mitigated by synthesis of an oclAsType() in the Abstract Syntax Tree, but it is not possible to provide a static type for the CollectionLiteralExp. This option could work but requires revision of abstract syntax and evaluation specifications. Option 5: The type of Set{} is back-propagated For instance in acc : Set(Real) = Set{}->including(1)->including(-1) the type of Set{} is Set(Real) since that is the eventual result type. This involves unusual reverse semantics. Option 6: The type of Set{} is Set(T) with T chosen for well-formedness of the expression in which the Set{} is used. For instance in acc : Set(Real) = Set{}->including(1)->including(-1) the type of Set{} is initially Set(T) where T <= OclVoid. Propagation of the type to Set(T)::including(UnlimitedNatural) requires T <= UnlimitedNatural. Propagation to Set(T)::including(Integer) requires T <= Integer. Finally, propagation to the initializer requires Real <= T. Therefore any Real <= T <= Integer is well-formed. The lower bound, Set(Real), is preferred since it avoids many type conversions. It is also the same result as Option 5. Option 6 involves only additional forward static semantics has no impact on evaluation, no impact on parsing, and gives the intuitively correct OCL 2.1 results. ----- In order to impose a user-specified element type and so get static type checking of user intent, a collection element type can be specified as: acc : Set(Integer) = Set(Integer){} It is difficult to parse this in OCL 2.1 because Set is not a reserved word and so lookahead is required to determine whether Set(someName) is the start of a StringLiteralExpCS or an OperationCallExpCS, with someName perhaps being a complicated nested type/value ambiguity. Issue 14357 introduces the concept of a restricted word preventing the unqualified use of Set as an operation name. The extension is then straightforward. Revised Text: In 7.5.11 after A bag: Bag {1, 3, 4, 3, 5 } add The element type may be specified in parentheses. This ensures that the types of elements can be statically checked. Bag(Real) {1, 3, 4, 3, 5 } In 8.1 CollectionLiteralExp replace Note that the definition below implicitly states that empty collections have OclVoid as their elementType. by Note that the definition below defines only an upper bound on the elementType. The usage of the CollectionLiteralExp defines a lower bound. If the elementType is not explicitly specified, the elementType must be chosen to ensure the well-formedness of the elements of the CollectionLiteralExp and the usage of the CollectionLiteralExp. For instance in acc : Set(Real) = Set{1}->excluding(-1) Set{1} is well formed for any type Set(T) where T . UnlimitedNatural. Well-formedness of the excluding operation call requires T . Integer, and well-formedness of the initializer requires Real . T. The overall expression is therefore only well-formed if Real . T . Integer. Either Set(Real) or Set(Integer) are well-formed. The most general type, Set(Real), is recommended since it minimizes type conversions and can often be easily deduced by considering the result type. In 8.1 CollectionLiteralExp replace inv: type.oclAsType (CollectionType).elementType = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) by inv: let elementType : Type = part->iterate (p; c : Classifier = OclVoid | c.commonSuperType (p.type)) in elementType.conformsTo(type.oclAsType (CollectionType).elementType) In 9.3 CollectionLiteralExpCS replace CollectionLiteralExpCS ::= CollectionTypeIdentifierCS .{. CollectionLiteralPartsCS? .}. Abstract syntax mapping CollectionLiteralExpCS.ast : CollectionLiteralExp Synthesized attributes CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast CollectionLiteralExpCS.ast.kind = CollectionTypeIdentifierCS.ast Inherited attributes CollectionTypeIdentifierCS.env = CollectionLiteralExpCS.env CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env Disambiguating rules [1] In a literal the collection type may not be Collection. CollectionTypeIdentifierCS.ast <> .Collection. by [A] CollectionLiteralExpCS ::= CollectionTypeIdentifierCS .{. CollectionLiteralPartsCS? .}. [A] CollectionLiteralExpCS ::= collectionTypeCS .{. CollectionLiteralPartsCS? .}. Abstract syntax mapping CollectionLiteralExpCS.ast : CollectionLiteralExp Synthesized attributes [A] CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast [A] CollectionLiteralExpCS.ast.kind = CollectionTypeIdentifierCS.ast [B] CollectionLiteralExpCS.ast.parts = CollectionLiteralPartsCS.ast [B] CollectionLiteralExpCS.ast.kind = collectionTypeCS.ast.kind [B] CollectionLiteralExpCS.ast.type = collectionTypeCS.ast Inherited attributes [A] CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env [A] CollectionTypeIdentifierCS.env = CollectionLiteralExpCS.env [B] CollectionLiteralPartsCS.env = CollectionLiteralExpCS.env [B] collectionTypeCS.env = CollectionLiteralExpCS.env Disambiguating rules [A] [1] In a literal the collection type may not be Collection. CollectionTypeIdentifierCS.ast <> .Collection. [B] [1] In a literal the collection type may not be Collection. collectionTypeCS.ast <> CollectionType *******