why no named block definitions inside of content function calls?

108 views
Skip to first unread message

Christopher the Magnificent

unread,
Sep 12, 2012, 12:37:03 PM9/12/12
to mako-d...@googlegroups.com
Hello,

I have tried to do something like this:

<%def name="somefunction(arg1)">
Some function output with argument ${repr(arg1)}.
${caller.body()}
</%def>

<%block name="thing1">
<%local:somefunction arg1="blah">
<%block name="thing2">
Some content that I hope will be printed out.
</%block>
</%local:somefunction>
</%block>

And Mako said that I wasn't allowed to put named blocks inside function calls.  Why is this not allowed?  Is it a technical limitation or an enforcement of an ideological restriction?

It seems to me that if blocks are implemented as global functions that Mako should simply be able to define the block, resolve the actual content of the block through the inheritance chain, if applicable, and then stick the resulting output into the function call content area.  Would it not only be possible but also desirable for the above code to behave equivalently to the following (assuming this is the top-level template):

<%def name="somefunction(arg1)">
Some function output with argument ${repr(arg1)}.
${caller.body()}
</%def>

<%block name="thing1">
<%local:somefunction arg1="blah">
${thing2()}
</%local:somefunction>
</%block>

<%def name="thing2()">
Some content, that I hope will be printed out.
</%def>

I am under the impression that the blocks are like "def" functions except:

1. They are always implemented as top-level functions in the resulting Python modules, rather than being able to be local, nested functions.
2. They may not take function arguments.
3. The first originating instance of a block is automatically and implicitly expanded with the top-most overriding block definition with the same name, and the result is inserted at the exact location of the original definition.  (Regular defs functions are never automatically expanded at the sites of their definition.)

Are there any other conceptual or implementational differences between blocks and "def" functions that prevent blocks from being used inside of function content calls, or even, come to think of it, inside definitions for regular functions like below?

<%def name="thing1()">
<%block name="override_me">
Something to be overridden.
</%block>
</%def>

Love to hear thoughts of anyone who might be in the know.  Thanks!

--Christopher

Michael Bayer

unread,
Sep 12, 2012, 10:27:25 PM9/12/12
to mako-d...@googlegroups.com
On Sep 12, 2012, at 12:37 PM, Christopher the Magnificent wrote:

Hello,

I have tried to do something like this:

<%def name="somefunction(arg1)">
Some function output with argument ${repr(arg1)}.
${caller.body()}
</%def>

<%block name="thing1">
<%local:somefunction arg1="blah">
<%block name="thing2">
Some content that I hope will be printed out.
</%block>
</%local:somefunction>
</%block>

And Mako said that I wasn't allowed to put named blocks inside function calls.  Why is this not allowed?  Is it a technical limitation or an enforcement of an ideological restriction?

The name given to a block becomes part of the "local" namespace of that template, and is accessible by the inheriting template.  The block's def (Python def) is copied out to the module namespace of the template's module, where it can be called by the inheriting template.   This is the main reason blocks can be given names.  A named block that's inside a function already is local to that function's scope, and cannot be called by the inherited template.

Try printing out template.code to see what the generated source looks like, to see what is actually going on.

It seems to me that if blocks are implemented as global functions

blocks that are at the top level are re-rendered as global functions, yes.  blocks that are inside of another block or def are intended to behave like Python closures (and they actually are closures).  So they aren't rendered globally.  

that Mako should simply be able to define the block, resolve the actual content of the block through the inheritance chain, if applicable, and then stick the resulting output into the function call content area.  Would it not only be possible but also desirable for the above code to behave equivalently to the following (assuming this is the top-level template):

<%def name="somefunction(arg1)">
Some function output with argument ${repr(arg1)}.
${caller.body()}
</%def>

<%block name="thing1">
<%local:somefunction arg1="blah">
${thing2()}
</%local:somefunction>
</%block>

<%def name="thing2()">
Some content, that I hope will be printed out.
</%def>

What is the "thing2" name accomplishing in the first example ?  you aren't referring to it.   If you want an inheriting template to use the name "thing2", and its going to pull that thing2 out of the <%local:somefunction>, that's not at all how this all works.

I am under the impression that the blocks are like "def" functions except:

1. They are always implemented as top-level functions in the resulting Python modules, rather than being able to be local, nested functions.

only named blocks.  anonymous blocks can be anywhere (you know there are anonymous blocks, right?) 

2. They may not take function arguments.

yes, if you wanted them to take arguments, you'd use a def.   blocks don't provide any function that defs don't except some syntactic convenience.

3. The first originating instance of a block is automatically and implicitly expanded with the top-most overriding block definition with the same name, and the result is inserted at the exact location of the original definition.  (Regular defs functions are never automatically expanded at the sites of their definition.)

defs and blocks both do this at the top level.   you can access top-level named blocks and named defs from the outside equally.   defs and blocks that are closures never do this.  they are Python function closures, and only exist within the scope of their enclosing function, same way they do in Python itself.


Are there any other conceptual or implementational differences between blocks and "def" functions that prevent blocks from being used inside of function content calls, or even, come to think of it, inside definitions for regular functions like below?

<%def name="thing1()">
<%block name="override_me">
Something to be overridden.
</%block>
</%def>

take the "name" out and it will work, but there's no "overriding" feature available.   To my recollection, there's no ability to "override" defs or blocks that are closures.   the "def-call-with-content" idea doesn't include the concept of "overrides".  at least I'm not recalling that i had anything in there that could do that (seems very complicated regardless.  most people don't even grok def-call-with-content at all).


Reply all
Reply to author
Forward
0 new messages