@Dennis-Zhang (Dennis Zhang) posted a new topic, subject "How to pass any amount of arguments in closure?". It read:

   Hi, I know that RFC of variadic generic in rust is still on-going, but how could we pass uncertain number of arguments?  
    let's say I have a field f: FnOnce() -> T, I want f to take any possible arguments, maybe f(1), maybe f(1, 2), how to do it?  
    Thanks in advance

@s3bk (S3bk (post content: CC BY-NC 4.0)) replied

    The short answer is that you can't.
    
    In your example you could take a `&[i32]`.  
    Or something like `serde_json8b7c:f320:99b9:690f:4595:cd17:293a:c069Value` that can be inspected to find out what it is. If you know exactly what type you are expecting, downcasting `Any` will work.

To which @Cerber-Ursi replied

    Dennis-Zhang:
    
    > I want f to take any possible arguments, maybe f(1), maybe f(1, 2), how to do it?
    
    The main question is, what do you want to do with these arguments? The "how?" in such cases fully depends on "why?", as there might be multiple possible ways to do this, with different pros and cons.

Then @Dennis-Zhang (Dennis Zhang) said

    actually I want to implement a very simple version of partial function in rust, so the function could be any kind of function with different numbers of arguments

Then @Michael-F-Bryan (Michael Bryan) said

    You can't do this for _any_ number of arguments, but it's possible if you have a specific function signature in mind.
    [code] 
        fn partially_apply(
          n: u32, 
          func: impl Fn(u32, &str, Vec<u8>) -> usize,
        ) -> impl Fn(&str, Vec<u8>) -> usize {
          move |s: &str, v: Vec<u8>| func(n, s, v)
        }
        
    [/code]
    
    This is kinda awkward, though. So there's a good chance you won't be able to reuse the same partial application and currying tricks you get with normal functional languages.

Then @Dennis-Zhang (Dennis Zhang) said

    so I try to copy the way axum did to handler, but it came out with non-sized problem, the link is:  
    Rust Playground (rust-lang.org)

So @Cerber-Ursi replied

    Well, there are two obvious reasons:
    
      * Axum implements `Handler` for generic parameter, not for `dyn Trait`.
      * Axum doesn't try to store `dyn Handler` directly anywhere - it must be behind some pointer (most probably `Box`).

So @Dennis-Zhang (Dennis Zhang) replied

    well the first one I think it's the same, axum impl for dyn trait also, the second, I didn't know know about that

To which @Cerber-Ursi replied

    Dennis-Zhang:
    
    > axum impl for dyn trait also
    
    Could you show the implementation you're talking about? I've linked to the (simplified) `impl<F: FnOnce> Handler for F`, there's no `dyn FnOnce` here.

To which @Dennis-Zhang (Dennis Zhang) replied

    yes but in where it's a Fn right? isn't where would put a dyn before it?

To which @jjpe replied

    In principle it's possible to write an `Args` trait:
    [code] 
        enum ArgError {
            IndexOutOfBounds {
                index: usize, 
                num_args: usize
            } 
            // any other applicable variants here
        } 
        
        trait Args {
          fn get(&self, index: usize) -> Result<&dyn Any, ArgError>;
        }
        
    [/code]
    
    You could then implement that trait for tuples of various lengths.  
    Of course whether that will work or not depends on your use case, and you'll have to downcast the arg returned by `get()` in order to get any use out of it, so it's not exactly michelle37@example.net.

@Dennis-Zhang (Dennis Zhang) replied

    Hi thank you for replying! I solved the above problem but I am a noob to macro, how can I expand a vec in a macro and pass the values of the vec to a function? like I have a vec[1, 2, 3] and expand it to f(1, 2, 3)?

To which @Cerber-Ursi replied

    Dennis-Zhang:
    
    > how can I expand a vec in a macro and pass the values of the vec to a function?
    
    It's impossible, since macros can't generate different code depending on runtime values.

So @Dennis-Zhang (Dennis Zhang) replied

    You are right, I probably need unstable feature to call the function

After which, @Michael-F-Bryan (Michael Bryan) added

    Can you provide an example of where you need partial function application?
    
    It might be that we've gone down the rabbit-hole of variadic generics and implementing traits on tuples when actually there might be a much nicer solution if we take a step back.
    
    On the surface, this sounds quite similar to the "decorator pattern".
    [code] 
        trait Foo {
          fn bar(&self) -> usize;
        }
        
        struct Concrete;
        impl Foo for Concrete { fn bar(&self) -> usize { 42 } }
        
        struct AddOneDecorator<F>(F);
        
        impl<F: Foo> Foo for AddOneDecorator<F> {
          fn bar(&self) -> usize {
            let initial_value = self.0.bar();
            initial_value + 1
          }
        }
        
    [/code]
    
    You shouldn't need to reach for `nightly` for something like this. I'm sure there are alternate solutions or ways of phrasing the problem.

So @Dennis-Zhang (Dennis Zhang) replied

    Hi it's all for learning purpose, I am learning rust and haskell at the same time, so I want to implement something that can be done easily in haskell, I made something like this: Rust Playground (rust-lang.org), but I met another problem, trait object can not downcast back to its type in runtime, could you help me?

@Michael-F-Bryan (Michael Bryan) replied

    Dennis-Zhang:
    
    > but I met another problem, trait object can not downcast back to its type in runtime, could you help me?
    
    Check out the `st8b7c:f320:99b9:690f:4595:cd17:293a:c069any` module.
    
    Dennis-Zhang:
    
    > I am learning rust and haskell at the same time, so I want to implement something that can be done easily in haskell
    
    I'm sure you already know this but keep in mind that Rust and Haskell have different values and opinions, so something that may be easy or idiomatic in one language may be awkward or downright impossible in another (e.g. Rust can't generalise over different classes of monads, Haskell doesn't let you use pointers and requires a GC).
    
    I'm not saying "don't do that", it's actually really beneficial to know the strengths and limitations of each language, but just be aware that there may be points of friction when you try to implement a certain pattern from language A in language B. You might also get some funny looks or people asking why you are using a really complex solution when there is a much simpler, idiomatic way to do it.

To which @Dennis-Zhang (Dennis Zhang) replied

    Hi I checked Any before and it's not what I want, because I do not know the runtime type either, I did found a library implement partial application function but it's all macros and I can hardly understand it, thanks for the comment!

@Michael-F-Bryan (Michael Bryan) replied

    Dennis-Zhang:
    
    > I checked Any before and it's not what I want, because I do not know the runtime type either
    
    This should be possible. Maybe if you have an example of the code you'd like to write we can figure it out in a separate thread?

Then @Dennis-Zhang (Dennis Zhang) said

    Hi Michael, I am sorry I didn't save the code, it's all for practice, and someone else already did a more elegant way than I did so no reason to keep it ha ha

Then @system (system) said

    This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.


{'source': 'discourse', 'url': 'https://users.rust-lang.org/t/how-to-pass-any-amount-of-arguments-in-closure/70508', 'title': 'How to pass any amount of arguments in closure?', 'views': 707, 'has_accepted_answer': True, 'word_count': 1205, 'like_count': 5, 'reply_count': 14, 'participant_count': 5, 'posts': 21, 'tags': '', 'author': '@Dennis-Zhang (Dennis Zhang)', 'participants': '@Dennis-Zhang (Dennis Zhang), @s3bk (S3bk (post content: CC BY-NC 4.0)), @Cerber-Ursi, @Michael-F-Bryan (Michael Bryan), @jjpe, @system (system)', 'image_url': [None], 'created_at': '2022-01-18T07:33:29.270Z', 'last_posted_at': '2022-04-20T07:42:26.502Z'}