(start, end) versus (start, length) in API design

I saw two alternative conventions used when specifying a range of indices, for example

subString(int startIndex, int length); 

against.

 subString(int startIndex, int endIndex); 

They are obviously equivalent in terms of what you can do with them, the only difference is whether you specify the final index or the length of the range.

I assume that in all cases startIndex will be included and endIndex will be excluded.

Are there any good reasons to prefer each other when defining an API?

+8
language-agnostic api coding-style api-design
source share
4 answers

I would prefer length simply because it gave me another question to ask / find in the documentation.

For endIndex based on one, is it an inclusive or exclusive endpoint?

(For any option, you can ask the same question about startIndex , but it will be a perverse API that will make it exceptional).

+5
source share

How to eliminate positional arguments ...

  • use longer names subStringFromUpto (startIndex, stopIndex)

  • use a single agreement throughout the library

Didn't we find the best after all these years?

Oh yes, in Smalltalk, maybe, because the question is marked as linguistic-agnostic ...

 aString copyFrom: startIndex to: stopIndex. aString substringOfLength: length startingAt: startIndex. 

Less ambiguity, but maybe we will have to wait another 30 years before adopting this style more
(probably it looks too easy to be serious)

+3
source share

This is a good question, and I think the preference that should be used comes down to what is the most common use case. Most use cases are equally simple using the API, but consider this:

You want to get a substring starting at 5 and ending at the end of the line. Using an index-based version (assuming the second index is exclusive), it is as simple as:

 str.subString(5, str.length()); 

With API supporting length:

 str.subString(5, str.length() - 5); 

This second approach is much less concise and clear. However, this can be solved by simply stating that if the length leads to overflowing the remaining line, it will gracefully support this (e.g. str.subString(5, str.length()); will capture everything from index 5 to the end, even if he can request more characters than left). Ruby does this with the String # splice method in addition to supporting advanced things like negative indices.

In my opinion, the index-based approach is more specific, especially when negative indexes are not allowed. This makes it very obvious what to expect from the API, which may be good; which makes shooting in the leg difficult. However, a well-documented API such as Ruby makes it easy to expand the programmer's capabilities and can make an elegant substring.

I also found that in general, when I perform substring operations, I often know my starting and ending points. When using a length-based approach that would require additional computation when calling the API (e.g. substring(startIndex, endIndex - startIndex) ).

+2
source share

Someone needs to study typical call sites to figure out which approach gives the most compressed code (and therefore probably the correct code).

I like the argument that using β€œlength” you don't need to look at the documentation, but you can already look at the documentation to determine if the second integer is β€œend” or β€œlength”. If you call it endExclusive, then it will be self-tuning.

0
source share

All Articles