I still think this is approaching the problem from the wrong direction – IIUC, the problem is not that strings are Iterable, but that they are specifically
Iterable[str]. And most of the time a function is expecting a
Iterable[str] it will work with a
str, but not with the result that’s expected – technically it’s a value error, not a type error, but practically, it’s a type error (and I think the most insidious common one in Python since integer division was removed).
So what would solve the problem is a way to define any iterable[str] except not
str itself – i.e,
Iterable[str] - str
Yes, that would be a bit klunky, considering that’s it’s probably the most common use case [*] – but if there was a way to define it, then it could be given an alias, and no more klunk.
What I wonder is what other applications there are for “subtracting” types – if this is the only one, then probably better to put a kludge [uh – special case] in the type checkers.
[*] maybe not unheard of to take both an Iterable[str] and an [str] – this has been an ongoing issue long before static typing – and there’s plenty of code out there (at least in my codebases ) like:
if isinstance(bunch_o_strings, str):
bunch_o_strings = [bunch_o_strings]
for string in bunch_o_strings:
And that can be correctly typed as
Iterable[str] right now.
And that doesn’t just “fix” the type error, it provides a “nicer” API – maybe the same people that want strict typing wouldn’t like such a squishy API, but my scripting users do
I think the answer here may be that it’s impossible to describe a type that doesn’t exist, but pretend that an existing type is that type. It wouldn’t be the least bit hard if there actually WAS an AtomicString
But anyway: these issues with
str being an iterable of
str have existed for years, long before static typing – so maybe it’s too much to expect the type system to solve it without making any changes – if folks really need an AtomicString, then maybe make one?
But i don’t think the problem actual is that
str is iterable – that’s actually handy sometimes. The problem is that
str when you iterate – and that goes on forever.
When you have nested lists, you can iterate and get a list, and iterate and get a list, but eventually, you get to some non-list type.
When you iterate a numpy array you get a lower rank numpy array, but eventually you get a scalar.
When you iterate a
str what you always get is a length-one
str – forever. So maybe rather than an AtomicString, we need a Char.
Maybe the type system could consider a string an
Iterator[Char] – so it would not satisfy Iterator[‘str’] anymore. And I think that could be done without there actually being a
Hmm – then you would need to cast when you DO iterate through a string and want them to be considered strings. OR could you define a type in the type system that doesn’t actually exist?
Maybe back to
Iterable[str] - str – if there could be a way to spell that.