If you are going to specify ranges by specifying end-points it's generally best to specify the range as B<=x<E.
At the very least it means you can specify the empty range by B=E.
But when it comes to 'infinite' value spaces it becomes essential.
Suppose I want to specify every string beginning with C?
In the 'end exclusive' model that's B="C" and E="D".
In the 'end inclusive' model that's B="C" and E="CZZZZZZZZZZZZZZ..." where E is some string we've decided is longer than any string we're going to practically encounter.
It also makes it practical to define non-overlapping coverages as [B,E),[E,F) and so on.
NB: Mathematical convention is that [ indicates >= and ) indicates <
Some people argue it's a matter of taste. But in practice you can create a partition from ordered values A,B,C,D,E... as [A,B),[B,C),[C,D) without any fiddling around trying to identify (the potentially non-existent or unconstructable) value immediately before B.
It's somewhere between messy and impossible to construct the partition [A,B-e1],[B,C-e2]. Just duck the issue and use half-inclusive intervals!
It normally makes sense to use inclusive-exclusive ranges but the approach works the other way.