Monday, March 8, 2010

Just a little bit about "Simple OCL"

I just come back from Cambodia, and it has been a wonderful time to think about how to simplify modeling technologies ;-) ;-) I have focused on the language we use everytime to make automation tools with modeling technologies : OCL

The OCL OMG specification has been released several times in the last 5 years. We use OCL at Obeo to make automation tools with Acceleo and ATL, and we think that OCL queries should be as short as possible to improve the template readability... We have defined several common OCL queries that are always used in our tools. We would like to have these queries in the standard library because we must define them each time we have to make a new tool with Eclipse modeling technologies.

Here are some ways to simplify OCL I have discussed a couple of days ago with OCL experts. It isn't really easy to think about how to improve OCL because there were a lot of work on it and we can't change everything for compatibility reason. But, it is really possible to improve the language with little thing without breaking the compatibility.

The first way for me to improve OCL is to add in the library the common stuff we define every time in our code generation and model transformation projects. When we navigate on models, the main things we do is to navigate around the current node, up and down : to get the children, the children of the children, the parent, and the siblings... OCL should propose shortcuts to go in these directions... Do we need a new function in the library or a new syntax element like in XPath? I don't know, but both will be better than what we have today. We often need to filter the types of the objects we would like to keep during this navigation. We spend a lot of time to explain how to get some specific children of the current node. As an example, here is the expression we have to write in OCL to get the descendant list of an object where we only want to keep the named elements :
myCollection->select(oclIsKindOf(NamedElement))-> collect(oclAsType(NamedElement))


It would be strictly equivalent to eAllContents(NamedElement) if the query eAllContents(OclType) was defined. Of course, we can define this query in one common library for all the projects of my company. I'd prefer to have such a useful service in the OCL standard library to prevent naming ambiguities. Today, everybody gives its prefered name to this query and it isn't possible to understand easily the work of someone else.

For the same reason, we would like to simplify the syntax used to make filters on collections. myCollection->select(name <> ' ') could be replaced by myCollection[name <> 0]. The "select" function is used everywhere in OCL queries. This new shorter syntax could really improve readability. To be extreme, [...] should be the way to filter every kind of thing, for example if I want to filter the types of the objects in the current collection, I would write something like that :
myCollection[Class].name

myCollection[Class or Interface].name

In the second example, "name" could compile because there is a common attribute called "name" both in "Class" and "Interface". The goal is to replace the oclAsType() function as often as possible.

Another way to improve the readability of the OCL expressions is to add operators like '+' or '-' between collections :
(property + method)->size()
(list - element)->size()
list + element

Some researchers think that we can already do that with operator overloading, but to go further, we would probably need generics in OCL.

The opinions of the OMG guys would be interesting ;-)

5 comments:

Sven Efftinge said...

Hi Jonathan,

does OCL have something like generics? How would you specify the query eAllContents(OclType) so that it returns a typed list through its static signature?

Btw. in Xpand we have typeSelect(Type) define on collections for that matter and I can agree that something like this is used frequently.

The other proposal with the array syntax being mapped to select on lists looks similar to the apply() semantics in Scala. That is, when an object 'x' has a defined method 'apply(Y)' one can write 'x(myY)'.
That's a nice and powerful concept.

Cheers,
Sven

Mika said...

Hi Jo,

I'm a bit confused about your proposal of a syntax for the select().

To sum up your idea, you would like to put the expression between square bracket instead of as an argument to the "select". Thus, any myCollection->select(xxx) would be replaced by myCollection[xxx].

My first issue is that you didn't talk about the full syntax of the select operation (with the explicit definition of the iterator). I think it is important to keep something similar, then myCollection->select(v | xxx) would become myCollection[v | xxx].

My second issue is the lack of consistency about your (well-founded) desire to replace myCollection->select(oclIsKindOf(NamedElement))-> collect(oclAsType(NamedElement)). But, if we follow the pattern exposed few lines before, we would have myCollection[oclIsKindOf(NamedElement)]->collect(oclAsType(NamedElement)) and not myCollection[NamedElement]. What I find confusing here is that we are not talking about making select() concise but select(oclIsKindOf(XXX))->collect(oclAsType(XXX)) (where XXX is an instance of OclType). This is a big difference and mixing this concept with the shorthand for select() is, imho, confusing.

I proposed two solutions:

- a different syntax shorthand for myCollection->select(oclIsKindOf(XXX))->collect(oclAsType(XXX)). For instance, myCollection (this is an idea of syntax after 2sec of standalone brainstorming, so feel free to propose anything else).
- implementing generics in OCL.

Regards

Mika said...

Argh, Google strips my proposal for the syntax shorthand.

It was to put the type in angle brackets:
myCollection < XXX >

Bureck said...

Hi,

I agree that OCL definitely should provide a larger set of navigator-functions and shortcut notations. The QVT/OM standard already includes a filter-syntax similar (although not as expressive) to the one you suggested. Unfortunately the operation-semantics is defined in using imperative QVT/OM language features (see chapter 8.2.2.7 ImperativeIterateExp in the QVT spec).

Max

Jonathan Musset said...

There aren't "Generics" in the current version of OCL. But, it will probably change...
The next version of the specification is coming soon...
I think that I was not really clear... You can already write something like p.eAllContents(EClass).eAllAttributes() with OCL, the returned type of eAllContents(EClass) is a collection of EClass and eAllAttributes() is defined on EClass, so it compiles if the eAllContents query exists... My problem is that everybody gives a different name to the "eAllContents" query and we often write typecasting (it's awfull because there are a lot of oclAsType and oclIsKindOf occurences)

Mikael, I agree with your myCollection[v | xxx] but, in my opinion, the '|' must be optional...
The "angle brackets" is also a good idea...

I know that QVTo defines such a syntax with brackets [...] but,
Max, Do you know how it is possible to have this navigation shortcut in QVTo but not in OCL?
Both QVTo and OCL are OMG specifications... Maybe, we should have a standard for the OMG standards, or interoperability between the OMG specifications... But we know that it isn't so easy... ;-)

Cheers,

Jonathan