eclipse-ocl / org.eclipse.ocl

Eclipse Public License 2.0
0 stars 0 forks source link

[analyzer] Source Collection Literals for arrow operations must be resolved at run-time #500

Closed eclipse-ocl-bot closed 1 hour ago

eclipse-ocl-bot commented 1 hour ago

| --- | --- | | Bugzilla Link | 299841 | | Status | CLOSED FIXED | | Importance | P3 normal | | Reported | Jan 16, 2010 06:03 EDT | | Modified | May 29, 2012 13:22 EDT | | Version | 3.0.0 | | Blocks | 318248 | | Reporter | Ed Willink |

Description

AbstractOCLAnalyzer.getCollectionSourceExpression currently creates a Set{x} source for a non-collection x in x->f following 7.5.3 of the spec.

However the spec also states in 11.2.3 that null is converted to Bag{} so that null->isEmpty() is true.

The null-ness cannot be known in general at compile time so the collection literal can at best be selectively synthesized at compile time. Better to never synthesize at compile time so that the run-time evaluation is consistent.

[The specification could be much clearer.]

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on Jan 29, 2010 02:46

The Bag/Set distinction is probably not as alluded to by the specification: Rather

Where static type analysis has resolved a suitable CollectionKind, a null value is converted to an empty collection of that kind, or a non-null value to a single element collection of that kind.

Where static analysis has not resolved a suitable CollectionKind (including Collection), a null or singleton value is not converted to it.

This:

null->size()

has no statically determined type and so should be an analysis failure.

Whereas:

let n : Sequence(String) = null in n->size()

is ok because the null value has a static type.

Similarly:

let n : Sequence(String) = null in n->excludesAll(null)

is ok because the excludesAll has a statically determined type for conversion of the argument.

eclipse-ocl-bot commented 1 hour ago

By Alexander Igdalov on Jan 29, 2010 05:35

(In reply to comment #1)\ Hi Ed,

I agree: null->size() must be a failure.

let n : Sequence(String) = null in n->size() let n : Sequence(String) = null in n->excludesAll(null)

I think both expressions must be evaluated to invalid since its a feature call on null. Do you agree?

The same should be true about iterators.

let n : Sequence(String) = null in n->collect(i : String | i.foo())\ must be invalid too.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on Jan 29, 2010 11:32

(In reply to comment #2)

let n : Sequence(String) = null in n->size() let n : Sequence(String) = null in n->excludesAll(null)

I think both expressions must be evaluated to invalid since its a feature call on null. Do you agree?

If we were designing a new language, this is a design decision we could discuss. [I might agree with invalid but would want to research the ergonomics further.]

However we are endeavouring to make maximally compatible sense of OCL 2.x, where in 11.2.3 we have

"However, by virtue of the implicit conversion to a collection literal, an expression evaluating to null can be used as source of collection operations (such as 'isEmpty')."

This does not appear to contradict anything else so the two expressions in question must return valid results (0 for the first, true for the second.)

The next sentence of 11.2.3

"If the source is the null literal, it is implicitly converted to Bag{}"

clearly cannot be correct. e.g.

let y : Set(String) = null, z : Set(String) = null in y->symmetricDifference(z)

should be successfully analyzed, so when evaluated the null values of y and z must be promoted to Set{} not Bag{}.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on Jan 29, 2010 12:56

I changed my mind while walking the dogs. I agree with you.

There is a relevant analogy with null and empty String, which some tools try to treat as equal. In OCL, a null String is completely different to an empty String. Use of a null (undefined) String is generally invalid.

The conversion of null to Bag{} attempts to make a null and empty Collection equivalent. If we follow through the unpleasant corrollaries of this we can perhaps overturn 11.2.3 as a bug fix avoiding the need to wait for OCL 3.0.

For instance, type consistency requires null to be converted to the more appropriate of Bag{}, Set{}, OrderedSet{}, Sequence{}, Collection{}. So presumably null = Bag{} and null = Set{} therefore Bag{} = Set{} violating the definition of Collection::=().

For null->empty() to return a valid value violates the principle that the Collection is undefined, therefore it can have no defined size.

Even more fundamentally, why are operations on undefined Collections valid when operations on undefined non-Collections are invalid?

--

The motivation for this implicit conversion was to ensure that complex iterations work naturally over empty collections. There is no need for them to work over NullLiteralExp if the normal behaviour of empty collections does not produce a NullLiteralExp. All our thought examples have required a direct [null-size()] or indirect [let n : String{} = null in n->size()] construction of a NullLiteralExp. I don't think that a NullLiteralExp arises in sensible exprssions on sensible meta-models, so I suspect that the original motivation was associated with overcoming a limitation in a particular meta-modelling approach that used null for empty collections. NB EMF always (lazily) creates empty collections unless the feature specifically supports unsettable.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on Jun 18, 2010 16:59

Summary of foregoing discussion.

Conversion of any form of implicit or explicit null to an empty collection of any kind seems inappropriate and requires further contribution to OMG Issue 14981.

Any attempt to use null as a collection should give a static error for an explicit null, and an invalid result for an implicit null.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on Mar 14, 2011 16:41

Treating -> on aNonCollection as a shorthand for

aNonCollection.oclAsSet()->

removes all the magic and the need for dynamic evaluation.

In the pivot model the analyzer synthesizes the above call to OclAny.oclAsSet() whose implementation can be defined to give the chosen semantics and overloaded if appropriate for dynamic dispatch on null.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on May 27, 2011 06:40

Resolved for Indigo is 3.1.0 not 3.2.0.

eclipse-ocl-bot commented 1 hour ago

By Ed Willink on May 29, 2012 13:22

Closing all bugs resolved in Indigo.