len(v) # Number of elements in the Vector `v`
Agreed, this should definitely be the behavior. So how do we get a vector of lengths of each element?
# Compute the length of each element of the Vector `v` v.apply(len) v @ len
Also possible is:
v.len()
We couldn't do that for every possible function, but this one is special inasmuch as we expect the items each to have a .__len__() but don't want to spell the dunders. Likewise for just a handful of other methods/functions.
The key different though is that *I* would want to a way to use both methods already attached to the objects/items. in a vector and also a generic user-provided function that operates on the items. I guess you disagree about "method pass-through" but it reads more elegantly to me:
# Replace all "a" by "b"
v.apply(lambda s: s.replace("a", "b")) v @ (lambda s: s.replace("a", "b"))
Compare these with:
v.replace("a", "b")
Since we already know v is a Vector, we kinda expect methods to be vectorized. This feels like the "least surprise" and also the least extra code. Moreover, spelling chained methods with many .appy() calls (even if spelled '@') feels very cumbersome:
(A) v.apply(lambda s: s.replace("a", "b")).apply(str.upper).apply(lambda s: s.count("B"))
(B) v @ lambda s: s.replace("a", "b") @ str.upper @ lambda s: s.count("B")
(C) v.replace("a","b").upper().count("B")
Between these, (C) feels a heck of a lot more intuitive and readable to me.
Here we put an emphasis on the methods already attached to objects. But this isn't terrible:
def double(x): return x*2 v.apply(double).replace("a","b").upper().count("B")
In @ notation it would be:
v @ double @ lambda s: s.replace("a", "b") @ str.upper @ lambda s: s.count("B")
The 'double' is slightly easier, but the method calls are much worse.
MOREOVER, the model of "everything is apply/@" falls down terribly once we have duck typing.
This is a completely silly example, but it's one that apply/@ simply cannot address because it assumes it is the SAME function/method applied to each object:
class CaseInsensitiveStr(str):
... def replace(self, old, new): ... return str.upper(self).replace(old.upper(), new.upper()) ...
l = ['Monday', CaseInsensitiveStr('Tuesday'), 'Wednesday'] v = Vector(l) v.replace('day', 'time')
<Vector of ['Montime', 'TUESTIME', 'Wednestime']>