Uniform Function Call Syntax allows you to write
x.f(*args, **kwargs)
instead of f(x, *args, **kwargs)
.
I do recognise that it’s not going to get implemented in the manner above, because it would be a breaking change (people are bound to have (ab)used the pattern try: object.method(); except AttributeError: do_stuff()
), and because it would make it too easy to write awful unreadable code (because if you see x.f()
it could be any of object_attribute, class_method or actual_function, in addition to possible definitions in an inheritance hierarchy, there’d often be too many places to look).
But there are a lot of use cases where UFCS would be really nice.
It’s not just me that thinks so. That’s why scala, nim and D have implemented UFCS, and there are 2 projects on github that implement UFCS for python. (Uniform Function Call Syntax (UFCS) for Python · GitHub and GitHub - witer33/justmagic).
UFCS enables a programming pattern which I really like that looks something like this:
def public_function(arg1, arg2, arg3):
return load_thing(arg1)
.first_transformation()
.second_transformation(arg2)
.third_transformation(arg2, arg3)
.fourth_transformation()
which looks a lot neater to me than either
def public_function(arg1, arg2, arg3):
tmp = load_thing(arg1)
tmp = tmp.first_transformation()
tmp = second_transformation(tmp, arg2)
tmp = third_transformation(tmp, arg2, arg3)
tmp = tmp.fourth_transformation()
return tmp
or
def public_function(arg1, arg2, arg3):
return third_transformation(
second_transformation(
load_thing(arg1).first_transformation(),
arg2
),
arg2, arg3)
).fourth_transformation()
additionally, it is a small annoyance to me every once in a while that I have to write len(thing)
instead of the more natural thing.len()
.
There’ve also been two request on the forum in the last month that could have been eased by UFCS:
Allowing parameters in-between function names, who would have been able to express their function as this_set.has_subset_in(set_list). And
Prefix shorthand for sending args by using `->`, who proposed using the symbols x -> f
instead of x.f()
which doesn’t feel as intuitive to me, but there’s the same desire to write functions after their primary argument (as you do with methods) rather than writing them before.
questions
- supposing we couldn’t change the behaviour of
.
, but we could elect another symbol, what symbol do you think would work well? My best idea is..
but that’s a little ugly.!
is too shouty,:
could lead to ambiguity,.:
is a little funny… - let’s call the symbol ▼ for now, which I don’t think is a valid python symbol. What would you think of
def public_function(arg1, arg2, arg3):
return load_thing(arg1)
.first_transformation()
▼second_transformation(arg2)
▼third_transformation(arg2, arg3)
.fourth_transformation()
?
- Would it be preferable if
x▼f()
evaluates tox.f()
ifx
has a methodf
, or if it always evaluates tof(x)
? The latter might be simpler to work with, but the former would allow for lovely clever trickery.
- I would use (pseudo-)UFCS if it was available in Python
- I would not use (pseudo-)UFCS if it was available in Python
- I would hate other people to be able to use (pseudo-)UFCS if it was available in Python