BUT I'd much rather get rid of the "this link has expired" syndrome.
Fast is only impressive if the results are modern.
BUT I'd much rather get rid of the "this link has expired" syndrome.
Fast is only impressive if the results are modern.
I do that much more often than I hit an expired link.
Here's an example. Currently if you go to the home page and then click the "More" link at the bottom to go to the next page, and wait long enough, the more link expires. That's because it's currently implemented as something like this (not sure about ARC syntax, I'll use Scheme syntax here, but you get the idea):
(define (show-list-of-posts page-number)
... display the rest of the homepage ...
(link "More" (lambda () (show-list-of-posts (+ 1 page-number)))))
This stores the closure `(lambda () (show-list-of-posts (+ 1 page-number)))` with the free variable `page-number` in a hash table on the server. The URL becomes an index into that hash table. But the only information needed to reconstruct such a closure, is the function body and the free variables. So if we defined an auxilary function: (define (foo page-number)
(show-list-of-posts (+ 1 page-number)))
then we could represent the closure as the pair ("foo",page-number). If we encode that in the URL, then instead of looking up the closure from the hash table, we can reconstruct the closure on the fly. Hence we do no longer have to store anything on the server, and no links can expire anymore.There are some challenges when you want to do this transformation automatically, but they can be overcome.
I don't think this is strictly true. The comments and reply links simply link to a normal (non-closure) URL on the site and the page is generated from that URL in the normal manner.
The reply links have a parameter 'id' - the id of the comment to which the reply is being posted. I would guess it's just passed to a normal function which adds the reply to the post.
May be you mean the same thing, but "serializing closures in the url"(where? all I see is the id of the post being replied to) isn't the same as params in the url which are then passed to a function.
If you have a lambda expression like `(lambda () (show-list-of-posts (+ 1 page-number)))`, the Scheme implementation does these things:
1. Introduce a global function definition with the same body as the lambda expression but with an extra parameter for the free variables. The free variables in the body of the function get replaced with expressions that extract their value from the extra parameter that has the free variables.
2. Convert the lambda expression to an expression that builds a pair of a function pointer to that global function, plus the values of the free variables.
For example the code:
(define (show-list-of-posts page-number)
... display the rest of the homepage ...
(link "More" (lambda () (show-list-of-posts (+ 1 page-number))))
Will get converted to something like this: ;; this is the extra global function that has the body of the lambda expression
;; note that the reference to `page-number` got
;; replaced by `(extract-value "page-number" params)`
(define (closure-324 params)
(show-list-of-posts (+ 1 (extract-value "page-number" params))))
;; note that the lambda expression gets replaced by a create-closure expression
(define (show-list-of-posts page-number)
... display the rest of the homepage ...
(link "More" (create-closure closure-324 "page-number" page-number)))
create-closure creates a closure data structure where the first argument is the function pointer, and the rest of the arguments are the free variables.Now, what happens if you want to remove this closure business in a web application, and instead use normal URLs?
First, you introduce a global request handler for the body of the lambda:
(define-handler (post-list-handler params)
(show-list-of-posts (+ 1 (extract-value "page-number" params))))
This would define the handler for news.ycombinator.com/post-list-handler?page-number=12.Then, instead of the (link ...) with a closure, you just link to that url in the show-list-of-posts function:
(define (show-list-of-posts page-number)
... display the rest of the homepage ...
(link "More" (create-url post-list-handler "page-number" page-number)))
Compare these code snippets to the one above. Do you see the similarity to closure conversion? In both cases we:1. Introduce a global function/handler for the body of the lambda.
2. That function/handler gets a `params` argument that has the free variables.
3. Everywhere a free variable is referenced in the body, it gets replaced by an expression that extracts the value from the params argument.
4. In place of the lambda expression, we have respectively a (create-closure func free-vars...) or a (create-url handler free-vars...)
So it's really completely analogous. That's why I say that we are just serializing the closure here, and this could be done automatically. Hopefully this makes it more clear what I mean, but maybe these details just make it less clear if you're not familiar with how closures are implemented (closure conversion)...
Great explanation of what's causing that - thank you!
I suspect hindering spam and vote manipulation plays a part in the architectural decisions. It also makes it possible to create different HN's for different users - e.g. the hellbanned, royals, and plebeians.
This is particularly infuriating on a cellphone.
One quick fix: in the code that prints this message, check to see if the request was a comment-post action. If so, append, "...but for your convenience, here's the text you tried to post, so it's not lost forever: [...]"
(Just watch out for XSS!)