Re: Unexpected variable scoping rules if #include is used within a #macro
Attila Szegedi <[email protected]>
| Newsgroups | gmane.comp.web.freemarker.user |
|---|---|
| Message-ID | <[email protected]> |
Yep, creating libraries of macros and then pulling them in using [#import] is the recommended way of creating and using reusable template elements. Attila. On 2009.05.04., at 16:19, Newman, John W wrote: > Daniel & Attila, thank you both for responding. > > I didn't realize [#include wasn't scoped by the bounds of the > physical text file. The way it works does make perfect sense now > that I am aware of it. I think [#macro and [#local is what we > should be using everywhere instead. I just text searched through > all of our templates and the bug we found on Friday appears to be > the only occurrence of this misuse of [#include. So eventually > we'll rake everything in to use [#macro and [#local in but for now > I'm just going to blank out the variable. > > Thanks again > > > -----Original Message----- > From: Daniel Dekany [mailto:[email protected]] > Sent: Saturday, May 02, 2009 6:31 AM > To: FreeMarker-user > Subject: Re: [FreeMarker-user] Unexpected variable scoping rules if > #include is used within a #macro > > Saturday, May 2, 2009, 11:27:36 AM, Attila Szegedi wrote: > >> Sounds like [#embed] from 2.4 would do what John expects it would - >> do >> you agree Daniel? > > I don't think so... He rather wanted something like #include + #var, > since he wants all the variables that are visible at the place of > #include to be visible inside the included template, yet he don't want > the variables created in the included template to have any effect on > the variable set of the including template. Anyway, I think that's > quite a bad idea in most applications, exposing local variables to > another template... and *maybe* John's application is not an exception > either. (In several such cases it will certainly turn out that > exposing the variables of the including place wasn't that important > thing originally, the intent was rather that the developer wants many > smaller files (and hence possibly leveraging some template-loading > facilities, like "acquisition") instead of a few big macro libraries.) > >> Maybe we could implement it for 2.3 as well (not sure how much of the >> underlying 2.4 machinery would need to be ported though, so it might >> not be worth the effort). > > I'm not even sure 2.4 worth the effort... or better said, if it's the > right place to invest our energies into. We have a significant 2.3.x > user-base. You think they will suffer with migrating ti 2.4.x? Not > many of them, I think. People will rather just start using 2.4 in new > projects. But then, well... while we have this visibility as we have > now, shouldn't give them something that indeed fixes the several > issues with the overall architecture? That will be unpopular in short > term, but I'm certain not on the long term... > >> Attila. >> >> On 2009.05.01., at 23:50, Daniel Dekany wrote: >> >>> Friday, May 1, 2009, 10:46:33 PM, Newman, John W wrote: >>>> Hello, >>>> >>>> We are using FM 2.3, and we've spotted a strange bug with our code. >>>> I've been wading through the docs for a bit here but haven't found >>>> the answer as to why this is happening. Perhaps a simple test is >>>> the best way to explain it: >>>> >>>> Main template: >>>> [#ftl] >>>> [#import "scopeTest.ftl" as test /] >>>> [@test.runTest /] >>>> >>>> scopeTest.ftl: >>>> [#ftl] >>>> [#macro runTest] >>>> [#list 1..30 as i] >>>> [#include "strangeScope.ftl" /] >>>> [/#list] >>>> [/#macro] >>>> >>>> strangeScope.ftl: >>>> [#ftl] >>>> [#if i % 10 == 0] >>>> [#assign someLocal = i + 2 /] >>>> [/#if] >>>> ${i} ${someLocal!'not defined'}<br /> >>>> >>>> Produces this output: >>>> >>>> 1 not defined >>>> 2 not defined >>>> 3 not defined >>>> 4 not defined >>>> 5 not defined >>>> 6 not defined >>>> 7 not defined >>>> 8 not defined >>>> 9 not defined >>>> 10 12 >>>> 11 12 < What? >>>> 12 12 < Why is this still here >>>> 13 12 < shouldn't it say not defined, since, once the include >>>> reaches EOF the someLocal is out of scope and destroyed? >>>> 14 12 >>>> 15 12 >>>> 16 12 >>>> 17 12 >>>> 18 12 >>>> 19 12 >>>> 20 22 < correct >>>> 21 22 < this should say undefined?? >>>> 22 22 >>>> 23 22 >>>> 24 22 >>>> 25 22 >>>> 26 22 >>>> 27 22 >>>> 28 22 >>>> 29 22 >>>> 30 32 >>>> >>>> Is this expected behavior? >>> >>> Yes... frankly, I don't quite get what's odd about it. >>> >>>> Why does a variable that is not declared in a macro remain in scope >>>> for the entire macro? >>> >>> [#include ] has copy-paste-like semantic regarding variable scoping. >>> It's a bit like #include in C, you see. Also, #assign creates the >>> variable on the top-level, which is yet another reason it won't go >>> out >>> of scope. BTW, the variable scoping rules are described here: >>> http://freemarker.org/docs/dgui_misc_var.html >>> >>>> [#local sounds like what I want but that is not permitted in the >>>> include. >>> >>> That indeed won't work there since the included file is parsed >>> without >>> assuming that it will be used inside a macro (and that indeed >>> can't be >>> find that out), and #local works only inside #macro or #function. >>> But >>> even if #local worked there the output would be the same, as the >>> #local variable is created in the scope of the nearest enclosing >>> #macro/#function. >>> >>>> If the someLocal var was declared within the macro itself this is >>>> what I would expect, however in this case, I'm expecting it to be >>>> declared, destroyed, re-declared within the include. The macro >>>> shouldn't even know it is there. Right? >>> >>> Well, #assign creates kind of global variables. Well, it's not >>> absolutely global (that's why we also have #global) if you look into >>> the topic of #import-s... but it doesn't mater now. What you have >>> expected is maybe rather like #var in FreeMarker 2.4 >>> (http://freemarker.org/docs-24pre1/dgui_misc_var.html), which is not >>> released yet (and it won't be in the foreseeable future). >>> >>>> Is this a bug or a feature? If it's the latter, please explain the >>>> reasoning here and what the best practice is if any. >>> >>> Code snippets that meant to be black-boxes are usually implemented >>> as >>> macros. They can also have parameters and nested content, which is a >>> huge advantage over includes. >>> >>>> Is it more correct to ditch the include, convert it to a second >>>> macro and use local? >>> >>> I guess... without seeing the concrete application of course. >>> >>>> I'm a bit confused on this and concerned that we could have several >>>> other instances of include within macro... >>> >>> I don't think the behavior of #include is surprising regarding >>> variables, as this how "include" works in most languages that has >>> it. >>> Also the documentation >>> (http://freemarker.org/docs/ref_directive_include.html) says: "The >>> included file shares the variables with the including template, >>> similarly like if it was copy-pased into it." >>> >>>> Thanks as always. >>> >>> -- >>> Best regards, >>> Daniel Dekany >> >> ------------------------------------------------------------------------------ >> Register Now & Save for Velocity, the Web Performance & Operations >> Conference from O'Reilly Media. Velocity features a full day of >> expert-led, hands-on workshops and two days of sessions from industry >> leaders in dedicated Performance & Operations tracks. Use code >> vel09scf >> and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf >> _______________________________________________ >> FreeMarker-user mailing list >> [email protected] >> https://lists.sourceforge.net/lists/listinfo/freemarker-user >> > > -- > Best regards, > Daniel Dekany ------------------------------------------------------------------------------ Register Now & Save for Velocity, the Web Performance & Operations Conference from O'Reilly Media. Velocity features a full day of expert-led, hands-on workshops and two days of sessions from industry leaders in dedicated Performance & Operations tracks. Use code vel09scf and Save an extra 15% before 5/3. http://p.sf.net/sfu/velocityconf