!define within a macro destroys reference

0 votes
asked Dec 6 in Bug by Remco Boerma

See for yourself.

@startuml
!definelong with(x)
  !define _ x
!enddefinelong

with(a)
note over wrong: a : _
with(b)
note over wrong: b : _
with(a)
note over wrong: a : _


!define _ x
note over right: x : _
!define _ y
note over right: y : _
!define _ x
note over right: x : _
@enduml

Produces:

The second `with(a)` produces a reference to `b`, not only from `_` but it wrongly changes `a`

When the same technique is used without macro substitution the right colum is produced, as would be expected. 

1 Answer

0 votes
answered Dec 7 by mgrol (2,560 points)

Hi,

yes and no. Yes because it looks like it, but no because it is a homemade problem from you that comes from the way macros work. To summarize: You replaced your a already with b and you work with a chain of string substitutions. I hope the image makes it more clear, look at the variables in the left comments:

http://www.plantuml.com/plantuml/uml/dPB1QiCm44Jl-ef9UccWN-1J-Wqjv58mAsiTYQwb8AyJ--zhDKqQ22Mu1nsqZ6RUBDhsIbc7JipASHiYIufxd8BwvtgiDvSfQinNi-BeVcN6nAGCuLQHMfnoUVgqyq7vhKkVNE7TSsRGVDGpsYIIJc4M7Ia7ii8zQX2i-SwZpTal7JcVpIhmUE16GQXGFqpRUL9GemE9J0WzIdg5IuKXEivzamhHoqU4Be6pTt2uqjd_qrtX27On4zqpBTeO7a7PHOlwaUAGqppiYfiM-oaD8CbCRaBcWr333dr78bY_hb6gmCAOcxystXJBOU_rsciilMwKqv_AgIWNU6uvkg6JBm00

I hope it is more clear now. If you still wonder why does your right lifeline works. You always start with a clean set of variables and you have no interchained substitutes. You need to think more globally. There is currently no local scope of these substitutions.

@plantuml: Therefore, this is IMHO not a bug.

BR,

Michael

commented 4 days ago by anonymous
Thanks Michael,

I get what's going on, and then i wonder why the inconsistency would allow two different lines to be possible. Wouldn't the last !define _ x assign y to x instead of x? Why is the functionality of !define different when used in a macro and not in the main code?
Can you elaborate more on the clean set of variables?

I would love to use something like:

with(something):
  send(_,value)
with(something_else):
  send(_,another value)

or better even:

with(something):
  send(value)
with(something_else):
  send(another value)

which will use _ as it is set by the with macro.
I can turn this into a stack and use copy and paste between different schema's, which would serve me a lot, and give cleaner code because there's less references and more scope to use.

Looking forward to you reply
commented 4 days ago by mgrol (2,560 points)
Hi,

I am not the developer of plantuml and I didn't look into the code. Please see  the link below I added some more notes to the original sequence.
Define in Macro does:
1) subsitute _ with a
2) subsitute  a with b
It is like a queue.
For the defines not within the macro
1) subsitute _ with x
2) subsitute a new _  with < because the _ from 1) is already x
It's rather difficult to grasp.

Think about using macros not to define other macros but to actually do something directly.
Global string replacements are difficult to handle.

I adopted the example from above and added some lines. I defined a new macro newWith() in which I can hand over the participant (WHERE) and the value as WHAT. Therefore, I am able to do the stuff without defining a string substitute on a global level.

http://www.plantuml.com/plantuml/uml/nPJFofj05CNtynJd-xgfO1VjKh0aq42wRGDk2ZBgDGuTlM4Seq8Uliu4bJQBOF_GnQ3UkPxpcyjXTgsLndQr5Yy5bQeXpSqPlRBLstH8WxcA5DEdUA6cMDk4QDWID9KMNA8txjStIQKiVQtvEqKuLMG8Sbgs8fIiDVTgQhfAesIcgKKAYKnuFndSzVXAvYuMWOOBvHOI4TAdRaabBMHkEwdr2DN2kKUOZz0r1PasPqSKVcjWjy1b3t1OwBBVfrlW9YFFz6S3mwQ9uHbKjc5G2pykXgTYxTIian-vWzI6P372q4NBd0gqzUI8r_shpneoYDljvfTdDkfSUMZ_iZrK0yOrkXZ-dkWwS2-op7lmyrujntzlENhB_t1A4SSuSe_FwBdJ1Gg6ieZZdwwGXlh4XJGv7huSmkIuFmK2mAhiDnPbru38FroRtyIxZtFN9qRBDTdAqQfxpcgP6_xrIffjFNVuFbWAFltXX-2nOpSfTBN-0G00

Macros should be used (in my opnion)  like methods from applications/services. If you try to do something in your application by defining everything as global variables it will be pretty difficult to see all the side effects when you changed one of your globals. If you wrap your actions into macros as I did in the example above, it will get easier.

If you need a working example for a sequence diagram send me a PN with your email address.

BR,
Michael

BR,
Michael
commented 3 days ago by Remco Boerma (100 points)
Thanks Michael, that's useful.
Would love that sequence diagram as that's what i'm mostly interested in. I'll pm you my email.

I'm using macro's on a global level to easy the use of plantuml and use a more domain driven set of macro's. It would be great if some could interact on the global level.

Another question, in the same line: would you know of any way to disable macro expansion on a per use basis? Is there a way to escape a macro name in that sense?

Regards,
Remco
commented 3 days ago by mgrol (2,560 points)
Hi,
I already answered your PM via email, so you should have received an email shortly after 11am CET. I do have a set of globals as well as you can see in my example e.g. for the colors. However, I warned you about the side effects of changing these variables due to the side effects.
I don't really get your last questions. I'll try to answer and maybe it is the answer you were looking for. There is currently no possibility like
!definelong macro(value,boolean)
!if(boolean)
    doSomething()
!else
    doSomethingElse()
!endif
!enddefinelong
I don't know if this is somehow close to what you were asking for. If not could you maybe sketch what you expect?

Btw: This is a discussion we opened here http://wiki.plantuml.net/site/plantumlshell. However, this discussion just started.

BR,
Michael
...