6

When declaring types, with generic parameters, to be stored in runtime storage, it’s common to see this pattern

#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
pub struct MyItem<TypeA, TypeB> {
    pub item_a: TypeA,
    pub item_b: TypeB,
}

type MyItemOf<T> = MyItem<<T as Config>::TypeA, <T as Config>::TypeB>;

However, this seems a bit clunky, and I have tried the following

#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
pub struct MyItem<T: Config> {
    pub item_a: T::TypeA,
    pub item_b: T::TypeB,
}

only to get an error saying that T doesn’t implement TypeInfo. This is what I ran into in the past, so I've used the first pattern above for some time.

There’s a way to get the second approach above to work by using #[scale_info(skip_type_params(..))] to tell scale_info to ignore that T doesn't implement TypeInfo.

Still, I run into the error that MyItem<T> doesn't implement parity_scale_codec::MaxEncodedLen. I've looked around and found that the Substrate Kitties tutorial uses the #[codec(mel_bound)] attribute on its Kitty<T> struct. I found that it also works in my case and I ended up with

#[derive(Encode, Decode, MaxEncodedLen, TypeInfo)]
#[scale_info(skip_type_params(T))]
#[codec(mel_bound())]
pub struct MyItem<T: Config> {
    pub item_a: T::TypeA,
    pub item_b: T::TypeB,
}

However, I don't quite understand how #[codec(mel_bound())] works and what are the tradeoffs involved with it. I couldn't find much documentation around it. Would anyone be kind enough to explain how it works?

1 Answer 1

5

skip_type_params(T) boils down to the same as mel_bound(), both will have an empty where-bound for the implementation of MaxEncodedLen. The advantage of skip_type_params is that if there are more generic parameters it is easier to skip single ones, while mel_bound() skips all generic parameters.

By default the macro will put the following where-bound: T: MaxEncodedLen. As you already have seen, this is wrong. So, we have the mel_bound attribute which lets you as a developer write the where-bound manually. You could write mel_bound(T::TypeA: MaxEncodedLen, T::TypeB: MaxEncodedLen) and it would compile as well. However, you don't need this because you probably have the bound on TypeA: MaxEncodedLen in your trait declaration. So, you just write mel_bound() to get an empty where-bound.

There is actually an issue to also add skip_type_params support to scale-codec: https://github.com/paritytech/parity-scale-codec/issues/316

1
  • Thanks a lot for your answer! I hope these things can be unified in the future with skip_type_params
    – Angelo
    Apr 19, 2022 at 21:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.