Is there a way to replace f(object, args...) with object.f(args...)?

295 views
Skip to first unread message

cheng wang

unread,
Oct 7, 2015, 11:13:33 AM10/7/15
to julia-users
Hello everyone,

In some cases, I would like to make a function belongs to an object.
In classical OO, we do something like object.f(args...).
In Julia, we could do it like this: f(object, args...).

So I was wandering if there is some way to do following:
I write object.f(args...), while julia could know it actual means f(object, args...).

One naive way to implement this is in two steps:
first, the compiler search for a field of object equal to f, if it's not found,
then, compiler search for a function like f, and the invoke it.

Looking forward for your opinions!

Simon Danisch

unread,
Oct 7, 2015, 11:23:23 AM10/7/15
to julia-users
There are a lot of things "one could do" ;) Can you give some appealing reasons, why someone should invest his/her time into this?

Best,
Simon

cheng wang

unread,
Oct 7, 2015, 11:31:15 AM10/7/15
to julia-users
Just looks natural in some cases.

For example: Man.eat(food) looks better than eat(Man, food).

A similar situation is arithmetic expression. 2 + 3 might look more natural than (+ 2 3).

Kevin Squire

unread,
Oct 7, 2015, 11:38:40 AM10/7/15
to julia...@googlegroups.com
Hi Cheng,

Just so you know, this type of call has been discussed a number of times in the past (on my phone, so searching julia-users and julia-dev is hard right now). 

The general response has been that, while this may be more familiar to programmers coming from some languages, Julia's focus on multiple dispatch is a key component of the language, and there isn't much desire to complicate the implementation or use of the language with multiple calling conventions. 

That said, you could almost certainly fake this calling convention with a macro.

Cheers,
   Kevin

Milan Bouchet-Valat

unread,
Oct 7, 2015, 11:43:57 AM10/7/15
to julia...@googlegroups.com
Le mercredi 07 octobre 2015 à 08:31 -0700, cheng wang a écrit :
> Just looks natural in some cases.
>
> For example: Man.eat(food) looks better than eat(Man, food).
>
> A similar situation is arithmetic expression. 2 + 3 might look more
> natural than (+ 2 3).
Looks like you'd rather want to write
Man `eat` food
or something similar instead of Man.eat(food).

For previous discussions about this, search for "infix operator" in the
list archives and on GitHub.


Regards

Eric Forgy

unread,
Oct 7, 2015, 11:44:30 AM10/7/15
to julia-users
I'm still a Julia newbie, but have been lurking around long enough to know that a common answer for questions like this is... 

You can have the behavior you want via a fairly straightforward macro.

In this case, the macro would simply take object.f(args) and replace it with f(object,args), which is pretty much what Matlab does. This may be a bad idea for reasons I'm not yet aware of (but would like to learn), but hope it helps a little.

David Gold

unread,
Oct 7, 2015, 11:46:56 AM10/7/15
to julia-users

cheng wang

unread,
Oct 7, 2015, 12:17:55 PM10/7/15
to julia-users
Newbie here too :)

For me, the problem is having to write @mymacro everytime I use this style.

cheng wang

unread,
Oct 7, 2015, 12:25:12 PM10/7/15
to julia-users
Thanks everyone!

A very related issue that the authors of Julia discussed.

In scala, object.f(args) is implemented as f(object, args).
For Julia, maybe this implementation would harm the performance.
Anyway, It's fine to use f(object, args) :)

Glen O

unread,
Oct 7, 2015, 12:35:00 PM10/7/15
to julia-users
Perhaps you could include the function amongst the elements of the type?

immutable MyArray
    array::Array
    fill::Function

    MyArray(array)=new(array,i->fill!(array,i))
end

B=MyArray(zeros(5,2));

B.array
5x2 Array{Float64,2}:
 0.0  0.0
 0.0  0.0
 0.0  0.0
 0.0  0.0
 0.0  0.0

B.fill(1);

B.array
5x2 Array{Float64,2}:
 1.0  1.0
 1.0  1.0
 1.0  1.0
 1.0  1.0
 1.0  1.0

Does that help? Note that I have no idea how well it would perform in terms of optimisation.

Steven G. Johnson

unread,
Oct 7, 2015, 12:47:40 PM10/7/15
to julia-users
It's a bad idea.   You shouldn't try to write C programs that look like Fortran programs, you shouldn't speak French with English pronunciation, and you shouldn't try to write Julia programs that look like Python programs.   Part of programming is learning to adapt to the local style, both the style of a programming language and also the style of a project that you are contributing to.

The only difference between object.verb(args...) and verb(object, args...) is spelling.  Since there is no practical need for the former, you should just get used to the Julia spelling when writing Julia code.

Steven

PS. In olden times, many people learned programming in Pascal. When they switched to C, their first instinct was often to define macros that made C look more like Pascal, and this was universally considered to be a mistake by experienced programmers. See: http://c-faq.com/cpp/slm.html

Eric Forgy

unread,
Oct 7, 2015, 1:23:51 PM10/7/15
to julia-users
Well said! :D

cheng wang

unread,
Oct 7, 2015, 1:26:00 PM10/7/15
to julia-users


On Wednesday, October 7, 2015 at 6:47:40 PM UTC+2, Steven G. Johnson wrote:
It's a bad idea.   You shouldn't try to write C programs that look like Fortran programs, you shouldn't speak French with English pronunciation, and you shouldn't try to write Julia programs that look like Python programs.   Part of programming is learning to adapt to the local style, both the style of a programming language and also the style of a project that you are contributing to.
I don't see why it is bad to support more styles if there is no harm to the original one.
So actually I was also asking if this new style will bring evil things to local style.
 

The only difference between object.verb(args...) and verb(object, args...) is spelling.  Since there is no practical need for the former, you should just get used to the Julia spelling when writing Julia code.
 
Since dot already means access fields of an object. It slightly affects, maybe?
 

Steven

PS. In olden times, many people learned programming in Pascal. When they switched to C, their first instinct was often to define macros that made C look more like Pascal, and this was universally considered to be a mistake by experienced programmers. See: http://c-faq.com/cpp/slm.html
Thanks for sharing this story, it is interesting.
However I always like to reason about thing in details, not just you should don't do this.

 
 

Scott Jones

unread,
Oct 7, 2015, 1:59:22 PM10/7/15
to julia-users
I think the important take away is that Julia's *multiple* dispatch can be much more powerful than traditional "object oriented" single dispatch.
Once you get your head wrapped around that, I don't think you really would want to go back to the Python/Java/JS/C++ single dispatch way of doing things.

Maxim Grechkin

unread,
Oct 7, 2015, 2:10:32 PM10/7/15
to julia-users
The only difference between object.verb(args...) and verb(object, args...) is spelling.  Since there is no practical need for the former, you should just get used to the Julia spelling when writing Julia code.
What about auto-complete? object.verb provides better opportunities to auto-complete on dot compared to verb(object, args). If you have an object and you want to figure out what you can do with it, all you can do in Julia is try using `methodswith`, but that's not that straightforward or easy to use.

I've seen some proposals to do an auto-complete on "object, " (auto-complete putting verbs before object), but I don't have a sense of how awkward will that look in an editor.

Pablo Zubieta

unread,
Oct 7, 2015, 2:10:45 PM10/7/15
to julia-users
As others mentioned, it is better to use multiple dispatch as the Julia language was developed with it as one of its central features.

You could easily change the name of the function to make it look natural (in the english grammar sense). E.g. you can define feed(Man, food) or feed(Man, with=food) if that seems more natural to you.

cheng wang

unread,
Oct 7, 2015, 2:16:46 PM10/7/15
to julia-users


On Wednesday, October 7, 2015 at 8:10:45 PM UTC+2, Pablo Zubieta wrote:
As others mentioned, it is better to use multiple dispatch as the Julia language was developed with it as one of its central features.
Totally agree with this. using verb(object, args) to implement object.verb(args) actually still relies on multiple dispatch.
 

You could easily change the name of the function to make it look natural (in the english grammar sense). E.g. you can define feed(Man, food) or feed(Man, with=food) if that seems more natural to you.
This is a GREAT trick. Thanks!!!! 

cheng wang

unread,
Oct 7, 2015, 2:21:28 PM10/7/15
to julia-users
I absolutely like multiple dispatch. Just want to make syntax sugars based on this.

Steven G. Johnson

unread,
Oct 7, 2015, 3:39:22 PM10/7/15
to julia-users
On Wednesday, October 7, 2015 at 1:26:00 PM UTC-4, cheng wang wrote:
I don't see why it is bad to support more styles if there is no harm to the original one.

Because code that mixes multiple styles is harder to read (imagine reading a document that jumps back and forth between different spellings), harder to share (because other Julia programmers won't know your idiosyncratic style), and harder to combine with other features of the language (as others have said, multiple dispatch is central to Julia's design and central to the design of the standard library).

This comes up with every new programming language, which is why it is useful to learn from history.

Stefan Karpinski

unread,
Oct 7, 2015, 5:03:13 PM10/7/15
to julia...@googlegroups.com
In this case, it also obfuscates the meaning of the code. Does x.f(y) mean f(x,y) or is it actually x.f(y)? With this proposal you would need to know something about x in order to decide, currently there's no confusion.
Message has been deleted

cheng wang

unread,
Oct 7, 2015, 5:44:02 PM10/7/15
to julia-users
Hello Stefan,

After thinking your reply and doing more search, I found Julia support x.f(y) natively by encapsulating f into the constructor of object x.
So thanks a lot!

Now I have another question:
Since x.f is different for different x, f need to be compiled as many times as the number of x ??
Here I suppose f uses x.

jonatha...@alumni.epfl.ch

unread,
Oct 7, 2015, 5:55:26 PM10/7/15
to julia-users
I think the auto-completion is a bit of an issue, it makes Julia functions not easily discoverable. In other language when you have a string you can just type dot and tab and see all the methods that you can apply to your string, so you almost never need to go to the doc.

Something similar should be possible to implement in Julia with methodswith but I'm not sure any IDE support that yet. methodswith might also be too slow for that purpose.

Stefan Karpinski

unread,
Oct 7, 2015, 6:03:45 PM10/7/15
to julia...@googlegroups.com
This is a real issue but I don't think that aping the syntax of a very different paradigm is the right solution.

cheng wang

unread,
Oct 7, 2015, 7:49:36 PM10/7/15
to julia-users
In Julia, when people use x.f(y), what he actual means is f(x, y) (assuming f relies on x). So there is no need to define f inside a type, just define f(x,y) outside.
So, my first conclusion is: it is not a good practice to put function inside a type.

If there is a rule that people can not define function field in a type, then set x.f(y) = f(x,y) does not have the confusion you mentioned early.
Also x.f might be good for multi-dispatch. I am not sure how multi-dispatch is implemented, but the prefix x seems provide a good heuristic.

Best,
Cheng

Jonathan Malmaud

unread,
Oct 7, 2015, 10:06:27 PM10/7/15
to julia-users
You could also use pipelining: man |> _->eat(_, food). There's been talk of having "pronoun" syntactic sugar to let you write that as
man |> eat(_, food) or perhaps taking it even further and assuming the first argument is the pronoun recipient, yielding
man |> eat(food)

I personally favor a solution along these lines since it doesn't hide multiple dispatch but still gives you the svo order which many find more natural in certain domains.

Jonathan Malmaud

unread,
Oct 7, 2015, 10:24:36 PM10/7/15
to julia-users
A great package actually already implements this concept: https://github.com/one-more-minute/Lazy.jl#macros:

julia> eat(x,y) = println("$x ate $y")
julia> @> 7 eat(9)
"7 ate 9'

Jeffrey Sarnoff

unread,
Oct 7, 2015, 11:09:27 PM10/7/15
to julia-users
It may be that this cannot be fully resolved until the REPL's internal sketch of function dependencies allows rapid reweaving when an intermediate function is modified.
With that, pulling function-family specs and offering thematic looks could be very efficient.

le...@neilson-levin.org

unread,
Oct 8, 2015, 12:01:28 AM10/8/15
to julia-users
Seems a bad idea even as syntactic sugar, except for the case of using PyCall (when the target language is loosely object oriented).

If you prefer object oriented dispatch, many languages offer it.  With strong typing, optionally as Julia provides, OO dispatch can off make class inheritance very difficult.  I realize the OP has no issue with multiple dispatch and wants to preserve it and the syntactic sugar would rarely, if ever interfere with it.  Since multiple dispatch is expressed with function call syntax, Julia should stick to that.  While I wouldn't want Julia to go too wild down the functional programming path, the key benefits of FP that Julia provides--namely, multiple dispatch, 1st class functions, and closures--are really great and handily fit a language with a more imperative style.

In Python (I still love Python), x.f(y) is really just syntactic sugar for f(x,y).  It almost seems silly to have it at all.  And since Julia is even less OO than Python, which is to say not at all then it seems almost misleading to mimic the OO syntax since OO is definitely NOT what is happening under the hood.

While I realize the OP is not really asking for it, it is still worth pointing out that there seems little benefit to going down the OO path.


Burning Legion

unread,
Oct 8, 2015, 3:25:20 AM10/8/15
to julia-users
I grew to love multiple dispatch after awhile. It is quite different and honestly it does take awhile to fully make use of it. It made my life much easier once I had a grasp on it personally.
What you want could be done as well by defining Man.eat(y) = feed(Man,y) in your constructor.

cheng wang

unread,
Oct 8, 2015, 4:33:38 AM10/8/15
to julia-users
Thank everyone!
I am convinced by the trick feed(man, food).
Just like: append!(collection, element) vs collection.add(element).
append! gives me the feeling that I am controlling the program :)

Best,
Cheng

Glen O

unread,
Oct 8, 2015, 4:38:37 AM10/8/15
to julia-users
This would all be so much easier if we had custom infix operations beyond the unicode ones.

Just a thought, but what if |> were tweaked to have a ternary form |> (), so that a|>f(b) automatically gets interpreted as f(a,b)? If you had a function that outputs a function (say, f(j)=i->i^2+j^2), then to use the output function, you would use brackets to fix it... a|>(f(b)) would evaluate as a|>(i->i^2+b^2), in this case.

Then you'd have man|>eat(food), and you'd have 10|>mod(7), and A|>fill!(1), and other such instructions.
Reply all
Reply to author
Forward
0 new messages