I agree. I think of this as a functor pattern: object that supports some params being bound at constructor time, and other params set when the function is called later.
In languages that let you operator overload function call syntax, you end up with an object that, once constructed, supports being called like with same syntax as a function call. This works easily in python (define __init__ and __call__ ), and you don't have to fight the typesystem to structure code that will accept both a callable object or a function.
Another perspective of the whole thing is that you have a function with many arguments, then you curry to bind some arguments, then pass the resulting function with remaining free arguments to be called.
I prefer structuring code as functor objects as it lets you access the bound parameters as attributes (if you want to expose them) which can also sometimes be useful in code or in test
> I agree. I think of this as a functor pattern: object that supports some params being bound at constructor time, and other params set when the function is called later.
> Another perspective of the whole thing is that you have a function with many arguments, then you curry to bind some arguments, then pass the resulting function with remaining free arguments to be called.
It's not the same, though, because a socket etc is being constructed in the constructor. Here's an abridged (and possibly wrong!) version of a monitoring client:
class Monitor:
def __init__(self, monitoring_url, app_name):
self.monitoring_url = monitoring_url
self.session = aiohttp.ClientSession(timeout=aiohttp.ClientTimeout(total=1))
self.details = ujson.dumps({'app_name': app_name, 'pid': os.getpid()})
async def send(self):
async with self.session.post(monitoring_url, data=self.details, raise_for_status=True) as resp:
pass
If you treat that as currying, you will create a new ClientSession every time you call ping(). A ClientSession contains a connection pool, so that means you will create a new socket instead of reusing one.
> In languages that let you operator overload function call syntax, you end up with an object that, once constructed, supports being called like with same syntax as a function call. This works easily in python (define __init__ and __call__ ), and you don't have to fight the typesystem to structure code that will accept both a callable object or a function.
In Python and Java, you can easily refer to bound methods to produce callables from objects, so this seems like unnecessary work.
In languages that let you operator overload function call syntax, you end up with an object that, once constructed, supports being called like with same syntax as a function call. This works easily in python (define __init__ and __call__ ), and you don't have to fight the typesystem to structure code that will accept both a callable object or a function.
Another perspective of the whole thing is that you have a function with many arguments, then you curry to bind some arguments, then pass the resulting function with remaining free arguments to be called.
I prefer structuring code as functor objects as it lets you access the bound parameters as attributes (if you want to expose them) which can also sometimes be useful in code or in test