Environment types should be strongly typed
Problem
I would consider this behavior a bug:
#[ink::contract]
pub mod foobar {
#[ink(storage)]
pub struct Foobar {
value: BlockNumber,
}
impl Foobar {
/// Constructor with mismatching type:
/// Timestamp vs. BlockNumber.
///
/// The `value` param is `Timestamp` here, but
/// `BlockNumber` in storage.
#[ink(constructor)]
pub fn new(value: Timestamp) -> Self {
Self { value }
}
#[ink(message)]
pub fn get(&self) -> BlockNumber {
self.value
}
}
}
It works because BlockNumber and Timestamp are type aliases to the same underlying type u64. This is expected behavior of Rust, since type is just an alias here.
I would argue that in our context BlockNumber and Timestamp are explicitly meant to be different things. It should not be possible to use them interchangeably in the way above. If one intends to do that one should e.g. implement From.
The way we have it now can lead to unintended behavior and hence bugs. Same thing goes for type Balance, which just doesn't enable the behavior above since it's u128 for our chain configs.
Solution
I have no idea how to solve this properly. I discussed briefly with @Robbepop and two options came up:
- Implement wrapper types, which usually leads to inconveniences.
- Implement the new-type pattern for these types, which might get complex and cause issues for methods which have a
selfreceiver.
ToDo
- [ ] The
Environmenttypes should be strongly typed.
I'm not convinced this should be considered a bug.
In my mind, this is no different from a programmer accidentally mixing up argument names (timestamp instead of block_number).
E.g:
pub fn new(timestamp: BlockNumber) -> Self {
Self { value: timestamp }
}
ink! is intended to be as close to idiomatic rust as possible. If this behaviour is "normal" in classic rust, I don't see a reason why we should be concerned with it either.