Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add functions for setting default custom layers #608

Merged
merged 2 commits into from
Nov 12, 2020
Merged

Conversation

christopher-dG
Copy link
Member

@christopher-dG christopher-dG commented Oct 29, 2020

Some motivation for this: BrokenRecord.jl wants to add some behaviour to all calls to HTTP.request, which sounds like a good case for a custom layer, but since it is not in control of where HTTP.request is called, it can't insert a modified stack into all those calls. Instead, it uses Cassette to achieve something similar, and it works, but it can be horribly slow. With the ability to add default layers, BrokenRecord would no longer need Cassette and would be 500000x faster and more reliable.

Naming for these functions is open for discussion, I didn't think too hard about it.
I tried to keep the API similar to the existing insert function.
If something like this is actually wanted, I'll write some documentation for it.

  • Running a test suite with currently released BrokenRecord: 143s 😴
  • Same test suite with new HTTP + BrokenRecord: 28s 🔥

export Layer, next, top_layer, insert
export Layer, next, top_layer, insert, insert_default!, remove_default!

const EXTRA_LAYERS = Set{Tuple{Union{UnionAll, Type{Union{}}}, UnionAll}}()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmmm.....I don't quite understand the eltype of the Set here; why all the Tuple/Union/UnionAll dance?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was trying to keep all the type parameters as concrete as possible. The Set elements are Tuples with two elements: the first is the before layer, which can be either a Type{<:Layer} or Type{Union{}} (in the case that we insert a layer as the last layer), and the second is the custom layer, which is always a Type{<:Layer}. Since layer types are always parametric, a non-parameterized layer type is a UnionAll. Does that make sense? Maybe it's totally unnecessary to parametrize the Set like this.

@oxinabox
Copy link
Member

When I saw BrokeRecord.jl I thought it was a good use case for a custom layer and was surprised that it instead used cassette.

@christopher-dG
Copy link
Member Author

Yeah, it's not possible (AFAIK). If some transitive dependency calls HTTP.get, there's no way to put a custom layer in there.

@christopher-dG
Copy link
Member Author

Any more thoughts on this @quinnj?

Copy link
Member

@quinnj quinnj left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I don't love this approach, but I think it's fine w/ our current setup. I've started mulling over ideas for removing the strongly typed layer system for something a little simpler; like perhaps using an array of "layer functions" (which would work similarly to the approach in this PR), or something along those lines.

@quinnj quinnj merged commit ff009e8 into master Nov 12, 2020
@quinnj quinnj deleted the cdg/default-layers branch November 12, 2020 06:56
@findmyway
Copy link

This feature is quite useful.

One thing I do not understand is, why is a Set used here, isn't the order guaranteed?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants