Wednesday, July 9, 2008, 11:34:52 PM, Joe Hudson wrote:
> On Wed, Jul 9, 2008 at 11:23 AM, Daniel Dekany <dde...@freemail.hu> wrote:
>> Wednesday, July 9, 2008, 4:03:36 PM, Joe Hudson wrote:
>>
>>> FYI: I added a really cool addition to the macro functionality:
>>> http://code.google.com/p/zipscript/issues/detail?id=29&can=1&q=label:r0.8.4%20label:Module-core
>>
>> I know the problem you seem to attack here (i.e., when buffering
>> needed because a part of the output depends on the later output), but
>> I don't see how does it solve that. If I can separate the initializer
>> code from the others, then I don't need to buffer, since then calling
>> the initalizer can be the first thing in the template. The problem
>> used to be exactly that I can't do this separation (not reasonably
>> easily or not at all). And for using #initialize, I still need to do
>> that separation. And if I can do it, then again, I could just put it
>> at the beginning of the template. What do I miss here?
>
> Yes, but say you separate the page layout from the body content for
> reuse and the layout contains the javascript includes. I think this
> example might explain it:
>
> Map context = new HaspMap();
> // load context
> Template screenTemplate = zipEngine.getTemplate("someScreen.zs");
> Context initializedContext = screenTemplate.initialize(context);
> Template layoutTemplate = zipEngine.getTemplate("layout.zs");
> initializedContext.put("screen_placeholder", screenTemplate);
> String result = layoutTemplate.merge(initializedContext);
>
> So, now you can process templates with initialized context from other
> templates. Does that make sense?
Yes, in the case of creating the page from multiple templates it
works. Although the same kind of problem arises here as in the earlier
version of object-oriented (aka template-defined) parameters: it
doesn't work well if you use macros extensively. Because, then the
#initialize part possibly had to be moved inside a macro (with the
non-initialization-time stuff that it belongs to), and thus the
template only contains a call to the macro. So it doesn't directly
contains the #initialize directive, and thus, I guess, it will not
work. Not mention, that even if you descend into the called macros to
find #initalize-s, the macros can be called conditionally, so... you
end up with the same issue again as with object-oriented parameters
(that you have solved there, but the result is confusing IMO, so it
might not be repeated in this case too). (Also, as another
macro-related issue, this feature is available only if you chose to
use multiple templates per HTTP resposne (or whatever the unit of the
output is, like HTML file), as opposed to multiple macros per HTTP
response. And some may want to compose the page using only a single
template but multiple macros. After all, a main use case of
object-oriented parameters is layouts.)
>>> My comments are below but in the future, Jonathan and the FM team have
>>> been more than gracious to let me use this forum but I'm sure my
>>> welcome here is wearing thin.
>>
>> Yeah, the problem is that we didn't really talked about ZipScript VS
>> FM, and mostly only that would be on topic. Well, maybe just respond
>> privately to me to this mail.
>>
>>> I propose that if you want to continue this conversation, we do it
>>> in the ZipScript developers group:
>>> http://groups.google.com/group/zipscript-dev. If not, thank you,
>>> Daniel, for your feedback. I appreciate you actually taking the time
>>> to do so.
>>
>> I don't even have a google account yet, etc., so as currently I don't
>> plan to contribute, we rather should just continue in private for now.
>>
>> [snip]
>>>>>>>> - "Required parameters must be prefixed with *": I think in practice
>>>>>>>> the basic (default) case is that a parameter is required. So rather
>>>>>>>> indicate if the parameter is not required, but has no default value.
>>>>>>>> Like, maybe [#macro name reqParam optionalParam?], or even [#macro
>>>>>>>> name reqParam optionalParam=null] for easier undesirability. (The
>>>>>>>> choice of * is also not very lucky, since for many it means "any
>>>>>>>> number of something, including 0". See in file paths and regexps.)
>>>>>>>
>>>>>>> That isn't an issue for me because the required * is a prefix to the
>>>>>>> attribute key and the math operator is inside a default value
>>>>>>> reference so no problem here.
>>>>>>
>>>>>> I have talked about certain language design decisions here, and I do
>>>>>> see a problem here, as I said. I didn't talked about what can be
>>>>>> implemented.
>>>>>
>>>>> Ok, we disagree here
>>>>
>>>> But in which points and why?
>>>
>>>
>>> We disagree on the fact that using * to mark required fields is a
>>> problem. Why, because you do think it is a problem and I don't.
>>
>> The usage of "*" instead of whatever else was not important here. My
>> main point is that the most common (most natural) case is that a
>> parameter is required, so it's that case where you should not use any
>> special operators. Now of course it depends on what the macro library
>> is about, but I think most macros has more required than optional
>> parameters. Also, regardless of that, the other problem is users can
>> easily assume by mistake that by writing [#macro foo x y], it's
>> already ensured that x and y will be present. And anyway they will
>> tend to write just that, without all the "*"-s, both out of laziness,
>> and because it's the usual way of declaring parameters everywhere. So
>> it's also a safety/maintainability thing for the "strict case" to be
>> the default, and the "loose case" to be the one that need to be asked
>> explicitly (so the user surely will know what exceptional things can
>> occur).
>
> Ok, I did miss your point. I agree with you on that maybe required
> should be the default and an identifier should be used for optional.
> I think '?' would make sense but that might be a bit tougher because
> it is at the end of the parameter just like it would be if it were
> used as a special method. I'll have to think about how that will
> work.
If optional parameters will exactly behave as if their default value
were null, then in theory paramName=null would be enough. Yeah,
possibly too verbose, but at least self explanatory. (However, I don't
like if it behaves exactly like if the default value is null, because
then you can't tell if the parameter was omitted, or present but with
null value. But surely many would find this kind of differentiation
overly purist for a template language.)
>> [snip]
>>>> I see. Two things. You didn't declared the "header" and "footer"
>>>> parameters in the definition of the "grid" macro, so it should be an
>>>> error. Then, it may worth reevaluation if this little convenience
>>>> trick worth the complication of the language (think about the users).
>>>> Because I don't think that header/footer is *that* frequent. Or is it?
>>>
>>> Think of header/footer elements more like a body element. You don't
>>> declare a body if you have it, right?
>>
>> Huh? This comparison doesn't stand. If something has only one body,
>> then of course you just write:
>>
>> <@foo>
>> the body
>> </@foo>
>>
>> not:
>>
>> <@foo>
>> <@body>
>> the body
>> </@body>
>> </@foo>
>>
>> because then you could argue that @body has also a body, so then you
>> had to write:
>>
>> <@foo>
>> <@body>
>> <@body>
>> the body
>> </@body>
>> </@body>
>> </@foo>
>>
>> and so on, infinitely. But when you have more kind of "bodies" inside
>> "foo", you *do* write out "body":
>>
>> <@foo>
>> <@body1>
>> the body
>> </@body1>
>> <@body2>
>> the body
>> </@body2>
>> </@foo>
>>
>> There is nothing asymmetric in this.
>>
>>> I just see a pattern of many UI components optionally using this
>>> type of structure so I built it into the langauge.
>>
>> For example where? Did they used that for this? Or, maybe just they
>> didn't have generic template-defined parameter feature.
>>
>>> I agree that it
>>> is an advanced feature and can be replaced by
>>> [@header]whatever[/@header] but it is just something I wanted to
>>> support. It is probably just something I would document in a "For
>>> Advanced Users" section or something like that.
>>
>> A mistake that some languages used to make. I used to try hard to
>> avoid features that I have to document under a section like that. It's
>> just a template language, so it's important to avoid too much fancy
>> features. I think, it should be rather be a bit more verbose, than a
>> bit more complex. And in this case you really just saving a few
>> keystrokes, on the expense of making the templates harder to
>> understand. For a generic programming language it's OK to have those
>> baroque details, but for a strongly specialized language it's often
>> not. Especially when the target audience of the language is not only
>> hardcore programmers.
>
> Ok, you have sold me. I might be introducing functionality that will
> just confuse the user. I'll take that out.
>
>> --
>> Best regards,
>> Daniel Dekany
--
Best regards,
Daniel Dekany
It will work in terms of calling initialize methods that are in
external macro definitions. However, you are right, it will call
initialize for any macros that are referenced from the template
regardless of whether or not they will get used. I still think it is
pretty valuable functionality. And, for that matter, I could probably
modify the logic to actually perform just enough work to actually
include only the macros that will get used. And, even with the
macro-driven layouts, the initialize would be valuable because the top
portion of the page (including all JS references would be merged
before the body area which would be where the bulk of the JS
components would be used.
Ex template:
[@page.page]
blah
[@tab.pane]...[/@tab.pane]
blah
[/@page]
--- page macros ---
[#macro page ...]
...
[#foreach include in jsIncludes]
... <-- normally we wouldn't know about the tab component yet here
[/#foreach]
[/#macro].
--- tab macros ---
[#macro pane ...]
[#initialize]
${jsIncludes.put("tab.js", true);
[/#initialize]
[/#macro]
That's funny because that is exactly how I used to have it. I'll put
it back that way for 0.8.5
I'm not saying I would do this because I'm happy with the
functionality as is but, I could just evaluate ahead of time only the
elements that are required to determine if a macro is included or not
for the initialize part. I would, of course, have to execute these
elements again when performing the actual merge which is why I might
not add this functionality.
Currently, any macros that are referenced in a template (and macros
referenced by a macro referenced by a template and so on...) will have
the initialize directive run regardless of whether or not they will
actually get included during the merge.
> On Fri, Jul 11, 2008 at 7:27 AM, Daniel Dekany <dde...@freemail.hu> wrote:
[snip]
>>> It will work in terms of calling initialize methods that are in
>>> external macro definitions. However, you are right, it will call
>>> initialize for any macros that are referenced from the template
>>> regardless of whether or not they will get used. I still think it is
>>> pretty valuable functionality. And, for that matter, I could probably
>>> modify the logic to actually perform just enough work to actually
>>> include only the macros that will get used.
>>
>> How would you do that? I mean, this is the same kind of contradiction
>> as with the conditional/looped/etc object-oriented parameters. You
>> want the advantages of both the markup-like languages (I mean, like
>> with typical XML Schemas you can examine the whole tree in any order,
>> you can "look ahead" without problems) and of the usual imperative
>> languages (where you have to execute things in strict order to get
>> build the result). Now of course it would be desirable, but you just
>> can't find out ahead which macros will be executed, as the only way to
>> know that is indeed executing the template. And this can't be fixed in
>> general, of course. So what's the twist this time?
>
> I'm not saying I would do this because I'm happy with the
> functionality as is but, I could just evaluate ahead of time only the
> elements that are required to determine if a macro is included or not
> for the initialize part. I would, of course, have to execute these
> elements again when performing the actual merge which is why I might
> not add this functionality.
Yeah, that wouldn't work... for one, the parameters to the macro calls
are possibly determined during the normal template execution, so you
can't just make some macro calls out-of-order. (This is the same
problem as with the object-oriented parameters... where it was
addressed, well... bravely or what should I call it? :) ) Also, if you
have <@userMacro><@iHaveInialize /></@userMacro>, then you can't know
what side-effects userMacro has, so it's not safe to call it twice.
> Currently, any macros that are referenced in a template (and macros
> referenced by a macro referenced by a template and so on...) will have
> the initialize directive run regardless of whether or not they will
> actually get included during the merge.
After all, some redundant JavaScript includes doesn't hurt too much
usually... And if I insert them manually, I will usually still insert
all that is *possibly* needed, so in practice the end result is
certainly not of worse quality with the automated approach.
I think this is more of an issue with documentation. This may not
useful to everyone but it certainly is to me. I have a desire to have
a single layout definition for a web app and not to have to worry
about all the javascript includes needed for any page that uses that
layout. These most certainly can get very large especially when you
are talking about libraries like YUI.
Any code in the initialize method will only run once regardless of how
many times the macro is actually called. Because of this, you do not
have access to any parameters that were passed to the macro.