Julia: Curried versions of endswith and startswith

Created on 8 Sep 2019  ·  7Comments  ·  Source: JuliaLang/julia

In the spirit of https://github.com/JuliaLang/julia/pull/30915 I was wondering whether a PR for adding single-argument versions of endswith, startswith, and occursin that can be used as follows in functions like filter would be appreciated.

filter(endswith(".jl"), readdir())

I feel that I have definitely typed x->endswith(x, ".jl") far too often :)

good first issue help wanted

Most helpful comment

Having a long list of functions where the first argument is considered special seems bad to me. Instead, just like with vectorized function we should IMO focus on syntax that tries to handle all of this in one fell swoop (https://github.com/JuliaLang/julia/pull/24990). Anything else will just be a neverending debate of what functions should implement this special handling and since Base code is not special, this will also seep out to the package ecosystem. We should learn from the f(::Missing) = missing story that is currently experiencing that thing and not try have another of those situations.

All 7 comments

Having a long list of functions where the first argument is considered special seems bad to me. Instead, just like with vectorized function we should IMO focus on syntax that tries to handle all of this in one fell swoop (https://github.com/JuliaLang/julia/pull/24990). Anything else will just be a neverending debate of what functions should implement this special handling and since Base code is not special, this will also seep out to the package ecosystem. We should learn from the f(::Missing) = missing story that is currently experiencing that thing and not try have another of those situations.

The criteria we agreed to when starting with that currying was:

  1. Two-argument function where the subject is the first argument: verb(subject, object).
  2. Currying on the second argument, so verb(object) = subject -> verb(subject, object).
  3. Linguistically, verb(object) reads naturally as a predicate.

These criteria are clearly met by endswith and startswith:

  • endswith(".jl") is a predicate for strings that end with .jl
  • startswith("/") is a predicate for strings for start with /.

For occursin it's more borderline since by these rules, occursin(object) is a predicate that applies to patterns (subject) to test whether they occur within a fixed collection or string (object). That's probably not what you had in mind. If we had the ismatch(string, pattern) predicate of yore, then ismatch(pattern) would do what you want.

24990 is very high-level and new feature oriented. Not quite done yet.

One could simply generate a lot of those binding (currently defined in https://github.com/JuliaLang/julia/blob/v1.2.0/base/operators.jl with a for loop doing @eval over a preset array of function names. Rather simple.

There will be however some corner cases with builtins functions such as

@test_throws ErrorException Base.:(===)(t) = Base.Fix2(:(===),t)
@test_throws ErrorException Base.isa(t) = Base.Fix2(isa,t)
@test_throws ErrorException Base.:(<:)(t) = Base.Fix2(:(<:),t)

If we did https://github.com/JuliaLang/julia/issues/35031
And add contains as a Arg order flipped version of occursin
Then contains would have same pattern as needed.

I retract my comment at https://github.com/JuliaLang/julia/issues/33193#issuecomment-529205329, these specific set of functions do seem to fit the pattern where this would make sense.

This seems decided: startswith & endswith are ok, occursin is not ok. Just needs a PR.

Just needs a PR.

Will create one.

Was this page helpful?
0 / 5 - 0 ratings