djc / askama

Type-safe, compiled Jinja-like templates for Rust
Apache License 2.0
3.45k stars 218 forks source link

Template can't be turned into a trait object #238

Closed dnsco closed 4 years ago

dnsco commented 5 years ago

First off, thanks for the crate!

Since the size_hint function has not constraints on things being sized, and has no receiver the Template trait can't be changed into a Trait Object. Could this function be moved out of this trait, or could it be turned into a method?

I would like to be able to box my templates, rather than compile with monomorphization to keep compile times down.

Thanks!

djc commented 5 years ago

Some discussion here: https://internals.rust-lang.org/t/allowing-calling-static-methods-through-trait-objects/10417

djc commented 5 years ago

If you'd like to add dyn_size_hint() method to the trait as proposed as a workaround there, I'd be happy to merge that! Should be a fairly straightforward change.

jbg commented 4 years ago

I’m also seeing long compile times partly caused by having a lot of templates. I had a read through that thread and played around with adding a dyn_size_hint() method but I can’t quite understand how to do this in a backward-compatible manner.

djc commented 4 years ago

What kind of backwards compatibility are you looking for? Let's start with a backwards-incompatible version, and then see how backwards incompatible it actually is.

(FWIW, I don't expect it to be much of an issue since Askama provides the trait and also itself generates the implementations.)

jbg commented 4 years ago

As far as I understand the discussion, the idea is to split the trait in two. One trait is object-safe and another trait contains the methods that would otherwise make the trait non-object-safe (and is automatically implemented for anything that implements the first trait and is Sized).

I think this would necessarily be a breaking change to the public API of Template since size_hint() is part of that public API.

Either size_hint() remains in Template with its current signature, which makes the trait non-object-safe, or it moves into a separate trait, which is a backward compatibility break.

djc commented 4 years ago

But my thing is that size_hint() is not a very important part of Template, in the sense that probably a minority of users is using it other than through the integrations included in Askama. Of course I could be wrong about that... but I don't mind making a backwards-incompatible release, anyway (and based on the crates.io data, people are upgrading enough anyway). Let's move size_hint() to a different trait.

jbg commented 4 years ago

OK, great. I will send a PR soon!

jbg commented 4 years ago

I opened two PRs with different approaches.

269 is closer to that discussion linked above. You can derive Template as normal and then do (&tpl as &dyn TemplateDyn) or Box::new(tpl) as Box<dyn TemplateDyn> to get a trait object.

270 is a lighter change, it just moves the no-receiver size_hint() method into a separate trait, updates askama_derive to also produce impls for that trait, and if users want to get a size hint for a template without an instance they just need to import that trait. Since Template no longer has that method it's now object-safe and you can create trait objects.

djc commented 4 years ago

Should be fixed by #270.