6 ms·
Never played around with Lisp, so excuse the ignorance. Is this typical to construct HTML in Lisp? This feels incredibly verbose and error prone, not to mention
by nodesocket 9y ago
Never played around with Lisp, so excuse the ignorance. Is this typical to construct HTML in Lisp? This feels incredibly verbose and error prone, not to mention confusing and hard to grok. Good luck having a designer mockup/write HTML.
(defun login-panel ()
(pbox "login/register"
(:form :id "logform" :class "nomargin"
(:table :style "border-collapse: collapse"
(:tr (:td :colspan "2" "username:"))
(:tr (:td :colspan "2" (:input :id "loguser" :class "txt" :name "user" :type "text" :size 15)))
(:tr (:td :colspan "2" "password:"))
(:tr (:td :colspan "2" (:input :id "logpass" :class "txt" :name "pass" :type "password" :size 15)))
(:tr (:td :colspan "2" (:input :id "logmem" :type "checkbox" :name "mem" "remember me")))
(:tr (:td :colspan "2" (:span :id "logerror" :class "error" "")))
(:tr (:td (:input :id "logbtn" :class "btn" :type "submit" :value "Login" :onclick "login(); return false"))
(:td (:input :class "btn" :type "submit" :value "Register" :onclick "register(); return false")))
(:tr (:td :nowrap t :colspan "2" :align "center" :class "little" (:a :href "/password" "what's my password?")))))))
- grzm 9y agoIt's not uncommon. An example in Racket is html-template.[0] Hiccup is one in Clojure.[1] There's a spectrum of methods for doing things like this: both Clojure and Racket have Mustache[2] implementations. "Confusing and hard to grok"† is in the eye of the beholder. Syntax highlighting and indentation go a long way (as well as exposure), though even in black and white, the parens fade for me much more than angle brackets do. Personally, I'd wrap some of the longer lines, but that's a style thing. [0]: https://docs.racket-lang.org/html-template/index.html https://docs.racket-lang.org/html-template/index.html. [1]: https://github.com/weavejester/hiccup https://github.com/weavejester/hiccup [2]: https://mustache.github.io/mustache.5.html https://mustache.github.io/mustache.5.html † Sorry. Couldn't let the typo stand. Heinlein made me do it.
- spapas82 9y agoClojure also has Selmer (https://github.com/yogthos/Selmer https://github.com/yogthos/Selmer) which is a Django inspired templating language!
- unrealhoang 9y agoHow is it verbose? It has much LESS noise than HTML. IMHO, Lisp is the simplest and smallest readable representation of data structure. I will trade JSON for edn [1] any days of the week [1] https://github.com/edn-format/edn https://github.com/edn-format/edn
- grzm 9y agoI share your zeal, but the answer to apparent incredulity isn't to raise the level. People have different tastes when it comes to programming languages and methods, and that's okay. There's often things we can learn from different techniques. To our parent's points, it's more verbose if you're used to passing data into a separate template file. That can help abstract the markup from the data processing. To their point regarding designers, many are more comfortable working with HTML files than application code. That can be a benefit for many teams. Clearly some lispers agree, as they've implemented alternatives like Mustache templates.
- TeMPOraL 9y agoThe notion of incredulity probably comes from fact that it's literally impossible for HTML encoded in s-expressions to be more verbose than HTML encoded in HTML! > To our parent's points, it's more verbose if you're used to passing data into a separate template file. That can help abstract the markup from the data processing. One does not exclude another. The "template" can be another lisp function (in another file). > Clearly some lispers agree, as they've implemented alternatives like Mustache templates. Probably popular demand. Personally, I don't think they should be used, like ever. Those template languages were a doubly bad idea. First, they work on HTML serialization to string instead of HTML semantics as a tree, making it easy to introduce both bugs and security vulnerabilities. The concepts of "escaping", "sanitization" or "injection" are only relevant when you're abusing a serialization format instead of working with the language at the appropriate level. Second, they all seem to have started with the assumption that "views don't need code". Each of them, over time, slowly discovered that no, views actually do need to have code, and slowly gained variables, conditionals, loops, function calls... and turned into shitty Turing-complete languages they tried so hard not to become. The problem here was always the premise. Views absolutely do need code, and so they should be written in a proper programming language.
- chrisdone 9y agoA designer can just write HTML or some toy language. A programmer will translate it to something manageable eventually anyway. A trivial automatic process can convert HTML to a DSL. Although making code sensibly refactored and readable is usually a manual job for the programmer.
- stesch 9y agoLayout in code is something Flutter is doing. And Flutter will be used in the mobile OS Fuchsia.
- erpellan 9y agoS-expressions can be mechanically converted to HTML. HTML is more verbose and error prone: </closingtag> vs ) <form><table></form></table> oops. Can't happen with an s-expression
- candiodari 9y agoExactly. The thing that I always remember is that identifiers encoded this way simply can't get out of sync from client to server. Commands, paths, enums, ... Where a form is posted, say, is an easy constant, that defines both the routing AND the string in the form. Where forms always have the fields defined in a structs, never more, or less. And this can result in sites that are very fast to add things to, as opposed to have dozens and dozens of files everywhere. But everyone wants "single page apps". Because client -> server ---[html]--> client --> server --[javascript]--> client --> server --[4*ajax requests necessary to fill in the initial page]--> client --> server --[4*images necessary to fill in said javascript]--> client Is so obviously "much faster" than: client -> server --[html+embedded everything]--> client
- geocar 9y ago> Good luck having a designer mockup/write HTML. What you are looking at was designed by a designer. Maybe you think another designer you know could make something that looks better if only they could use their own tools, instead of tools that this designer liked to use. I remember an age when I would receive photoshop "designs" that I would have to re-code in HTML. Then they got dreamweaver and thought they didn't need me to code their stuff up anymore, just to debug their stuff and tell them why it didn't work in X/Y/Z browser combination. When the lisp programmer is writing their login panel, they start out writing "code" like this, (defun login-panel () (pbox "login/register" then decide they need some HTML. `pbox` recognises HTML as long as it looks like lisp so: (:form :id "logform" :class "nomargin" (:table :style "border-collapse: collapse" (:tr (:td :colspan "2" "username:")) (:tr (:td :colspan "2" (:input :id "loguser" :class "txt" :name "user" :type "text" :size 15))) (:tr (:td :colspan "2" "password:")) (:tr (:td :colspan "2" (:input :id "logpass" :class "txt" :name "pass" :type "password" :size 15))) (:tr (:td :colspan "2" (:input :id "logmem" :type "checkbox" :name "mem" "remember me"))) (:tr (:td :colspan "2" (:span :id "logerror" :class "error" ""))) (:tr (:td (:input :id "logbtn" :class "btn" :type "submit" :value "Login" :onclick "login(); return false")) (:td (:input :class "btn" :type "submit" :value "Register" :onclick "register(); return false"))) (:tr (:td :nowrap t :colspan "2" :align "center" :class "little" (:a :href "/password" "what's my password?"))))))) can be transformed into the much more complex: <form id="logform" class="nomargin"> <table style="border-collapse: collapse"> <tr><td colspan="2">username:</td></tr> <tr><td colspan="2"><input id="loguser" class="txt" name="user" type="text" size="15"></td></tr> <tr><td colspan="2">password:</td></tr> <tr><td colspan="2"><input id="logpass" class="txt" name="pass" type="password" size="15"></td></tr> <tr><td colspan="2"><input id="logmem" type="checkbox" name="mem">remember me</td></tr> <tr><td colspan="2"><span id="logerror" class="error"></span></td></tr> <tr><td><input id="logbtn" class="btn" type="submit" value="Login" onclick="login(); return false"></td> <td><input class="btn" type="submit" value="Register" onclick="register(); return false"></td></tr> <tr><td nowrap="t" colspan="2" align="center" class="little"><a href="/password">what's my password</a></td></tr> </table> </form> But what is the alternative? To embed the html so that it still looks like HTML means making a string of some kind, and running the risk that there's some kind of variable expansion or XSS or other thing that will bite them in the butt. Maybe not in this simple example, but the need to get into the display-language is very common in a web application, so there are lots of fragments like this to answer to: Maybe this one and bigger we could move into a file and either read it every request or add some extra code to save the contents to a global variable. But we haven't gained very much for all that complexity -- this hypothetical "when" we get a designer who knows HTML and not Lisp, and can contribute in a way that meaningfully moves the project forward without making more work for other programmers is far away at this point, and the reddit developers are just going to rewrite the whole thing in Python anyway.
- TheAceOfHearts 9y agoEmbedding templates in code is actually quite nice. I used to think like you, but then I gave React a try and it completely won me over. Even without the transpilation step for JSX support, I find hyperscript [0] and friends [1] a notable improvement over other templating tools. Instead of having to jump to a separate file which magically inherits a bunch of implicit globals, you just call a function. If the system supports a component abstraction you can import them and compose views using the same programming constructs you use everywhere else. An error in the template can be caught by your linter or compiler, since it's just regular code. I'd say it's actually safer, since you typically won't have to worry about escaping values manually. And along the way you can validate the input in order to confirm you only ever generate valid HTML. Check out elm-css [2] as well, which lets you define your stylesheets with elm. This lets you take advantage of the their type system to make sure all class names are referenced correctly. A typo or accidental deletion would would cause it to fail to compile, allowing you to catch problems early. [0] https://github.com/hyperhype/hyperscript https://github.com/hyperhype/hyperscript [1] https://github.com/developit/vhtml https://github.com/developit/vhtml [2] https://github.com/rtfeldman/elm-css https://github.com/rtfeldman/elm-css
- TeMPOraL 9y agoI still don't get why non-code templating ever became popular. Especially that I saw it becoming popular in PHP, which itself is a better templating language than the templating languages people were using. Instead, people created plethora of languages that slowly accrued Turing-completeness with them, because religious adherence to "no code in views" is stupid. That said, glue-strings-together templates are still a problem and should not be used. HTML document is semantically a tree, and if you don't treat it like that, bugs and security vulnerabilities follow. (Respecting semantics applies to other languages as well. For instance, those who recognized SQL as a language, instead of some blob you concatenated out of strings, didn't have to worry about SQL injection.)
- krapp 9y ago>I still don't get why non-code templating ever became popular. Because if you're working on a team, not everyone on your team may be a programmer, particularly if they're just working on layout design, and the problem that templates solve in that regard don't require complete access to raw code. Separating one from the other makes it easy to focus on one versus the other. Just look at how messy a complex Wordpress template can get and how difficult it can be, just reading it, to get a grasp of what the HTML would look like, versus a Twig template which has a lot less noise. >Especially that I saw it becoming popular in PHP, which itself is a better templating language than the templating languages people were using. I've been down the road with PHP where everyone working on javascript and CSS also had to know just enough PHP not to break the site, because everything had raw PHP mixed into it, and then somewhere in the vast tree of includes including includes someone forgot to manually escape a variable that came from the database, or else they did, but now someone else escaped it twice, or they created some weird encoding problem because they were in a javascript context. PHP is at best an adequate templating language, and a good base to build a sane framework on. But a framework is necessary beyond a certain level of complexity, because most projects benefit from features that raw PHP doesn't provide, such as context-aware and automatic variable escaping, template inheritance, template caching, etc. You will either wind up using an existing templating framework, or you will wind up implementing an ad-hoc, informally-specified, bug-ridden, slow implementation of an existing framework. >That said, glue-strings-together templates are still a problem and should not be used. HTML document is semantically a tree, and if you don't treat it like that, bugs and security vulnerabilities follow. There's no way to get that in PHP without a template framework. PHP, unfortunately, doesn't even know that HTML exists[0], despite having the sole purpose of being an HTML preprocessor. [0]I just remembered there are XML functions like DomDocument that can be used to process HTML (with... effort) but I don't know whether or not you could get something like XHR out of it, and by extension, avoid the problem of HTML as concatenated strings.
- simias 9y agoI'll take sexps over sgml any time. Why do you think this is worse than the corresponding HTML code? You don't have the madness of the closing tag having to repeat the name of the element, the odd idiosyncrasies with self-closing tags, the arbitrary division and restrictions between attribute and children nodes... And of course in the context of writing lisp code it means that you have a uniform syntax instead of having some parts of the file as HTML and others in an other language (which is often a pain with code editors in my experience). It still baffles me that SGML and its descendants are so popular. They're quirky, terribly noisy for markup, incredibly large and slow for serialization and of course every variation introduces and removes arbitrary limitations.
- TeMPOraL 9y agoIt's less verbose than writing it as HTML (sexps > SGML markup for such uses). Moreover, it's the right way to go about it, because it treats HTML documents as the trees they are, instead of running free and wild with string substitution, creating both points of breakage and potential security vulnerabilities everywhere. RE designer thing, I guess it depends on how you work. Frankly, Reddit to this day doesn't look like anything that has ever met a designer (and that's a good thing in its case). Still, if you want, you can just stick to the designer that does mockups in Photoshop, and skip the other designer that converts those into HTML.
- aerique 9y agoIt depends and is a matter of taste. I'm very much a Common Lisp afficionado but I've come to dislike embedding HTML in code like this (also due to experiences in other languages). It's not error prone maybe even less so since it can be checked by the compiler. My preference is to use templating because it matches the final output closer and is, like you said, easier to show to other people / designers. However, even templating is sometimes turned into an enterprise confusing mess where it becomes very complex and hard to know where values come from.
- bluefox 9y agoYou could instead write abstractions for generating forms, e.g.: (pbox "login/register" (form (text "username:" :name "user") (pass "password:" :name "pass") (check "remember me" :name "mem") (group (button "Login" :onclick "login(); return false") (button "Register" :onclick "register(); return false")) (link "what's my password?" :href "/password")))
- codedokode 9y agoThis gets complicated quickly. For example, what if you need to add a CSS class, a placeholder or some custom attribute to an input field? You'll have to write code for every such case. And you can do the same thing with template engines like Twig with macros. Futhermore, Web frameworks like Symfony already have macros that are necessary to display a form. You don't even have to write them and that is a strong point of Symfony compared to weird self-made Lisp template engine.
- Jach 9y agoA nice thing about Lisp is you can do whatever without much getting in your way -- though this is a pretty common way of doing HTML for get-it-out-the-door work. You can get a whole lot fancier (https://github.com/Day8/re-frame https://github.com/Day8/re-frame is an example from ClojureScript land). But the context of what you're making determines the important variations, and whether you ever let a designer (or a programmer) touch this example at this level of resolution or something approximately the same like a separated out HTML file (or whatever template system you like) that the Lisp function just wraps. Example details that could be important in general, not just for this specific code repo: This thing has no concept of localization, is that a constraint? Accessibility? Are there dozens of other engineers working at this level of detail you need to worry about? Is this the output of a higher level tool used by either coders or designers? Is there a coherent component architecture behind this or is it just more of a utility function someone made? Do components need to be namespaced? Live in their own files/packages? Is the thing you're building a site with several unique pages or a SPA? Where are the JavaScript implementation points for things like the on-click's register() function? Or are you going to forbid JS in your markup (because it confuses designers, or because of CSP policy) and force programmers to bind things elsewhere? How does your routing system work, is it fine to hardcode those paths like that?
- Grue3 9y agoIt's common (and I agree it's ugly) but it's far from the only option. I'm using a library [1] that generates HTML from Google's Closure Templates [2] which any designer can easily understand. [1] https://github.com/archimag/cl-closure-template https://github.com/archimag/cl-closure-template [2] https://developers.google.com/closure/templates/ https://developers.google.com/closure/templates/
- krapp 9y agoHacker News/Arc forums (at least an archival version) seems to use both s-expressions and printing raw html/css/js[0]. As far as it being typical... given the zeal that lispers seem to have for s-expressions, yes probably. [0]https://github.com/wting/hackernews/blob/master/news.arc#L388 https://github.com/wting/hackernews/blob/master/news.arc#L38...
- zeveb 9y ago> This feels incredibly verbose and error prone, not to mention confusing and hard to grok. That looks a lot less verbose, error-prone, confusing & hard-to-grok than actual HTML, don't you think? Or do you actually prefer the HTML below? <form id="logform" class="nomargin"> <table style="border-collapse: collapse"> <tr><td colspan="2">username:</td></tr> <tr><td colspan="2"><input id="loguser" class="txt" name="user" type="text" size="15"/></td></tr> <tr><td colspan="2">password:</td></tr> <tr><td colspan="2"><input id="logpass" class="txt" name="pass" type="password" size="15"/></td></tr> <tr><td colspan="2"><input id="logmem" type="checkbox" name="mem"/>remember me</td></tr> <tr><td colspan="2"><span id="logerror" class="error"/></td></tr> <tr><td><input id="logbtn" class="btn" type="submit" value="Login" onclick="login(); return false"/></td> <td><input class="btn" type="submit" value="Register" onclick="register(); return false"/></td> </tr> <tr><td nowrap="true" colspan="2" align="center" class="little"><a href="/password">what's my password?</a></td></tr> </table> </form> For my money, the S-expression HTML is much easier to read & understand.
- dewski 9y agoYou may find varying answers depending on who you're asking and if they have any experience with Lisp. As someone who doesn't, the HTML example is 100% easier to read in my opinion coming from a Rails developer. You don't have to go against the grain to get the output you desire, you can just write it as it is intended to be rendered.
- kbp 9y ago> Is this typical to construct HTML in Lisp? This feels incredibly verbose and error prone, not to mention confusing and hard to grok. Good luck having a designer mockup/write HTML. Do you mean that (:td :colspan "2" "username:") is verbose and error-prone compared to <td colspan="2">username:</td>, or what are you comparing it to? That code is probably denser than I would have written it, but I don't see any issue related to the fact the HTML is being generated from Lisp. This example doesn't take advantage of it, but writing HTML in Lisp is easier and less error-prone than regular HTML, because you can abstract patterns and factor things.