Allowing arguments on many places in function name

Here’s a goofy topic for a rainy Sunday. I was pondering this morning how it would look if a function could accept arguments in more than one place, like the following

(needle)occursin(haystack)

rather than the current

occursin(needle, haystack)

This for sure would open up for some code that reads very much like natural language, but would there be significant downsides?

Some potential complications and comments:

  • One could probably not allow two consequtive sets of ()() as that would make it hard to know the sematics of fun1(a1)(a2)fun2, are these two functions or one with two args?
  • I think one would have to require that at least one sets of () end every function call, otherwise it would be difficult to understand what ()producefun() means, does it return and call a function like producefun()() in todays semantics, or is it a single function call?
  • All functions (#1)some(#2)text(#3) could also automatically define sometext(#1,#2,#3) as a fallback.
  • This is in some sense a generalization of defining ones own infix operators, as (a)isa(T) can already be expressed as a isa T

Some nice examples

  • (needle)occursin(haystack)
  • map(f)over(x)
  • in(y)store(A)*(b) / store(A)mul(b)in(y) # Maybe difficult to make work with operators.
  • findfirstin(a)suchthat(x->x>0)
  • elementsof(a)thatare(>(0)) or (a)keep(>(0)) instead of filter(>(0), a)

Breaking, since this syntax already means multiplication:

julia> (3+2)sin(4)
-3.7840124765396412

See also the long discussion in #16985 on custom infix operators. The good news is that a vast number of custom infix operators are already available in Julia — in fact, an infinite number, since you can add any number of combining characters, super/subscripts, and a few other characters to existing operators:

julia> const ∈′ = occursin
occursin (generic function with 6 methods)

julia> "er" ∈′ "better"
true

julia> "er" ∈′ "worse"
false
4 Likes

You can abuse the multiplication syntax to make it happen already:

julia> struct Infix
           f
           rval
       end

julia> Base.:*(x, i::Infix) = i.f(x, i.rval)

julia> occursin(x) = Infix(Base.occursin, x)
occursin (generic function with 1 method)

julia> needle, haystack = "th", "hey there";

julia> (needle)occursin(haystack)
true
6 Likes