Since Julia is struct oriented, this could be a nice way make the language more ergonomic for methods
https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax
Assume
struct Blah
...
end
foo(b::Blah,i::Int32)
...
end
b = Blah(..)
In addition to this syntax
foo(b,123)
this would also be acceptable if a function signature existed with Blah as first parameter type
b.foo(123)
Edited: fixed function name to be idiomatic
This goes against Julia's functional philosophy and threatens to make Julia into an OO language, so I don't think you're going to get much agreement from experienced Julia developers.
Also, note that it'd be more idiomatic to just define:
function foo(b::Blah, i::Int)
...
end
foo(b, i)
No need to name it Blah_foo
, since Julia uses multiple dispatch. Now foo
can be extended to be called with instances of Bar
or Flub
or whatever as the first argument by just adding another method.
To your point, I consider this to be quite ergonomic.
I don't see how a new way to call a function threatens a whole language to become OOP. That's a slippery slope fallacy. People are writing functions associated with structs right now and that's not a threat to the language.
Nim is a procedural language that takes this idea pretty far and it is very imperative oriented: https://narimiran.github.io/nim-basics/#_calling_the_procedures
Another benefit I see to uniform function call syntax is the support of autocomplete in IDEs/REPL for Julia. One would simply suggest a list of functions with the variable's type as a first parameter.
Let's put autocomplete aside for a moment, since it's mostly orthogonal to your RFC. Let's also not discuss just ergonomics since that is mostly a matter of personal choice, and UFCS doesn't actually shorten the number of keys you have to press to achieve effectively the same behavior with idiomatic Julia code (as I demonstrated above).
What concrete benefits do you see from adding UFCS to Julia? What things are currently difficult/infeasible to do with idiomatic Julia syntax that UFCS would improve on? If you can, try to refrain from pointing to other languages as the core of your example, and instead focus on what people use Julia for today, and how UFCS can help them. Specific examples would be very helpful as well!
If you can illustrate how UFCS really is a game-changer or significant improvement over what's currently possible, without any significant downsides to implementing it, maintaining it, and seeing its usage become commonplace in the package ecosystem, then I think you'll be able to garner support and valuable discussion for your RFC.
The basic problem with allowing foo(b,123)
to be called as b.foo(123)
is that it implies that the first argument is special. This is true in OO languages because the first argument is used for dispatch, but is mostly not true in Julia because multiple dispatch treats all arguments equally.
isn't this a duplicate issue of #25052?
It solves problem of function chains natively
[-1, 2, 3].filter(x -> x > 0).map(x -> x^2)
instead of
map(x -> x^2, filter(x -> x > 0, [-1, 2, 3]))
.
And it has absolutely nothing with object oriented stuff.
And yes - it's much better to use in IDE with autocompletion.
Why is this issue closed?
Because aside from tab completion there are nothing but negatives to it? In general we don't make changes that would make stuff worse.
there are nothing but negatives to it
@timholy so you consider this
map(x -> x^2, map(x -> x^2, map(x -> x^2, [-1, 2, 3])))
as being superior to
[-1, 2, 3].map(x -> x^2).map(x -> x^2).map(x -> x^2)
Right? With multi-line it will be even more interesting.
@alexeypetrushin, you can already use
[-1,2,3] .|> x->x^2 .|> x->x^2 .|> x->x^2
(and maybe [-1,2,3] .|> _^2 .|> _^2 .|> _^2
in the future #24990) for map
-like function chaining.
We also have
((([-1,2,3].^2).^2).^2)
These have the additional advantage over chaining map
in that they both fuse into a single loop with no temporary arrays.
And you can also chain map
directly:
[-1,2,3] |> y->map(x -> x^2,y) |> y->map(x -> x^2,y) |> y->map(x -> x^2,y)
@stevengj try use pipes for functions with many arguments, don't know how things are now, but previously julia pipe had limitations.
This last line [-1,2,3] |> y->map(x -> x^2,y) |> y->map(x -> x^2,y) |> y->map(x -> x^2,y)
- you basically doing exactly what uniform function call does, but in an verbose and strange way.
Being able to write data processing pipelines from left to right is a happy accident that x.f(y)
method call syntax happens to be good for. That syntax already has a meaning in Julia so there's no way we're changing the meaning of it in any 1.x release (and pretty unlikely in 2.0, to be honest). The most constructive direction this conversation can take is thinking of alternative ways to get the benefits of the left-to-right processing flow. Insisting that one wants the [-1, 2, 3].map(x -> x^2).map(x -> x^2).map(x -> x^2)
syntax to work as is in Julia is not going be productive.
Yes, you can write [-1,2,3] |> y->map(x -> x^2,y) |> y->map(x -> x^2,y) |> y->map(x -> x^2,y)
in an ugly way, but you could also just write [-1,2,3] .|> x->x^2 .|> x->x^2 .|> x->x^2
(or [-1,2,3].^8
) — we have plenty of other ways to construct this in Julia.
I think the proposal with the most support (#24990) has been to implement nicer multi-argument function chaining in the future with something more flexible like the Scala-like syntax [-1,2,3] |> map(_^2,_) |> map(_^2,_) |> map(_^2,_)
.
Furthermore, the proposed "uniform function call syntax" wouldn't even solve this, because it would transform [-1, 2, 3].map(x -> x^2)
to map([-1, 2, 3], x -> x^2)
, which is the wrong argument order for Julia.
Julia isn't an OO language. The first argument isn't special for dispatch, so OO-like syntax here is a non-starter.
Why is this issue closed?
is answered by
That syntax already has a meaning in Julia so there's no way we're changing the meaning of it in any 1.x release (and pretty unlikely in 2.0, to be honest).
And it is a valid answer.
The first argument isn't special for dispatch
the first elements in a list is neither special so head
or first
or car
should be deleted from any language. I am fine with it.
Asides from this, I am start recognizing the community being toxic and fundamentalism.
Cool reaction, dude. Devs take the time to explain why something isn't a good fit for this language. You call them toxic for explaining it to you. There's nothing "fundamentalist" about this. If you're going to engage here, at least engage with what someone has actually written. The first
argument is totally non-sequitur: it's common to want to take the first element from a collection, so there is a first
function. It's also common to want to take the last element, so there is a last
function. What in the world does that have to do with method/function call syntax?
Most helpful comment
Yes, you can write
[-1,2,3] |> y->map(x -> x^2,y) |> y->map(x -> x^2,y) |> y->map(x -> x^2,y)
in an ugly way, but you could also just write[-1,2,3] .|> x->x^2 .|> x->x^2 .|> x->x^2
(or[-1,2,3].^8
) — we have plenty of other ways to construct this in Julia.I think the proposal with the most support (#24990) has been to implement nicer multi-argument function chaining in the future with something more flexible like the Scala-like syntax
[-1,2,3] |> map(_^2,_) |> map(_^2,_) |> map(_^2,_)
.Furthermore, the proposed "uniform function call syntax" wouldn't even solve this, because it would transform
[-1, 2, 3].map(x -> x^2)
tomap([-1, 2, 3], x -> x^2)
, which is the wrong argument order for Julia.Julia isn't an OO language. The first argument isn't special for dispatch, so OO-like syntax here is a non-starter.