The binary "is spam" thing seems like a non-issue, unless I'm misunderstanding something. In Python you can easily implement Boolean attributes using predicates without breaking the API, like so:
@property
def is_spam(self) -> bool:
return self._comment_check in {"true", "blatant"}
Then you can simply add another predicate to support the blatant case:
Akismet provides a service and a Python library for calling that service.
The service has 3 possible returns: not spam, likely spam, and definitely spam. Their library maps those 3 to 2: false, true.
So, if you use their library, there’s no way to discriminate between likely spam and definitely spam.
I wouldn’t consider rewriting the library for such a simple change, though. Yes, changing the existing function to return a three-valued result would be a breaking change, but adding a new entrypoint that does that, although technically a breaking change (that’s discoverable by reflection) would not be a breaking change.
I also don’t see why introducing asynchrony would require a rewrite. It could just be bolted on in new entry points, which, I think, the author actually did (“So I made the decision to have two client classes, one sync and one async. As a nice bonus, this meant I could do all the work of rewriting in new classes with new names. That would let me mark the old Akismet class as deprecated but not have to immediately remove it or break its API”)
message.is_blatant_spam # true if blatant spam
message.is_spam and not message.is_blatant_spam # true if possibly spam
not message.is_spam # true if not spam
But there's nothing stopping adding that middle one as another property, again without breaking compatibility:
@property
def is_possibly_spam(self) -> bool:
return self.is_spam and not self.is_blatant_spam
The point is, you don't actually have to break compatibility here, you can just define more predicates to add the extra granularity without breaking the existing ones.
> providing both sync and async code paths in the same class, often using a naming scheme which prefixes the async versions of the methods with an a
I have a solution to write a single code path for both async and sync
https://news.ycombinator.com/item?id=43982570
I don't really understand what that does.
Brings back memories if when b-list was on the front page of HN all the time.
Another approach to preserve the fully functional api is decorators.
The binary "is spam" thing seems like a non-issue, unless I'm misunderstanding something. In Python you can easily implement Boolean attributes using predicates without breaking the API, like so:
Then you can simply add another predicate to support the blatant case:Akismet provides a service and a Python library for calling that service.
The service has 3 possible returns: not spam, likely spam, and definitely spam. Their library maps those 3 to 2: false, true.
So, if you use their library, there’s no way to discriminate between likely spam and definitely spam.
I wouldn’t consider rewriting the library for such a simple change, though. Yes, changing the existing function to return a three-valued result would be a breaking change, but adding a new entrypoint that does that, although technically a breaking change (that’s discoverable by reflection) would not be a breaking change.
I also don’t see why introducing asynchrony would require a rewrite. It could just be bolted on in new entry points, which, I think, the author actually did (“So I made the decision to have two client classes, one sync and one async. As a nice bonus, this meant I could do all the work of rewriting in new classes with new names. That would let me mark the old Akismet class as deprecated but not have to immediately remove it or break its API”)
If you want to handle the three cases individually using your implementation, you would have to make another function call, rather than just the one
You don't, although it is perhaps quite awkard:
But there's nothing stopping adding that middle one as another property, again without breaking compatibility: The point is, you don't actually have to break compatibility here, you can just define more predicates to add the extra granularity without breaking the existing ones.