Type issue when checking for diagram existence

Hi I’m using capella 1.4.2 and M2Doc 3.2.0 and I encountered weird behaviour for the function isRepresentationDescriptionName().

Most of the time it worked completely fine in my model and document but after I tried to use it to export LABs something weird happened. If I use
self.containedLogicalArchitectures.ownedLogicalComponentPkg.isRepresentationDescriptionName('Logical Architecture Blank')
to check for existing LABs I get an error and the validation file shows
The predicate never evaluates to a boolean type ([Sequence(boolean)])

I interpret this as the function returning a Sequence(boolean) instead of a boolean (which should not happen according to documentation). Now, this problem can be solved by adding ->first() to extract the boolean from the Sequence. However, the error is thrown for all subsequent uses of isRepresentationDescriptionName() regardless of diagram types or usages.

If I do not check for LABs, everything works. If I use the code block, everything AFTER it throws the same Sequence(boolean) error. Currently, I “bypass” the issue in my model by not checking if the diagram exists. I just directly loop the representationByDescriptionName() for the corresponding diagram type…

Below I attached the code I’m using in a minimal test case to reproduce the problem. Uses 1 logical function, one LAB and one LFBD.

// Works fine
m:for LF | self.containedLogicalArchitectures.containedLogicalFunctionPkg.ownedLogicalFunctions
m:LF.name
m:if LF.isRepresentationDescriptionName('Logical Function Breakdown')
m:for rep | LF.representationByDescriptionName('Logical Function Breakdown')
m:rep.name
m:endfor
m:endif
m:endfor

// Introduces problem
m:if self.containedLogicalArchitectures.ownedLogicalComponentPkg.isRepresentationDescriptionName('Logical Architecture Blank')
m:for rep | self.containedLogicalArchitectures.ownedLogicalComponentPkg.representationByDescriptionName('Logical Architecture Blank')
m:rep.name
m:endfor
m:endif

// Does not work anymore (but works if I delete the previous code block)
m:for LF | self.containedLogicalArchitectures.containedLogicalFunctionPkg.ownedLogicalFunctions
m:LF.name
m:if LF.isRepresentationDescriptionName('Logical Function Breakdown')
m:for rep | LF.representationByDescriptionName('Logical Function Breakdown')
m:rep.name
m:endfor
m:endif
m:endfor

The AQL expression you are writing creates a collection of objects:

self.containedLogicalArchitectures

At this point you have a collection of objects as the name containedLogicalArchitectures suggest. You can check this by looking at the EReference:

self.eClass().eAllStructuralFeatures->select(f | f.name = 'containedLogicalArchitectures')

The 0…* means many values.

Then AQL continue the evaluation it will collect every navigation result in a Collection. After the ```
isRepresentationDescriptionName() call you get a Collection of Boolean. And the condition of the if must be a Boolean (scalar). That the reason for your error message. Using the first service is not a good idea here, you probably want to know if there is at least one true value in the Collection:

...->exists(b | b)

The last block should still be working even if the second block fails. Do you have the corresponding error message ?

Thanks, that explains the first part well!

Yes, the last block shows the same error message: The predicate never evaluates to a boolean type ([Sequence(boolean)]). Although it shouldn’t.

This message make sens for this line:

m:if self.containedLogicalArchitectures.ownedLogicalComponentPkg.isRepresentationDescriptionName('Logical Architecture Blank')

But it doesn’t make sens on this line:

m:if LF.isRepresentationDescriptionName('Logical Function Breakdown')

Can you check the message location ?

An other way to do this would be to check if the list of representations is empty or not:

{m:let representations = LF.representationByDescriptionName('Logical Function Breakdown')}
  {m:if not representations->isEmpty()}
    {m:for rep | representations}
      ...
    {m:endfor}
  {m:endif}
{m:endlet}

The let statement is used to cache the list of representations. It’s might be easier to read also.

The message location is the third block, even if it doesnt appear in the second block (for example, by using your suggested ->exists(b | b) to check if there is at least one true value in the returned collection).

If I use your suggested solution, I do not get the error message for the third block but I find this unsatisfactory.

If we go to my original example, the code I use is basically the following. Running Block A also prints out the name of the one existing diagram, so I would expect it to still be there when Block A runs a second time.

Block A -> No error
Block B -> Error
Block A -> Error

If I now use either first() or exist() then I get

Block A -> No error
Block B -> No error
Block A -> Error

If I use your let solution (Block C) instead of Block A it works fine, proving that the list of representations is not empty (implicitly proven by Block A as well if we look into the generated document)

Block A -> No error
Block B -> No error
Block C -> No error

But if copy paste the first block at the bottom again the error re-appears

Block A -> No error
Block B -> No error
Block C -> No error
Block A -> Error

If I delete Block B it works fine

Block A -> No error
Block C -> No error
Block A -> No error

That was a lot of cases. Essentially, I’m happy with finding workarounds but the error I experience should not occur. Because I get the impression that calling isRepresentationDescriptionName() on a collection permanently changes its behaviour for all subsequent calls which is of course undesirable.

I think something else is getting M2Doc of tracks here. Not sure what in you case but:

  • Word sometime replace quotes while copy/pasting
  • text areas might also break M2Doc parsing

If want me to have a look at your template, you can open an issue here and attach your template. Also add a link to this discussion.

I created an issue and attached my example model: https://github.com/ObeoNetwork/M2Doc/issues/454

Thank you, I’ll have a look.

Copyright © Eclipse Capella, the Eclipse Capella logo, Eclipse and the Eclipse logo are Trademarks of The Eclipse Foundation.