ruricolist / serapeum

Utilities beyond Alexandria
MIT License
423 stars 42 forks source link

Enhancing hooks #41

Open Ambrevar opened 5 years ago

Ambrevar commented 5 years ago

Serapeum has simple hooks, but while working with Next I figured they might not be enough.

In Next we use https://github.com/scymtym/architecture.hooks mostly because I didn't know that Serapeum had hooks :p cl-hooks and Serepeum hooks seem to overlap a lot.

We've discussed some of the shortcomings of cl-hooks there: https://github.com/scymtym/architecture.hooks/issues. In short:

What's most problematic with hooks and as the Emacs experience has showed us is that they don't play well with lambda functions:

We discussed this here: https://github.com/atlas-engineer/next/issues/419.

My solution to this was to implement a "handler" type which would allow the user to add anonymous functions to a hook but with extra data so that the handler can be compared and introspected to some extent.

Thoughts? Let me know if this is a bit obscure, I can provide more examples.

ruricolist commented 5 years ago

You definitely have a point. The big advantage of hooks in Emacs is that they don't require coordination -- you can push to a hook even before the library that defines it is loaded. That doesn't work in CL, where you have to wait for the package. (I suppose you could use keywords as hooks, but that's disgusting.)

I'll read the discussions you linked. I do really like the idea of having something analogous to method combinations for hooks.

ruricolist commented 5 years ago

Note to self: cf. SRFI 173.

ruricolist commented 5 years ago

A thought: with indirection we gain the ability to check the arity of the supplied function by doing runtime compilation of a lambda: e.g. if the user provides function f we can compile (lambda (x) (funcall f x)) and the compiler might tell us if the arity is wrong.

Ambrevar commented 5 years ago

Nice thought!

About the SRFI: I actually contacted them about my thoughts, never go a reply though... :p

Ambrevar commented 5 years ago

(And I believe their implementation to be very similar to what Serapeum currently does, that is to say a tad bit too limited :p)

Ambrevar commented 5 years ago

I can work on a patch if you like.

By the way, moving to hook type will break the current implementation. What's the policy of Serapeum regarding backward compatibility?

ruricolist commented 5 years ago

I've converted the current implementation to use generic functions, so it should be possible to maintain backward compatibility with a dedicated hook class.

Ambrevar commented 5 years ago

Great!

Discussing with @scymtym from cl-hooks (https://github.com/scymtym/architecture.hooks/issues/5#issuecomment-538740860) I figured the following regarding "global, ahead of definition hooks":

Have a notion of global hooks that can be optionally associated with a type or an instance.

For instance

would return 3 different hooks (I came up with the helper functions here).

Ambrevar commented 4 years ago

https://github.com/atlas-engineer/next/pull/483 is mostly ready. Would you consider merging them here?

ruricolist commented 4 years ago

I've added enhanced hooks to Serapeum. Since they involve a fair amount of new exports, however, I've taken a different approach: Serapeum now has a contrib/ directory, and the enhanced hooks are implemented in a new package, :serapeum/contrib/hooks.

Ambrevar commented 4 years ago

Thanks a lot!

This hook implementation has proven invaluable for Nyxt so far. There are still a few points to complete though, see the TODO: in the code. Your insights are welcome!