Multiple Function calls in Text: only one processed

0 votes
asked Apr 17, 2020 in Bug by vogtadi (140 points)

Issue

Using multiple functions in a text only calls the first occurrence.

To reproduce

  1. Create a function

  2. Use that function in a text ONCE → OK

  3. Use that function multiple times in the SAME text → only the first occurrence is calling the function.

Note

  • Diagram Type does not matter. Example shows a class diagram, but as this seems to be an issue in text processing, other diagram types are affected as well.

  • It does not matter, whether it's the same function or two separate functions.

Example

@startuml
!function txthighlight($text)
<font color=blue>$text</font>
!endfunction

class "SomeClass" as x {
  + Member1: Does txthighlight("blue") Stuff
  + Member2: Does txthighlight("blue") and txthighlight("blue") Stuff
}
@enduml

1 Answer

0 votes
answered Apr 17, 2020 by plantuml (257,860 points)

Thanks for the report.

We probably made a confusing choice with "void function" and "return function". (see https://plantuml.com/en/preprocessing ).

I think we should use a fresh new keyword for "void function" (what about "procedure" for example?) to emphasize the difference with "return function" which must return a value.

So you example should be written this way:

@startuml
!function txthighlight($text)
!return "<font color=blue>" + $text + "</font>"
!endfunction

class "SomeClass" as x {
  + Member2: Does txthighlight("blue") and txthighlight("blue") Stuff
}
@enduml

So we are going probably to slightly change the preprocessor:

  • !function will have to !return a value
  • !procedure (former "void function") won't be able to return anything. They will only output text

I think it will make things more clear to people. What do you thing about it ?

commented Apr 17, 2020 by vogtadi (140 points)

Indeed I was not taking too much attention to the difference of these two types of functions. I noticed that you can !return a value, but was not aware of the implications. As both ways seem to output text in the end, I didn't are too much. My bad!

Rewriting as you suggested works completely fine and as expected.

However, would the issue not be the same with a future !procedure definition? After all the issue, I had was not that the void function I implemented did not result in outputting the correct text, but the second occurrence was not "seen" by the parser.

So the point (in the documentation) should be that

  • A void function or !procedure is a subroutine, which can produce text itself and cannot be used as part of an expression.
  • !function is a subroutine, which produces a result, which can be used in any expression (similar to a variable).
If my observations are correct, a function (with a !return value) does behave identical to a void function if used outside of an expression. That was probably one of the reasons, which I thought there is no real difference.
commented Apr 17, 2020 by plantuml (257,860 points)

We've just published a new beta http://beta.plantuml.net/plantuml.jar which uses !procedure now.

This will be offically released in next version. It has a slight impact on some existing diagrams, because some !function definitions have to be changed into !procedure definition. But I think it's more clear this way, and that it's not too late to do this important move.

Your observation are correct, and we will update the documentation after the official release.

Some additional notes :

  • It is true that a procedure call should not be used inside an expression. However, in some cases, it could be usefull to put some header text just before the procedure call. This explains the behavior of your original post. However, I agree that this is confusing, and maybe we are going to remove this feature in the future.
  • A main difference between return function and procedure is that procedure can output several text lines while return function can only return one String or one Integer. Of course, you can put carriage return in this single String, but it still one single Strong.
  • The degenerate case of procedure with one single line looks very similar to a return function. As you state, this degenerate procedure does behave almost identical to a return function, except that you cannot put several procedure call on a single line, while you can for return function. As conclusion, if you define a procedure which has a single line, it probably means that you should declare a return function instead.
Thanks for your contributions that help us to improve the preprocessor specification !
...