1

I guess I should have pre-faced this with: Yes, I know there is no need for a new templating language, but I want to make a new one anyway, because I'm a fool. That aside, how can I improve my language:

Let's start with an example:

using "html5"
using "extratags"

html {
    head {
        title "Ordering Notice"
        jsinclude "jquery.js"
    }
    body {
        h1 "Ordering Notice"
        p "Dear @name,"
        p "Thanks for placing your order with @company. It's scheduled to ship on {@ship_date|dateformat}."
        p "Here are the items you've ordered:"
        table {
            tr {
                th "name"
                th "price"
            }
            for(@item in @item_list) {
                tr {
                    td @item.name
                    td @item.price
                }
            }
        }
        if(@ordered_warranty)
            p "Your warranty information will be included in the packaging."
        p(class="footer") {
            "Sincerely," br @company
        }
    }
}

The "using" keyword indicates which tags to use. "html5" might include all the html5 standard tags, but your tags names wouldn't have to be based on their HTML counter-parts at all if you didn't want to.

The "extratags" library for example might add an extra tag, called "jsinclude" which gets replaced with something like <script type="text/javascript" src="@content"></script>

Tags can be optionally be followed by an opening brace. They will automatically be closed at the closing brace. If no brace is used, they will be closed after taking one element.

Variables are prefixed with the @ symbol. They may be used inside double-quoted strings. I think I'll use single-quotes to indicate "no variable substitution" like PHP does.

Filter functions can be applied to variables like @variable|filter. Arguments can be passed to the filter @variable|filter:@arg1,arg2="y"

Attributes can be passed to tags by including them in (), like p(class="classname").

You will also be able to include partial templates like:

for(@item in @item_list)
    include("item_partial", item=@item)

Something like that I'm thinking. The first argument will be the name of the template file, and subsequent ones will be named arguments where @item gets the variable name "item" inside that template. I also want to have a collection version like RoR has, so you don't even have to write the loop. Thoughts on this and exact syntax would be helpful :)

Some questions:

  • Which symbol should I use to prefix variables? @ (like Razor), $ (like PHP), or something else?
  • Should the @ symbol be necessary in "for" and "if" statements? It's kind of implied that those are variables.
  • Tags and controls (like if,for) presently have the exact same syntax. Should I do something to differentiate the two? If so, what?
    • This would make it more clear that the "tag" isn't behaving like just a normal tag that will get replaced with content, but controls the flow. Also, it would allow name-reuse.
    • Like tag would be a normal tag, but @tag would be a directive like @for, @if, @include, @using
  • Do you like the attribute syntax? (round brackets)
  • How should I do template inheritance/layouts?
    • In Django, the first line of the file has to include the layout file, and then you delimit blocks of code which get stuffed into that layout.
    • In CakePHP, it's kind of backwards, you specify the layout in the controller.view function, the layout gets a special $content_for_layout variable, and then the entire template gets stuffed into that, and you don't need to delimit any blocks of code.
    • I guess Django's is a little more powerful because you can have multiple code blocks, but it makes your templates more verbose... trying to decide what approach to take
  • Filtered variables inside quotes:
    • "xxx {@var|filter} yyy"
    • "xxx @{var|filter} yyy"
    • "xxx @var|filter yyy"
    • i.e, @ inside, @ outside, or no braces at all. I think no-braces might cause problems, especially when you try adding arguments, like @var|filter:arg="x", then the quotes would get confused. But perhaps a braceless version could work for when there are no quotes...? Still, which option for braces, first or second? I think the first one might be better because then we're consistent... the @ is always nudged up against the variable.

I'll add more questions in a few minutes, once I get some feedback.


Semi-colons:

I'm going to use semi-colons to close tags without content. For example, div; would output and wouldn't eat the next token like it normally would.

Namespaces:

Since I'll be defining the tags in straight C#, and C# supports namespaces, I think I'll just use that namespace and it'll work seamlessly. namespace.tagname, but it won't be necessary to include the namespace unless you want to disambiguate. The most recently included (via @using directive) will take precedence.


@Tom Anderson:

div {
    p "This is a paragraph"
    p "This is another paragraph"
}

span(class="error") "This is going to be bright red"

img(src="smiley.png", alt=":)")

p {
    "This " a(href="about-paragraphs.html") "paragraph" " contains a link."
}
mpen
  • 1,889
  • 19
  • 29
  • Can you include other html files? Do you have template inheritance like in Django or layouts like in Rails? – Thierry Lam Jan 07 '11 at 20:41
  • 9
    No offence, but do you really think the world needs yet another template language? What's wrong with the thousands that already exist? That said it's very aesthetic. Can you do template inheritance? – dan_waterworth Jan 07 '11 at 20:43
  • 1
    What's wrong with YAML? – S.Lott Jan 07 '11 at 20:44
  • 8
    What problem are you trying to solve that other template languages fail to solve? – Jeff Jan 07 '11 at 20:46
  • 2
    @dan and jeff: The other languages are fine, and I don't expect this one to gain any popularity. It's mostly for my own use, built exactly the way I want -- concise and powerful. – mpen Jan 07 '11 at 20:49
  • @Thierry Lam: Yes, you'll be able to include other HTML/template files, I'll amend the question in a sec. I'm trying to decide though if layout files should be treated differently than content templates. CakePHP, for example, has a special concept of layouts, and there's a default layout that all your templates will get rendered inside of. – mpen Jan 07 '11 at 20:52
  • 3
    @S.Lott: do you mean HAML? I was just thinking that this looks quite similar to HAML. With curly-braces. – Adam Crossland Jan 07 '11 at 21:01
  • 1
    Hey, cool. I made this before. http://vision-language.sourceforge.net/cgi-bin/Home Maybe we should team up. – Jon Purdy Jan 07 '11 at 23:08
  • @Jon: Wow, that's remarkably similar. – mpen Jan 07 '11 at 23:45
  • @Ralph: Well, I've been using it on my company's site, but haven't had much need to update it. If you'd like to use it or look at the source for ideas, then by all means go right ahead. I think I'd actually like to revamp the syntax a bit and add some of the features that were planned but never implemented, so I might borrow a couple of *your* ideas, if that's alright. – Jon Purdy Jan 07 '11 at 23:59
  • @Jon: Haha.. go for it. Have you documented these planned features? I wouldn't mind seeing them. – mpen Jan 08 '11 at 00:01
  • 1
    @Jeff: Well, having made something pretty similar, I think I can say that the greatest advantages are the cleanness of the syntax and the strict imposition of separation of concerns, neatly dividing content (especially dynamically generated content) from the template used to present it. It's what you get from, say, well-designed PHP code, but without even the *ability* to inadvertently dirty it up. – Jon Purdy Jan 08 '11 at 00:03
  • @Ralph: The tracker on SourceForge is out of date. Named arguments were a big thing, and currently there's no support for numbers or iteration, though there are some functional constructs in the (rudimentary) standard library that allow for conditionals beyond a basic definedness test. I'll probably follow your example and remove the requirement of terminating statements with a semicolon, as it tends to cruft up the source a bit. Also, namespaces are a must. – Jon Purdy Jan 08 '11 at 00:08
  • @Jon: I'm going to use semi-colons to close tags without content. For example, `div;` would output `
    ` and wouldn't eat the next token like it normally would. I think you've devised a `null` construct instead? You mean tag-namespaces? Since I'll be defining the tags in straight C#, and C# supports namespaces, I think I'll just use that namespace and it'll work seamlessly. `namespace.tagname`, but it won't be necessary to include the namespace unless you want to disambiguate. The most recently included (via `@using` directive) will take precedence.
    – mpen Jan 08 '11 at 01:22
  • Check out HAML: http://haml-lang.com/ – Yevgeniy Brikman Jan 08 '11 at 01:36
  • @Ralph: Right, `null` is defined in the standard library as an empty string, so `div;` yields `
    ` and `div: null;` yields the correct `
    `. I mean namespaces for any identifier, tag or template, and being able to refer to the template in `@namespace foo { @define bar : "baz" }` as either `bar` or `foo:bar`, depending on what's been imported into the current scope. Unrecognised identifiers default to being interpreted as tags, so Vision's not restricted to HTML, but it also doesn't have a facility for checking for invalid tags, which yours would.
    – Jon Purdy Jan 08 '11 at 01:38
  • @Jon: My first prototype interpreted everything as an HTML tag by default too.... I think I might drop that functionality in favor of stronger validation. I don't think there will be much of a need for random tags after I implement the entire html5 spec. I'm not sure if I should check the attributes though... – mpen Jan 08 '11 at 01:54

3 Answers3

4

First thought: "Oh no, not another one!" Second thought: "Well, at least that was a unique concept".

You make a "template" language that in fact isn't a template language at all, as it bears no relation to the output. It more strictly a HTML generating language.

The idea is interesting, mostly because it has a much cleaner syntax than HTML. But it has one major drawback: No HTML-editor would understand it. Therefore it is only useful for HTML that is more generated than templated. That's definitely an interesting concept, as HTML technology is going more and more towards having HTML only doing content, and designing either with CSS or XSLT or both.

But do you really need a language for this? Building HTML is possible with modules in most languages, and although the syntax would be different, the code would end up looking quite similar. It wouldn't be to difficult to do something similar with say lxml or BeautifulSoup in Python. Maybe it would be less clean, but it would also not require you to learn another language.

My preferred technique is still to gather all data in the programming language (python in my case) and have a rather stupid template language that just formats it into HTML. (Unfortunately I never get to use my favorite: Templess, so it remains a favorite in theory only.)

In any case I'd prefer using a more Pythonic syntax. It's even cleaner:

html:
  head:
    title: "Ordering Notice"
    jsinclude: "jquery.js"
  body:
    h1: "Ordering Notice"
    p: "Dear @name,"
    p: "Thanks for placing your order with @company. It's scheduled to ship on {@ship_date|dateformat}."
    p: "Here are the items you've ordered:"
    table:
        tr:
            th: "name"
            th: "price"
        for item in item_list:
            tr:
              th: item.name
              td: item.price
    if ordered_warranty:
        p: "Your warranty information will be included in the packaging."
        p(class="footer"):
          "Sincerely," br @company # I don't understand this line
Lennart Regebro
  • 2,265
  • 13
  • 17
  • Well, that's the goal. Much cleaner syntax. One tag can even include multiple HTML tags you don't have to look it severely nested and what not. re: "No HTML-editor would understand it": I'm planning on adding a Visual Studio plugin. I don't think adding a syntax highlighter should be too difficult, IntelliSense might be a little trickier, haven't looked into it yet. Still, you're right, there's no *need* for it, but that's not what the question is about :) Assuming I'm foolishly going to go ahead with this... what are your thoughts? – mpen Jan 07 '11 at 21:50
  • I think my "language" or "generator" has a similar goal or concept as XSLT, but I found XSLT has quite a strange/backwards way of going about things and probably has a much higher learning curve to it than my language would. The idea of using tags named after their html-counterparts was to reduce the learning curve; once you're more comfortable with the language you could start writing your own that have no similarity at all to their HTML output. So really, there isn't *too* much to learn. If you take out the ifs and fors, the syntax is only slightly different from basic HTML. – mpen Jan 07 '11 at 21:55
  • I'm not quite sure how you would use BeautifulSoup for a similar purpose though? You could make some modifications to the HTML, but I don't see how you could even add loops with it. **Edit:** Nevermind... looking at `templess` I think I see what you mean. You could sneak the control structures in there as attributes or custom tags or something, but I quite hate that :) I'm trying to get away from XML-style code. – mpen Jan 07 '11 at 21:57
  • @Ralph: Well, you would make the loops in Python, then. – Lennart Regebro Jan 07 '11 at 22:08
  • The thing I dislike most about Python is its dependency on whitespace. It *does* look cleaner, but I just don't like it :) Regarding the line you don't understand... it outputs the word "Sincerely" followed by a `
    ` tag, `br` doesn't take any input so it's self-closed, and then the `@company` variable.
    – mpen Jan 07 '11 at 22:13
1

As Lennart says, this isn't a templating language. Rather, it's a domain-specific programming language, with primitives (or perhaps library functions, i'm not clear how the tags are defined) for producing HTML.

I wrote something similar a while ago, which i have sadly lost. However, rather than defining a new language, i simply wrote some functions in Python. Really, i needed to write a translator that turned DTDs into Python, but that's another story. Anyway, i had functions named for each tag, which would return an object representing an element with that tag, and which would accept various arguments according to the content model of that element. Attributes were handled with keyword arguments. So, you could write:

div(
    p("This is a paragraph"),
    p("This is another paragraph - div takes varargs")
)

span("This is going to be bright red", class="error")

img(src="smiley.png", alt=":)")

p("This ", a("paragraph", href="about-paragraphs.html"), "contains a link."),

But you couldn't write any of:

img("throws an exception because img elements can't have content")

span(p("throws an exception because spans can't contain block-level elements"))

p(nosuch="throws an exception because there's no such attribute")

img(alt="throws an exception because it lacks the required src attribute")

The objects constructed were lightweight, but knew how to write themselves to a file-like object, or assemble themselves into a string.

Because this is just ordinary Python code, you have the full power of the language - a language which already exists, is well-developed, powerful, and widely known and documented - at your disposal. If you want a loop, you use for, or even better, a list comprehension or generator expression. If you want a conditional block, you use an if. If you want to store a fragment of HTML and use it later, use a variable. If you want to put the values of variables into strings, use %. If you want a metaclass which applies a decorator to produce a generator from a lambda, go crazy. You can't do template inheritance as such, but the existing facilities of the language let you make a function which passes its arguments into a template:

def standardPageContainer(pageTitle, pageText):
    return html(
        head(
            title(pageTitle)),
        body(
            h1(pageTitle),
            hr(),
            pageText))

And you're away.

I will bet pounds to pork pies that my approach will deliver a cleaner, more consistent, easier to use, and more powerful language than yours in under a tenth of the lines of code. I can make that bet because i'm cheating like a swine: i'm stealing everything the Python guys have done.

Anyway, the moral of the story is: kids, just say no to domain-specific languages.

Tom Anderson
  • 3,022
  • 19
  • 24
  • I was thinking about ways to embed IronPython, but I haven't quite decided it's necessary yet. I've been using Django for awhile now, and I've very rarely needed more power than the limited tags it supports. If you're doing that much in the template, you're probably not separating your code properly. Regardless, I'm also developing a system so that you can add more tags and flow controls with just a few lines of C#. This is going into a C# framework, so I'm trying not to mix too much dependency on Python in there... that requires users to know 2 full languages instead of just the 1 (C#). – mpen Jan 07 '11 at 22:48
  • 1
    I could add a catch-all IronPython tag, like `` and bam, I've got all the power you've got, but with cleaner syntax. You'll probably say something like "what's the point then? just write in in straight python!"... well, I don't want to. I want clean, sexy syntax, and I won't compromise. Even if no one will ever use it. – mpen Jan 07 '11 at 22:53
  • @Ralph: I wrote something very similar to this in Java (before deciding that Python was a better fit), so i'm sure you could do it in C#. Any language with functions that can take varargs will do, in fact. As for doing too much in the template - quite possible, but your proposed language has just as much power, just less uniform syntax and more implementation work. If you want to keep logic out of the template, try Mustache, which has a .net implementation: http://mustache.github.com/ – Tom Anderson Jan 07 '11 at 22:54
  • @Ralph: i am completely baffled by your use of "clean". Your proposed syntax is decidedly less clean than Python's. – Tom Anderson Jan 07 '11 at 22:56
  • Decidedly? Let me rewrite your example in my language. They're almost identical, except mine has a few less keystrokes. How's that less clean? -- See updated Q. – mpen Jan 07 '11 at 23:03
  • @Ralph: for the basic stuff, both languages are pretty clean. It's the loops, filters, conditionals, and so on where they diverge. – Tom Anderson Jan 07 '11 at 23:08
  • It's a bit ironic mustache calls itself logic-less, and then in their first example they write this `{{#in_ca}}...{{/in_ca}}` which is essentially an "if" checking if `in_ca` is true or false. Anyway, I didn't say logic-less... there's a fine line between too much and too little control in the template. – mpen Jan 07 '11 at 23:18
  • @Tom: Yeah... and you haven't convinced me that mine will be any less clean. And anyway, that's why I'm *asking* this question. Show me a practical example where Python would be cleaner, and I'll refine my language until *it* is just as clean. That's exactly what I want to find out. – mpen Jan 07 '11 at 23:21
  • Also, I don't understand your argument against domain-specific languages. PHP was a domain-specific language, it became hugely popular. Django has its own template language, .NET MVC has 3 template engines now I think, all in use. Smarty is another one. So is mustache. – mpen Jan 07 '11 at 23:25
  • @Tom: One more thing, *how* exactly would I do this in C#? C# will accept a variable number of arguments, but it won't accept named arguments. I'd have to use a dictionary, or anonymous types. Neither requires varargs. – mpen Jan 08 '11 at 01:13
1

I like the syntax.

I don't like the idea of creating something just "because we can", without a precise need. But, well, it doesn't matter.

What matters is another thing I want to notice, which is sometimes forgotten by the people who create new languages, template systems, etc.:

  1. Do you intend to create tools to support this template language? I mean, when I develop an ASP.NET MVC website with Razor, I have a very helpful Visual Studio 2010 IntelliSense. If one day I need to use PHP (which is a template language), I can use Zend IDE and other helpful editors for it. If one day I start using your template language, do I have something better than notepad?

  2. Do you intend to provide help and support? Imagine one day I start using your language. And something wrong happens. What can I do?

You may say that it doesn't matter since your intent is not to create something to be used by hundreds of thousands of developers all around the world. But if you will one day use it in your websites, be aware that a website which uses some custom template language without tools or support can be maintained only by you.

This means that you will have problems if you are a professional developer and you use it inside your customers/your company website. This also means that you will have problems if one day some of your home-made websites will become famous or you will decide to invite somebody to work on your code.

Arseni Mourzenko
  • 134,780
  • 31
  • 343
  • 513
  • (1) Oh, did they finally finish adding intellisense to it? Been waiting for that. (2) Nope. I'll write some docs if there's enough interest, but otherwise, they're on their own. Theoretically they could turn to the community for support, if there ever is one. This is not so different from RoR or Django I think (but they actually *do* have communities). (3) I'll use it on my own sites first (not for clients), and see how well it fairs in the real world. Only after I give it some stress testing, I'll consider using it on a client's site. – mpen Jan 08 '11 at 01:59
  • (1b) Yes, I do plan on adding syntax highlighting for VS2010, possibly intellisense depending on how difficult it is to implement. – mpen Jan 08 '11 at 02:00
  • 1
    @Ralph: (1): see http://stackoverflow.com/questions/3491456/how-to-get-intellisense-for-razor-view-engine – Arseni Mourzenko Jan 08 '11 at 02:04