How duck typing shifts checks to the moment of use
In a duck-typed language, a function can receive an object without first checking whether it belongs to a particular declared class. Instead, the function tries the operation it needs—for example, calling a `read()` method. If the object supports that operation and behaves as expected, the work continues.
That makes it easy to use different kinds of objects through the same code. A file, a network response, or a custom object might all work with a function that only needs to read data. The function does not need a separate version for each one, or a shared class hierarchy built in advance.
Flexibility comes with a runtime tradeoff
Because the check often happens only when the operation is attempted, a missing method or incompatible result may remain unnoticed until that particular path runs. For instance, an object might have a `read()` method but return data in a form the caller cannot handle. The failure can appear during execution rather than when the program is first analyzed.
This approach favors adaptable code, especially when the needed behavior is small and clear. Its cost is that expectations may be less visible: a function’s requirements can live in its implementation, tests, or documentation rather than in a formal type declaration. The practical contract is the set of operations the code actually relies on.






