Arc Forumnew | comments | leaders | submitlogin
3 points by hjek 506 days ago | 9 comments
Does anyone know what the deal with the `hook` function in Arc is? What does it do and why?

Take for example news.arc. It looks like `hook` is called several times without `defhook` ever being called, so it would seem like it does ... nothing?

2 points by shader 506 days ago | link

The idea behind a 'hook' is that it is a place where code can be inserted without having to modify the original code. They're pretty common in emacs, for instance, where lots of packages provide hooks for easy extension in your .emacs file.

Arc hooks are apparently pretty lightweight:

  (= hooks* (table))

  (def hook (name . args)
    (aif (hooks* name) (apply it args)))

  (mac defhook (name . rest)
    `(= (hooks* ',name) (fn ,@rest)))

So, if there's a function bound to that name in the hooks table, it is run with the arguments. You only call 'defhook when you want to bind to that point in the code.

This is a rather interesting implementation to me, because I'm used to the emacs-lisp concept, where a hook is actually a list of functions that all get called on the arguments, so it can be added to multiple times. The corresponding names in elisp are 'run-hooks and 'add-hook.


2 points by hjek 506 days ago | link

Ok, makes sense. Thanks for the explanation!

So I guess it's on purpose that `(hook 'somewhere)` doesn't do anything until you define a hook for that place yourself, e.g.:

    (defhook somewhere () (pr "Hello from somewhere"))


4 points by shawn 448 days ago | link

Yes, the hooks exist because there was a lot of custom code that had to be injected somewhere. Much of HN's source code was not suitable for public release, even back in 2008.

Suppose you had to maintain an open source version of a codebase with closed-source elements. The hook functions here are the perfect way to do this.

For example, you'll notice pg does not appear on (and never has). The logic to filter his username must exist somewhere. It likely existed as a hook.


3 points by i4cu 443 days ago | link

I've found the 'hook' mechanism to be really useful. I use the same thing in an app I'm writing (in cljs) which auto creates web applications via data schematics.

When my app compiles a new app there's a little routine that adds/removes pre-defined function calls from within a table. So then when cljs compiles the client side code (which performs dead code elimination) the functions that are hooked into the table get added, but the others are eliminated. The cljs dead code elimination process couldn't do this alone; it required being able to hook/unhook code depending upon the app schematic.

Anyways, just wanted add to your point on how useful this feature can be.


2 points by shawn 443 days ago | link

Correction: the reason pg doesn't show up on the leaderboard is that he's an admin, and admins are filtered out here:

Poor example notwithstanding, the rest of my comment is probably correct. There was custom code that couldn't be shipped in the public release of news.arc.


2 points by krapp 505 days ago | link

I'm hoping to have some functionality for this wired into an update of prompt.arc and pushed soon.

It might be useful to be able to write app scripts and attach them or detach them from hooks. That seems like it would be a decent basis for a plugin system.

Or not, I don't know. We'll see I guess.


3 points by krapp 503 days ago | link

OK, I have a stupid question. How do I remove an item from a table?

Apparently it's (rem test table) but everything I've tried fails with "Can't take car of #hash(("foo" . (app-run "foo")))" I also thought I might have to assign nil to it but that returns an error as well. Here is my current code if it helps... it's just minor edits of prompt.arc, assignment and running an app in a hook all work:

    (def app-unhook (user app)
      (do ((rem !app hooks*) 
          (editor-page user "Hook removed from " app))))

    (def app-hook (user app) 
      (if (file-exists (app-filepath app))
        (do ((= (hooks* app) `(app-run ,app))
            (editor-page user "Hook applied to " app)))
        (editor-page user "Error: No application " app)))
I feel like I'm probably missing something obvious.


3 points by i4cu 503 days ago | link

rem only works on seqs, you need to set the value to nil:

  (= (mytable 'key) nil)
and tables don't hold nil valued entries so it works.


2 points by krapp 503 days ago | link