-
Notifications
You must be signed in to change notification settings - Fork 326
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
Rust code generation independent of FaustDsp trait #1062
Conversation
Thanks. Testing here with faust2portaudiorust tool, but I gets runtime error like:
so I guess the current port audio architecture, which use a fixed Can you have a look ? |
Merged thanks. |
ah now i understand the context of the other comment on the other pr better ... yes i will have a look. |
Could we wait a little bit with making this change? I have a substantial 'productive' usage of Rust + Faust, and I would like to test how this change would impact it. Unfortunately I'm travelling right now, and will only have access to a PC in a few days again. Specifically I want to verify if using ambiguous method vs impl names doesn't cause issues (hopefully it doesn't require using fully qualified names). Also, I'm seeing that some of the trait methods have been removed, and I'm wondering if it is easy to work around the missing functionality. |
The merged commit is here: 28a8b1a and is not involving any change in the architectures files. So hopefully it should not break anything. Please yes give feedback. In a more general term, @crop2000 we definitively have to be quite careful. As I said, I don't have expertise and time enough to be the final judge. @bluenote10, @obsoleszenz at least have to give their feedback each time. |
Agree. Let's move this one carefully. Maybe first introduce it behind a feature flag. But for sure am with @crop2000 that the rust code gen could be improved a good bit. |
@sletz yes commit 28a8... does not change the interface at all. It extents it providing a new function. @bluenote10 when you are able to share your architecture file it would be interesting. I don't aim to rush this PR, but i like to keep it minimal so i don't want to improve the architecture files in this PR. Just want to keep them working in the context they worked before. (Outdated jack etc...) |
@obsoleszenz a feature flag would increase the maintainance burden. Because it would double the code. I rather try to find a solution that works with a drop in extension, that reproduces the old behavior. |
I can confirm that 28a8b1a works well for me, and I like the idea of having that
My architecture file is rather boring: use crate::types::{FaustDsp, Meta, UI, ParamIndex};
type F32 = f32;
// Generated intrinsics:
<<includeIntrinsic>>
// Generated class:
<<includeclass>> What is crucial in my use case it to have a common interface for all generated DSPs (I have many), i.e., I naturally need a trait, and all generated DSPs are supposed to re-use the same base types. I have experimented a little bit with this feature branch, and I was able to make my usages work with it as well (by also forwarding the missing methods). So in principle I would be fine with the change. However, I don't really see yet why we want to go in that direction. So far I see a few minor downsides:
If I understand it correctly, this change was motivated by supporting |
Hi @bluenote10, My motivation for this and following changes is to keep the code generated by faust small and at the same time make the interface more flexible. I consider the FaustDsp trait flawed. It seems to me that it is designed like a object. It has for example the anti pattern to specify a new function for the trait. The functions I removed from the trait cannot be called from a trait object, because they don't have a self argument. The following will not work:
Did you try to generate your code with those functions removed from your trait specification? did you see this discussion: #1059 |
@bluenote10 I have an idea. we move this block
into the code generated by faust (with the 3 functions i criticized above). and add a flag like --no-faustdsp-trait to make it optional. This allows us to be fully backward compatible. In the long run I think we can come up with traits that are better specified ... the FaustDsp implementation would in that case redirect to those implementations. This doesn't solve the issue with the clippy lint you mentioned but this lint would appear in code generated by rust and not in the architecture file so i think this would be less of a problem. |
For use cases that need a trait the generated code is significantly larger due to having two impl blocks now. My git stats on my project after incorporating this change says ~500 lines of code more.
That is rather vague. The trait is not object safe, it is supposed to be used statically / generically.
To clarify: Having static factory methods in a trait is per se obviously not an anti-pattern -- it's basically just what the
Well, of course, they are static factory methods, so you have to use them like e.g.
Yes, but then everything breaks for me. My usages are all generic based on the trait. Think of usages like: pub fn create<D: FaustDsp<T = AudioFloat>>(sample_rate: i32) -> D {
let mut instance = D::new();
instance.init(sample_rate);
instance
}
pub fn extract_param_defs<D: FaustDsp<T = AudioFloat>>() -> Vec<DspParamDef>
where
T: Clone,
{
let mut ui_builder = DeclarativeUIBuilder::new();
D::build_user_interface_static(&mut ui_builder);
ui_builder.get_param_defs()
} For the record, I have pulled out the history where we switched from non-trait to trait: #448 At that time, this was generally preferred by e.g. @bkfox as well (#409 (comment)), because their use case also required having a common interface for all generated DSPs. I think it basically comes down to:
The question is how flexible does it have to be? The flip side of flexibility is instability and accidental breaking changes. For usages that need a common denominator for multiple generated DSPs arbitrary flexibility can be detrimental: Each method generated inside the impl block would raise the question: Is this method guaranteed to exist in all DSPs? Is this method signature always the same (e.g.
Yes, I wasn't really sure where to comment. Feel free to move the discussion back to that issue. |
That is how it currently works, right?
This could work, but doesn't it make the generation rather complex because it needs to support placing the method in either impl blocks? I would love to understand how much flexibility we really need to make up my mind if giving up on traits is really better. |
I find it difficult to really see what this pr changes, can we have some before/after code generation example? |
https://gist.github.com/crop2000/9f6a0c628df5c920c6f83e3ea5df5540 as generated in the impulse-tests using https://github.com/crop2000/faust/blob/rust_no_traits/tests/impulse-tests/archs/rust/architecture.rs please ignore the changes to the other architecture files for now. |
@bluenote10 I will make a commit with the proposed changed so that we don't have misunderstandings about what i propose. |
one point about what i think is important about traits they should only define what is needed for one task. In our case the information for UI and the compute function are not directly related and should have separate traits. It would be very bad to let the generated code change the FaustDsp trait itself For example by including compute_arrays() to FaustDsp the latest proposal to keep the FaustDsp as an optional feature in the generated code helps to ensures backward compatibility as long as the trait definition is not changed. |
The main change is to switch the code generation from producing a
In case one knows the specific type e.g.
That is true, but a few things to consider:
But that is essentially why I was asking about how flexible the interface should be, i.e., which parts may change. Once we have identified the variability of the traits, we could make a more informed decision how to split them up. |
in commit e21f3f0 i moved the FaustDsp trait impl block into a function in code generation for backwards compatibility. I see that this makes sense as a reference implementation to ensure backwards compatibility. for example if compiled with -ec flag the implemetation for compute in FaustDsp would either panic or call self.control() before self.compute() ... just as an example that it creates space for improvements and behavior changes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change looks generally good now after the last adaptation. Forwarding from the trait methods to the inherent methods is probably a viable strategy and there is no breaking change.
@@ -287,7 +287,7 @@ class RustInstVisitor : public TextInstVisitor { | |||
// impls, we need a mechanism to forward the information whether to use "pub" | |||
// or not. In the worst case, we have to prefix the name string like "pub fname", | |||
// and handle the prefix here. | |||
*fOut << "fn " << inst->fName; | |||
*fOut << "pub fn " << inst->fName; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this change about? (I couldn't really figure out what it affects during the code gen.)
Is the comment actually still valid after this change, because now function are no longer only attached to a trait as the first sentence says?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
i think it influenced the generation of get_num_inputs() before i changed it in the other pr.
i would remove the pub again.
Since functions are not attached it wouldn't matter if they are prefixed with "pub".
But because this is for internal functions we don't need pub.
I don't think the comment makes sense so I would remove it completely.
fc2c91b
to
305364b
Compare
0f17e99
to
fd78708
Compare
I am thinking to remove the option to not generate the trait from this PR. |
807c116
to
3187d5f
Compare
@bluenote10 do you agree with this pr? |
Yes, as far as I can see this strategy should be fine. It probably makes sense to merge #1066 first, because this PR seems to (partially?) contain the same changes, right? |
this pr contains the commit of #1066 because it builds on it. I opened a separate pr to keep the scope of each change clear. |
3187d5f
to
b1c7993
Compare
treat FaustDsp as a interface faust code is generated as implementation on the dsp struct provide FaustFloat type alias the type alias can be used also in the architecture file to make them compatible to both f32 and f64 use consts in trait impl and remove obsolete io functions use usize for count in impl use usize for count in compute call thanks to @bluenote10 for some fixes
b1c7993
to
34f8db6
Compare
@sletz this PR is now also ready to be merged. |
Merged thanks. Be sure to check |
I will review the architecture files in the next days |
faust code generation should not specify traits.
this pr introduces this change.
It is tested against the impulse-tests using the architecture file in its subfolder.
How much architecture files need to change depends on how traits are used.
The jack cpal and minimal architecture files could be compiled after minimal changes,
but need more cleanup work.