The better way to define the variable __gap in the proxy contract

Thanks for sharing, very helpful tutorial.

I was wondering if there was some resource available to better understand how to implement the __gap variable you are using in all your upgradeable abstract contracts (i.e. on v4.3.2 OwnableUpgradeable.sol where line 77 is uint256[49] private __gap;.

Does that mean that we're reserving 49 uint256 storage slots?
Will we then be able to declare new single variables pulling from that storage space? Something like

// V1
uint256[49] private __gap;

// V2
uint256[48] private __gap;
uint256 private myNewVar;

Also, will it then be necessary to provide a number of similar solutions for each possible type (i.e address) we might have to implement?

uint256[49] private __gapUint256;
address[49] private __gapAddress;

// V2
uint256[48] private __gapUint256;
uint256 private myNewUintVar;
address[48] private __gapAddress;
address private myNewAddressVar;

Thanks for your insight, the docs only barely mention this practice (https://docs.openzeppelin.com/upgrades-plugins/1.x/writing-upgradeable at the very end of the document).

I think it just reserves 49 slots, when you use it, you can define it as you want, such as:

// V1
uint256[49] private __gap;

// V2
uint256 private myNewVar;
uint256[48] private __gap;

Or:

// V1
uint256[49] private __gap;

// V2
address private myNewAddressVar;
uint256[48] private __gap;

That's great to know!
I'm assuming if a reserved storage slot will then be used by a struct type, we will have to consider its internal storage when declaring the new gap size?
Something like:

// V1
uint256[49] private __gap;

// V2
struct MyData {
    // will this struct also take up storage space? it shouldn't, being defined outside the contract, correct?
    uint256[] numbers;
    address[] addresses;
    uint256 number;
}

abstract contract MyContract {
    uint256 private myNewDataStruct;
    // [assuming the struct wont take up storage]
    // define the remaining gap as 49 minus the 3 slots used by struct, is this correct?
    uint256[46] private __gap;
}

Thanks again

been digging up a bit more on the subject and found out about Diamond Storage, which looks very interesting

going to leave these two links for future reference:

The diamond storage pattern is indeed interesting and a good (better?) alternative to gaps.

The struct that you showed does not affect storage layout, not because it was defined outside the contract but because the contract doesn't have a state variable of that type.