ink icon indicating copy to clipboard operation
ink copied to clipboard

The `call_builder` macro to provide a more developer-friendly way to work with `CallBuilder`

Open xgreenx opened this issue 1 year ago • 2 comments

Overview

Implemented the call_builder! macro from the proposal.

The macro return the CallBuilder type that supports hinting and highlighting in the IDE. The usage is the same as for standard cross-contract calls, where the call is wrapped into the call_builder macro:

#[ink::trait_definition]
pub trait Increment {
    /// Increments the current value of the implementer by one (1).
    #[ink(message)]
    fn inc_by_delta(&mut self, delta_1: u64, delta_2: u32);

    /// Returns the current value of the implementer.
    #[ink(message)]
    fn get(&self) -> u64;
}

#[ink(message)]
fn get(&self) -> u64 {
    self.incrementer.get();
    call_builder!(self.incrementer.get()).invoke();
    call_builder!(::dyn_traits::Increment::get(&self.incrementer)).invoke();
    call_builder!(<_ as ::dyn_traits::Increment>::get(&self.incrementer))
        .invoke();
    call_builder!(Increment::get(&self.incrementer)).invoke();
    call_builder!(::dyn_traits::Increment::get(&self.incrementer)).invoke();

    call_builder!(self.incrementer().get()).invoke()
}

#[ink(message)]
fn inc_by_delta(&mut self, delta_1: u64, delta_2: u32) -> u64 {
    self.incrementer.inc_by_delta(delta_1, delta_2);
    call_builder!(self.incrementer.inc_by_delta(delta_1, delta_2)).invoke();
    call_builder!(::dyn_traits::Increment::inc_by_delta(&mut self.incrementer, delta_1, delta_2)).invoke();
    call_builder!(<_ as ::dyn_traits::Increment>::inc_by_delta(&mut self.incrementer, delta_1, delta_2))
        .invoke();
    call_builder!(Increment::inc_by_delta(&mut self.incrementer, delta_1, delta_2)).invoke();
    call_builder!(::dyn_traits::Increment::inc_by_delta(&mut self.incrementer, delta_1, delta_2)).invoke();
    let call_builder =
        call_builder!(self.incrementer.inc_by_delta(delta_1, delta_2));

    call_builder.invoke()
}

How it looks in the IDE: image image

Follow-up

  • In the same way, we can add the create_builder! macro for constructors in the follow-up PR. It would simplify instantiation because all functions will be highlighted. The macro would be much simpler because it always requires an explicit type name.
  • Add mesage_descriptor! macro that returns the MessageDescription. Everyone would be able to get the method's selector(and other properties of the message) like in the solidity message_descriptor!(self.balanec_of).selector().
  • Remove the TraitCallBuilder and replace its functionality with a new macro. Remove the {method_ident}Output associated type from the trait definition.

xgreenx avatar Jul 26 '23 14:07 xgreenx

I am not fun of the macro's interface. Wrapping every single call into the macro just to get the syntax highlighting for the .invoke() or .try_invoke() commands doesn't seem very idiomatic IMHO.

Perhaps, if we could do something like:

self.incrementer.get().invoke()

It would be much clearer to the developer. I am open to other proposals too.

SkymanOne avatar Jul 26 '23 18:07 SkymanOne

It is a syntax for a rare case when the developers need to work with a result of the cross-contract call. Primarily, you work with methods directly like self.incrementer.get().

The idea of this change is to remove the {method_ident}Output alias from the trait in the follow-up PR. So it is impossible to support self.incrementer.get().invoke().

xgreenx avatar Jul 26 '23 18:07 xgreenx