I’d consider that error a feature, not a bug. In my mind, the raison d’etre of linspace is to hit the endpoints exactly — that’s how it differs from the other constructions.
Multiple dispatch only works with types, not values, so you can’t use it to do something special when one of the arguments is the value 1.
Range has the same behavior. It gives nonsensical enough results for length=0, but errors, rather than defaulting to the valid singleton range 0:0 that I expect.
That still makes some sense to me: an empty range is definitely what you asked for and definitely what you got back. A 1-length range with different endpoints is impossible to satisfy. Should it give you back 0:0 or 2:2?
What is most consistent with most user’s expectations?
range(2, stop=0, length=2) works, so why not choose the convention that range includes the mandatory first argument start, so: range(2, stop=0, length=1) → 2:2 range(0, stop=2, length=1) → 0:0
The assumption that a user would want an empty range, but never a semi-empty one seems inconsistent to me.
Otherwise, one works around this with clunky code blocks.
As soon as you’re guessing what the user meant and just arbitrarily picking one possibility, you’re in dangerous API design territory. Dynamic languages have traditionally loved doing this “for convenience” but the upshot is that most of them have a bad reputation for being impossible to write reliable code in. When in doubt about what the user meant, throw an error and ask them to be more specific.
range(0,step=2,stop=3) → 0:2:2
never returns 1:2:3. It silently assumes the range stops somewhere other than stop.
This seems very conventional. Using linspace to interpolate a specified number of points is too. I’ll back away from wanting a (tricky) mixture of the linspace and range behavior.