tag:blogger.com,1999:blog-3016981170905406325.post1188176250932340632..comments2024-03-22T05:35:31.155-07:00Comments on language agnostic: Yegge Strikes Back from the GraveInaimathihttp://www.blogger.com/profile/14277727122990903016noreply@blogger.comBlogger20125tag:blogger.com,1999:blog-3016981170905406325.post-70829422067842437702011-01-14T13:28:33.899-08:002011-01-14T13:28:33.899-08:00@lele - Yeah, the rule of thumb seems to be "...@lele - Yeah, the rule of thumb seems to be "If Edi Weitz wrote a package for something you need to do, use his". As far as I'm concerned, Hunchentoot is at the head of the pack in terms of application servers (and if I had more static pages to host, I'd do so using Antiweb). I also use cl-who for HTML generation. I haven't tried any of the web frameworks for real yet, so they may make things easier.<br /><br />I can't really back up my claims with specific evidence, unfortunately. I didn't document my decision process. What I remember is pulling up http://www.cliki.net/Web and going through lots of the documentation/"getting started" tutorials before settling.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-28058377082032030242011-01-08T12:42:49.699-08:002011-01-08T12:42:49.699-08:00Nice review from someone who tried both platforms....Nice review from someone who tried both platforms.<br /><br />As Yeggie stated, I have come to same conclusion too.<br /><br />> Granted, there's a clear "best" in each category, but you really need to do your reading in order to find that out.<br /><br />Would you please share your findings? To me it seems that Weitz's packages - HUNCHENTOOT, HTML-TEMPLATE, etc. - are to be preferred when developing Web apps. Maybe, Weblocks too.lelehttps://www.blogger.com/profile/00314110857110364782noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-9846306578522524262010-09-28T12:34:02.912-07:002010-09-28T12:34:02.912-07:00@Jay: Thanks for taking the time to ask.
I meant ...@Jay: Thanks for taking the time to ask.<br /><br />I meant it when I said I was a fan. The world needs a learning-friendly Lisp that can extend to production purposes, and you guys are doing a lot of good on that front. <br /><br />Keep up the good work.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-92074947711069325352010-09-28T12:10:41.217-07:002010-09-28T12:10:41.217-07:00It sounds like you want to use the 'web-server...It sounds like you want to use the 'web-server/http/bindings' library and deal with the potential problems that other framework simply hide from you. We have no intention of removing this library.<br /><br />s/s/d is no more a default than dispatch-rules. They are both part of web-server/servlet (the library for writing servlets.)<br /><br />Your "easy handlers" are basically dispatch-rules, although it also gives you a URL creating function so you can write (test-page arg ...) and have that expand into "/easy/arg ..." so you don't need to remember what URL calls test-page.<br /><br />The main difference is that dispatch-rules is functional: you write all the URL patterns in one place, whereas define-easy-handler appears to imperatively modify a global dispatch table. It should be easy to make a new library like dispatch-rules that behaved that way, but we haven't done it. (We = me; and I haven't done it because I think it is bad taste.)<br /><br />However, the dispatch/untyped package does do something similar to what you want, so you may want to use that instead.<br /><br />Thanks for writing this post and I hope I can find ways to improve the Web server for users like you,<br /><br />JayJay McCarthyhttps://www.blogger.com/profile/07912023932333508057noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-11387929771362506012010-09-28T11:47:31.683-07:002010-09-28T11:47:31.683-07:00PS from above
That story was indeed from the PLT ...PS from above<br /><br />That story was indeed from the PLT Blog, but not quite the same context. It was a post by Matthias Felleisen at http://blog.racket-lang.org/2009/03/drscheme-repl-isnt-lisp.html explaining why the DrScheme REPL expected you to reload an entire scheme file rather than making it easy to send in one command at a time. In my defense, the explanation does involve making this design decision specifically because Matthias saw so many people "stumble across the state of the repl". I assumed the same reasoning ran with the web server.<br /><br />I could be wrong, but I still respectfully disagree with the decision.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-50258885445080201912010-09-28T11:39:11.668-07:002010-09-28T11:39:11.668-07:00[continued from above]
"request-bindings/raw...[continued from above]<br /><br />"request-bindings/raw gives you a list (which you can map over) of all the binding data structures that contain this same information but in a byte-safe/file-upload-safe way."<br /><br />Now that you've pointed to the use of request-bindings/raw, it seems like you could map over the results by doing something like (map (lambda (b) (binding-form-value b)) (request-bindings/raw req)) which would get you a list of form outputs as byte-strings (My fault; I'll retract that objection from the blog post but keep the commentary for historical reasons). That means there's a workaround, but being that I'm quite likely trying to use any (non-file) bindings as vanilla strings somewhere, would it not make sense to provide that output in a simple manner? To me, the particularly bothersome part is that PLT once had such functions. In fact extract-bindings does precisely what I'm looking for in this situation, but has had a dire note attached in the documentation for quite a few versions stating that it exists for backwards-compatibility only.<br /><br />"Can you give me some suggestion to make it better?"<br />"I don't understand what you mean by "default". What is inconvenient that you wish were more convenient? As far as I can tell, there isn't really any default."<br /><br />The default seems to be the send/suspend/dispatch + embed/url way of doing it (which involves wrapping your actual response function in a `local`, then dispatching to it, or passing a lambda to send/suspend/dispatch as you showed in your example above). The url-based dispatch is provided in a separate module entirely. A better way would be the way that Hunchentoot does it, not to put too fine a point on it. Which is to say<br /><br />(define-easy-handler (test-page :uri "/easy") ()<br /> (page-template (:p "This is easier")))<br /><br />When I want a link to result in that function, I just make sure the url it calls is "/easy". This doesn't involve a call to embed/url, or an explicit local definition and dispatch call (define-easy-handler likely expands into these, but I don't have to keep typing them myself).Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-31012626391762759132010-09-28T11:38:17.847-07:002010-09-28T11:38:17.847-07:00Hello, Jay. I know who you are; this post aside I&...Hello, Jay. I know who you are; this post aside I'm actually a fan of PLT.<br /><br />"I'm interested in how it crashed, logs, stack traces, anything like that. The only thing like this I've experienced in deployments is memory related and the LRU manager alleviates that."<br /><br />It probably was a problem with limited memory, but I don't have any kind of reporting set up on the machine t's running it. What I know that I ran the server and checked back some days later to find that it no longer was (the machine wasn't restarted; other processes I started at the same time were still active and hadn't been restarted)<br /><br />"This may be what others say. In my opinion, it is good to not allow this because it stands in the way of simple inlining optimizations and analysis."<br /><br />My mistake. I thought I read a story somewhere (possibly the PLT blog; I'll check) about how difficult it was to predict the interactions of newly evaluated code with existing macros. The story seemed to suggest that this difficulty was the reason to make reloading the entire module mandatory (as opposed to letting the user evaluate piecemeal changes over top).<br /><br />In any case, my opinion is that the extra iteration speed you get during development outweighs the downsides introduced by interactive evaluation.<br /><br />"The HTTP protocol is byte-oriented. In Racket, strings are always UTF-8, but HTTP data may not be, so there is a concerted effort to not error when non-UTF-8 data is sent to the server."<br /><br />True, but most ways I've seen of handling GET/POST input don't require the developer to think at that level. Hunchentoot lets you retrieve a list of bindings (or just lets the your response functions take them as arguments), PHP gives you the $_POST variable, and Python does something similar. <br /><br />PLT's web server is the clear outlier, since it expects you to do something like (bytes->string/utf-8 (binding:form-value (bindings-assq #"[field_name_here]" (request-bindings/raw req)))) to get a single binding out in string form.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-62389975711950143232010-09-28T09:39:06.380-07:002010-09-28T09:39:06.380-07:00"There's also a few other little gotchas ..."There's also a few other little gotchas (like how awkward it is to actually create a link whose result is another scheme function,"<br /><br />(define (other-function req)<br />"You clicked me!")<br />(send/suspend/dispatch (lambda (make-url)<br />`(html (body (a ([href ,(make-url other-function)]) "Click me")))))<br /><br />I personally don't find this awkward because almost every response function starts with "(send/suspend/dispatch (lambda (make-url) ...))" so the only thing you need to do is write "(make-url the-function)" which seems pretty streamlined to me.<br /><br />Can you give me some suggestion to make it better?<br /><br />"and how url-based dispatch is for whatever reason NOT the default)."<br /><br />I don't understand what you mean by "default". What is inconvenient that you wish were more convenient? As far as I can tell, there isn't really any default. <br /><br />JayJay McCarthyhttps://www.blogger.com/profile/07912023932333508057noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-42491124813738687232010-09-28T09:38:49.208-07:002010-09-28T09:38:49.208-07:00"There's also a concerted effort from PLT..."There's also a concerted effort from PLT to keep things byte-oriented."<br /><br />The HTTP protocol is byte-oriented. In Racket, strings are always UTF-8, but HTTP data may not be, so there is a concerted effort to not error when non-UTF-8 data is sent to the server.<br /><br />"For example, there is no way to get a list of POST/GET parameters out of a request (other than "manually") in PLT scheme. "Manually" entails treating the request as an object with byte keys, which you can't map over cleanly."<br /><br />I'm not sure what you're talking about. request-bindings gives you an alist of all the parameters with their value. request-bindings/raw gives you a list (which you can map over) of all the binding data structures that contain this same information but in a byte-safe/file-upload-safe way. Is there something I'm missing?Jay McCarthyhttps://www.blogger.com/profile/07912023932333508057noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-91485314844085528152010-09-28T09:38:34.631-07:002010-09-28T09:38:34.631-07:00"Now in, PLT's defense, they're aware..."Now in, PLT's defense, they're aware of this. There was a concern about keeping LISP's inherently reflective nature, and they decided not to because it trips up so many people that they figured it wasn't worth the headaches. So the server forces you out while it runs, and the REPL bugs you to do a clean run every once in a while if your source has changed. I appreciate the sentiment, because it really was made to be a teaching tool, but I'm being mighty tempted by the dark side regardless."<br /><br />This may be what others say. In my opinion, it is good to not allow this because it stands in the way of simple inlining optimizations and analysis.Jay McCarthyhttps://www.blogger.com/profile/07912023932333508057noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-42521154805386822942010-09-28T09:38:05.973-07:002010-09-28T09:38:05.973-07:00Hi Inaimathi,
I'm the developer of the Racket...Hi Inaimathi,<br /><br />I'm the developer of the Racket Web Server. I have a few questions based on your post.<br /><br />"They do have a pretty cool web server, but it's far from fast in practice. It also seems to crash more often than I'd like for a production app. Nothing like once per week, but it's happened a few times so far."<br /><br />I'm interested in how it crashed, logs, stack traces, anything like that. The only thing like this I've experienced in deployments is memory related and the LRU manager alleviates that.<br /><br />[see next comment for more]Jay McCarthyhttps://www.blogger.com/profile/07912023932333508057noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-41174870403764308602010-09-28T07:16:40.249-07:002010-09-28T07:16:40.249-07:00@Xah Lee: Are you kidding? Thanks for the tutorial...@Xah Lee: Are you kidding? Thanks for the tutorials! They've been the most useful resource for me in learning Emacs (along with M-x apropos and M-x describe-key).Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-55438543868394446982010-09-27T23:19:41.723-07:002010-09-27T23:19:41.723-07:00oh nvm it works now. :) either i was mistaken or g...oh nvm it works now. :) either i was mistaken or going thru blogge/reader manager made it appear.Anonymoushttps://www.blogger.com/profile/11896508961236679878noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-77317084581235159162010-09-27T23:06:05.903-07:002010-09-27T23:06:05.903-07:00hi Inaimathi,
Nice article.
btw, i tried to subs...hi Inaimathi,<br /> Nice article.<br /><br />btw, i tried to subscribe your blog. Tried follow. Google reader says am already following but your blog doesn't show. Nor can i find a atom webfeed...<br /><br />ps thanks for links to my elisp tutorial.Anonymoushttps://www.blogger.com/profile/11896508961236679878noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-58312312835519601092010-09-27T06:01:05.800-07:002010-09-27T06:01:05.800-07:00@Drew: You are correct, I've updated the post....@Drew: You are correct, I've updated the post. While I was reading over, I also noticed a mis-called cl:map in number six. Really, I meant mapcar, since you need to pass a collection type to map in CL.<br /><br />@Jānis: Added a note to that effect. The point wasn't "you can't pack functions in varibles in CL", just that there's some overhead involved since it's not the default option and the two are treated as separate. By contrast, in Scheme, there is no difference. So anything you want to do in order to pass a variable around will also work on a function.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-85229954971335869012010-09-26T14:37:55.088-07:002010-09-26T14:37:55.088-07:00Minor mistake in point 4 : your last example of th...Minor mistake in point 4 : your last example of the CL:FORMAT function is missing the STREAM argument.Unknownhttps://www.blogger.com/profile/04885526471092506519noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-23457010615583675272010-09-26T14:20:49.027-07:002010-09-26T14:20:49.027-07:00I freakin' love plists while prototyping and e...I freakin' love plists while prototyping and exploring! So much clear info in debugging statements or when working in the REPL.<br /><br />I rarely replace them with classes once I'm done.aeriquehttps://www.blogger.com/profile/00198490678736556031noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-78295224874491057802010-09-26T13:51:21.565-07:002010-09-26T13:51:21.565-07:00Another note about point 6: you can do (setf (symb...Another note about point 6: you can do (setf (symbol-function 'foo) (lambda (num) (* num 2))), in which case you will be able to call FOO as a function afterwards.Jānis Džeriņšhttps://www.blogger.com/profile/06846740575608764708noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-62218424598096050042010-09-26T13:12:52.849-07:002010-09-26T13:12:52.849-07:00Thanks for pointing that out. My intention was jus...Thanks for pointing that out. My intention was just to show that there isn't a perfect isomorphism between variables and functions in CL the way there is in Scheme.<br /><br />Fixed above.Inaimathihttps://www.blogger.com/profile/14277727122990903016noreply@blogger.comtag:blogger.com,1999:blog-3016981170905406325.post-15040692720738175212010-09-26T08:49:17.466-07:002010-09-26T08:49:17.466-07:006 is a bit off. (apply (lambda (foo) bar) baz) is ...6 is a bit off. (apply (lambda (foo) bar) baz) is perfectly fine, as the first argument to APPLY evalutes to a function object. Assigning a lambda to a variable is fine, too: (setf foo (lambda () 42). The difference is that you can't then call (foo) to call that lambda and get 42, you have to use (funcall foo). But that doesn't work when you need to apply a function bound to a variable in Scheme, either.Xachhttps://www.blogger.com/profile/04498567730331742642noreply@blogger.com