Posts
Concept of more useful types
You've probably written something takes filename as an argument
def process_filename(filename: str) -> None: ...
And it was fine until you have not had a filename, but already retrieved bytes
value: bytes
process_filename(value) # incompatible
You could write bytes to disk and get a filename and make it work, albeit worsening performance among other things
Bytes → Filename → Process Filename
value: bytes
filename = write_to_disk(value)
process_filename(filename)
But data is more often received as bytes, not filename. So identifying a more useful type would have saved you jumping through hoops
in this case bytes is more useful than filename
Bytes → Process Bytes
# def process_filename(filename: str) -> None: ...
def process_bytes(bytes: bytes) -> None: ...
value: bytes
process_bytes(value)
process_bytes would still be useful if you had filename, or retrived data from other sources
Filename → Bytes → Process Bytes
Any other source → Bytes → Process Bytes
filename: str
with open(filename, "rb") as f:
bytes_from_disk = f.read()
process_bytes(bytes_from_disk)
process_bytes(bytes_from_network)
process_bytes(bytes_from_channel)
Conclusion
Identifying more useful types would save you from later refactoring, positively impact performance by cutting indirection and aid in writing reusable code. More useful type is more general. There are more transformations into such a type. In these examples, bytes is a better, more useful type than filename, network/channel pointer because there's a direct way to transform each of these data sources to bytes.