# How to discover functions which apply to a given object?

**URL:** <https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [February 22, 2019, 5:15pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087 "2019-02-22T17:15:22Z")\
**Posts on this page:** 17\
**Page:** 2

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 23, 2019, 8:47am UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/21 "2019-02-23T08:47:43Z")

</div>

> [@mboratko](#):
>
> pruning is needed, but the general idea is there

The solution by @WschW is very clever and displays the nice introspection facilites of Julia, but as clarified later, it breaks inference.

As @DNF suggested, this is primarily a problem for _tooling_. Also, to use Julia productively, it is best to realize that it isn’t Python, and should not be remade in the image of the latter. When learning a new language, I think it is best to learn it as is for about a year or two (or, alternatively, 100k LOC), and save language redesign for later.

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 1:38pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/22 "2019-02-23T13:38:15Z")

</div>

> [@DNF](#):
>
> I don’t see why method discovery has to be tied to object.method syntax.

It doesn’t, but I was arguing that `object.method` syntax is useful for other reasons. Here are my reasons in support of such a syntax:

**1. There are many instances when it is easier to read / write in the reverse order.**  
Consider

```julia
eigenvalues(laplacian(transitive_reduction(fill_from(A, edge_list))))

```

vs.

```julia
A.fill_from(edge_list).transitive_reduction().laplacian().eigenvalues()

```

The very existence of piping serves as a testament that there are instances where it is easier to put it in the reverse order, but while

```julia
fill_from(A,edge_list) |> transitive_reduction |> laplacian |> eigenvalues

```

works when the functions only take a single argument, it requires ugly and noisy syntax for anything else, for example

```julia
fill_from(A,edge_list) |> x -> connected_components(x, 3)

```

**2. Helps with conceptual flow.**  
Perhaps this is something which can be developed in time, however if you have object `x` and you want to pass it through a set of transformations which will eventually return some object `y`, it seems intrinsically easier to start from something that exists rather than envisioning what object `y` might be, what the last transformation you would apply would be, then the next-to-last, and so forth.

**3. Provides a natural way to narrow scope and discover functionality via tab completion.**  
Would it be possible to come up with something such as `A<ctrl+.>` (as you suggested) to expand a list of methods which take `A` as a parameter? Sure. Would it be natural to use it this way? Not really, because you’re writing something (the object name) which isn’t actually in the position it would end up. The code would have to be flipped around and turned into `function(A)`.

Part of the reason tab completion is so nice it that it is a _completion_. You are still writing the code the way you will eventually see it appear, if you get part way through but then realize you forgot the spelling of the method you want to call then you can tap tab and it will just fill out the rest, you can use partial names to reduce the number of suggested functions, etc. etc. If I was trying to get the connected components of a graph and I forgot if the function was `connected_components` or `conn_comp`, with code completion I would write `A.conn`, realize I didn’t remember the spelling, and then just hit `<tab>` and it would just fill out the rest. With your proposed method I guess I would have to type `A<ctrl+.>` and then maybe an interface would appear where I could start narrowing down the choices? But the point is that this is a totally different order of typing, and I would have to had consciously made a decision to use the function suggestion tooling rather from the start.

* * *

I would like to flip the question around - **what _disadvantage_ does UFCS have?** You don’t _have_ to use it. It is simply syntactic sugar, it doesn’t make Julia more or less object oriented. If Julia had UFCS, would you be asking for it to be removed?

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 1:47pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/23 "2019-02-23T13:47:18Z")

</div>

> [@Tamas\_Papp](#):
>
> When learning a new language, I think it is best to learn it as is for about a year or two

In most respects, I agree. However, with aspects related to ease of learning, it’s easy to _forget_ the aspects which were challenging at the start once you are proficient. Furthermore, once you are proficient, you don’t care as much about those aspects which would make it easier for others. In that sense, I think focus on these types of issues when learning a language is valuable.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 23, 2019, 1:51pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/24 "2019-02-23T13:51:31Z")

</div>

> [@mboratko](#):
>
> Furthermore, once you are proficient, you don’t care as much about those aspects which would make it easier for others.

Perhaps you misunderstood something — `methodswith` and similar introspection facilities are useful for _all_ programmers to Julia, regardless of how experienced they are.

You are arguing for an introduction of a _parallel_ facility. Why not use what you already have available? Also, note that _interfacing_ with this functionality is a separate issue, and you should not have to hijack the property API for it.

**EDIT** : also, if you have a proposal for extending/changing the language, please open a new topic; the _First steps_ category is not the best place for it.

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 2:13pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/25 "2019-02-23T14:13:43Z")

</div>

For my purposes, `methodswith` is not all that useful. For example, for a graph `A` then `methodswith(typeof(A))` returned 0 methods, and `methodswith(typeof(A), supertypes=true)` returned 242 methods. `InteractiveCodeSearch` already provides a more usable way to interface with it, the only disadvantage is that it needs to be kicked off by typing some code such as `@searchmethods typeof(A)` which, again, is a separate action from just _writing the code_. Sure, this might be made slightly easier by adapting the tooling to kick this off by typing `A<ctrl+.>`, but the point is that you still need to have decided _beforehand_ that “I’m going to search for a function now” rather than just writing code, which is what completion allows.

My point is that Julia’s _syntax_ is inherently prohibitive of this sort of _completion_. No matter what fancy interfacing or tooling that is laid on top of it, you will never be able to simply write some partial function name and then complete it with type awareness because the functions always have to come first.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 23, 2019, 2:31pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/26 "2019-02-23T14:31:18Z")

</div>

> [@mboratko](#):
>
> My point is that Julia’s _syntax_ is inherently prohibitive of this sort of _completion_ .

I am not sure about this, at the REPL one could look up completions for

```julia
f(arg1, arg2, ...)

```

with TAB if the cursor is on the `f`, and restrict to the applicable names. It just just has not been implemented (yet, AFAIK, I am not aware of an issue either). It would make a nice PR if you are interested.

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 2:34pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/27 "2019-02-23T14:34:39Z")

</div>

Sure, but I wouldn’t call that completion. (It’s similar to the [tuple completion](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/8) mentioned by @jonathanBieler above.) The point is you are not writing it in the same order as you would have written the resulting code, and that can never be the case with Julia because the function always comes first.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 23, 2019, 2:41pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/28 "2019-02-23T14:41:16Z")

</div>

> [@mboratko](#):
>
> you are not writing it in the same order as you would have written the resulting code

Sorry but I don’t understand. How else would you write functions than `f(arg1, arg2, ...)`? Except for infix operators, of course.

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 2:50pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/29 "2019-02-23T14:50:43Z")

</div>

With UFCS, the following are equivalent:

```julia
arg1.f(arg2,...)
f(arg1, arg2, ...)

```

The first object of a function is often the “main” argument, and that often is enough to narrow the scope of potential functions to a short list.

Again, you don’t _have_ to write things this way at all. I haven’t really heard an argument for _not_ allowing this.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [February 23, 2019, 3:02pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/30 "2019-02-23T15:02:35Z")

</div>

> [@mboratko](#):
>
> I haven’t really heard an argument for _not_ allowing this.

That’s not how computer languages should be designed — rather than including features because there are no arguments _against_ them, it is better to extend the language when there is an argument _for_ something.

That said, there are at least 3 a compelling arguments against the syntax you are proposing:

1. the first argument is nothing special in Julia — in fact, it is even _less_ special than in other languages with multiple dispatch, eg Common Lisp which would use order to resolve ambiguity.
2. it would conflate the syntax for `getproperty` with function call syntax
3. it is unclear how modules paths fit into this scheme — how would you translate eg `Statistics.quantile(xs, ps)`?

Personally, I doubt that UFCS fits naturally in Julia, but if you seriously want to argue for it, please do make a clear proposal in a separate topic. Again, _First steps_ is hardly the place for this.

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 3:42pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/31 "2019-02-23T15:42:50Z")

</div>

> [@Tamas\_Papp](#):
>
> if you seriously want to argue for it, please do make a clear proposal in a separate topic.

OK, if I want to push further for it I will consider making a proposal for it elsewhere. To address the arguments though:

> [@Tamas\_Papp](#):
>
> 1. the first argument is nothing special in Julia — in fact, it is even _less_ special than in other languages with multiple dispatch, eg Common Lisp which would use order to resolve ambiguity.

While the language may not place special emphasis on the first argument, humans still do. Again, I’m not suggesting that this is a _complete_ solution that is elegant and perfect in every use case, but it is amazingly useful in the other languages which have it.

> [@Tamas\_Papp](#):
>
> 1. it would conflate the syntax for `getproperty` with function call syntax

There’s no ambiguity though - it tries `getproperty` and if it can’t find anything it tries a function. It’s not the only way to call a function, so if you happend to have a name conflict you just write the function the other way. Other languages (D, Nim) handle this exactly the same way.

> [@Tamas\_Papp](#):
>
> 1. it is unclear how modules paths fit into this scheme — how would you translate eg `Statistics.quantile(xs, ps)` ?

If you really wanted to, `xs.Statistics.quantile(ps)`, however it seems that Julia encourages pulling everything into the global namespace anyway so this wouldn’t happen that much.

Again, it’s meant as an option to use when it makes “grammatical” sense. It’s not meant to be the _only_ way to apply a function, and it’s not meant to provide _perfect_ discoverability, but it’s a fair bit better than what is possible now. It’s obvious these “grammatical” order differences are important, otherwise the pipe operator wouldn’t exist.

I’m not wed to the dot operator, it just feels natural because that’s what I’m used to. The pipe operator is promising, but currently limited to single-argument functions only which greatly neuters it’s usefulness. I would be perfectly happy if something like [curry underscoring](https://github.com/JuliaLang/julia/pull/24990) is implemented, as it would also allow true _completion_ (i.e. typing your code in the same order whether you use completion or not). It is even more general than UFCS, at the expense of 5 extra characters of syntax. For example,

```julia
# Original method call:
connected_components(fill_from(A, edge_list), k)

# UFCS:
A.fill_from(edge_list).connected_components(k)

# Curry Underscoring Pipe:
A |> fill_from(_, edge_list) |> connected_components(_, k)

# Possible with Curry Underscoring, but not with UFCS:
some_array |> map(x->x^2, _)

# Splats are hopefully possible with Curry Underscoring?
C = (A_set, B_set)
C |> union(_...)

# Not sure about changing the order, for example
C |> func(_[2], _[1])
# but it doesn't have to be infinitely flexible,
# even UFCS provides a really decent level of flexibility.

```

Despite the noisier / cumbersome syntax I think I’m coming around on some sort of curry underscoring approach. It would work pretty well with completion, typing `A |> <tab>` could list all the methods which could take `A` in their input, auto-completing could even place the underscore where it should go based on type (if it was unambiguous). Limiting this auto-complete would be a challenge still, but it’s potentially progress.

---

<div class="post-metadata">

**Author:** ![waldyrious](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/waldyrious/32/80_2.png) [@waldyrious](https://discourse.julialang.org/u/waldyrious)\
**Post date:** [February 23, 2019, 4:35pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/32 "2019-02-23T16:35:19Z")

</div>

@mboratko in case you haven’t yet, I highly recommend you to read the topic [My mental load using Julia is much higher than in Python](https://discourse.julialang.org/t/my-mental-load-using-julia-is-much-higher-than-e-g-in-python-how-to-reduce-it/18902). It raises several points that are similar to yours, and has some quite insightful comments.

(I particularly liked [this comment](https://discourse.julialang.org/t/my-mental-load-using-julia-is-much-higher-than-e-g-in-python-how-to-reduce-it/18902/5) by @rdeits on that thread.)

---

<div class="post-metadata">

**Author:** ![mboratko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mboratko/32/5377_2.png) [@mboratko](https://discourse.julialang.org/u/mboratko)\
**Post date:** [February 23, 2019, 5:58pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/33 "2019-02-23T17:58:59Z")

</div>

Yes, that thread didn’t pop up in the related items at first but once this thread started rolling I noticed it linked (win for machine learning). I definitely share your sentiment regarding the mental load, as well as feeling overwhelmed by the seemingly open-ended task of selecting a function from all possible functions instead of getting the “narrowing context” effect I feel in Python.

[This github issue](https://discourse.julialang.org/t/my-mental-load-using-julia-is-much-higher-than-e-g-in-python-how-to-reduce-it/18902/27) and the related ones to it were also relevant.

Something that became clear to me during the discussion in this thread is the way that language syntax interacts with completion. In this way, I claim it is not just a question of tooling. It is also not, as suggested by one of the other responses to your thread, a OO vs functional paradigm shift as demonstrated by the highly functional proposals above.

For me, autocomplete is much more than just a convenience, and having good autocomplete is absolutely essential for any language designed for scripting and rapid prototyping. I appreciate the discussion about it here, it has helped me formalize the abstract properties necessary to be able to create a fluid autocomplete interface.

---

<div class="post-metadata">

**Author:** ![rapus95](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rapus95/32/3773_2.png) [@rapus95](https://discourse.julialang.org/u/rapus95)\
**Post date:** [January 9, 2020, 10:20am UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/34 "2020-01-09T10:20:05Z")

</div>

Even feeling a bit ashamed for reviving that topic, I want to refine the previously mentioned solution for tooling that might even be able to streamline both requirements (universal language & maximum discoverability).  
If we formally do tab replacement instead of completion we get a lot of possibilities. The following dot notation of course is motivated by OO history and could be replaced by anything the usecase/tooling/user combination might want. Even a preference setting in tooling could be made of it.

```julia
A = Graph()
A.<some complete key>
#Showing propertynames(A) marked as properties and showing functions that return on methodswith(typeof(A)) marked as such
#selecting a function resolves to
fun(A,<cursor>[, other args])

```

That would increase discoverability while (in the dot case) keeping the property api clean. It even helps newcomers remembering the function names and patterns used in Julia as it transforms the style used for discoverability into the style used in Julia.

Following that road down, tab suggestions can even be further refined and tuned (e.g., for supporting functional style methods, aka, comparing the type to the first non-function argument for proper suggestion of filter & map etc). Even further down the road this can take traits into account.

In my opinion discoverability would be best to stay orthogonal to code design since the former mainly depends on your own history and previous type of programming while the latter IMO is a “feature” of Julia. This maintains maximum flexibility which again allows tooling to streamline both traits without sacrificing universality. That allows different tooling designed for different use cases based upon the same universal language, Julia. =\> Make a DSL by tooling/restricting suggestions rather than by language design restrictions.

As a more concrete example I like to compare that to the eclipse completion where you can cycle through different suggestion modes. In our case the first iteration could look like “only propertynames or only function suggestions(-\>methodswith)”. In the next iteration we could add some mixed approach. And in a further advanced iteration we might even add some sort of AI to predicting the most favourable completion. Each of those stay entirely independent because the language allows a fairly universal representation with some (focused but basic/generic and type stable) syntactic sugar.

In the end everyone who wants to can simply hook their own completion script into the suggestion by simply providing a function that completes the input in front of any configured trigger event. When we stay at the same universal language we can support maximum diversity at the same time as maximum compatibility within the code.

I know, you already brought these points and for me it sounds like some sort of utopia but making utopia real is the designated purpose of Julia (Just remember the original blogpost “[Why we created Julia](https://julialang.org/blog/2012/02/why-we-created-julia)”).  
And btw, I’m pretty sure underscore currying will come. There is enough value and reoccuring interest in it that it will make it into the language. Hopefully even before 2.0. But even if not, 2.0 will be a very astonishing release anyway (Still hoping for [Invariant Tuples](https://github.com/JuliaLang/julia/issues/24614))

---

<div class="post-metadata">

**Author:** ![juliohm](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/juliohm/32/215266_2.png) [@juliohm](https://discourse.julialang.org/u/juliohm)\
**Post date:** [January 9, 2020, 11:02am UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/35 "2020-01-09T11:02:16Z")

</div>

> [@mboratko](#):
>
> My point is that Julia’s _syntax_ is inherently prohibitive of this sort of _completion_ . No matter what fancy interfacing or tooling that is laid on top of it, you will never be able to simply write some partial function name and then complete it with type awareness because the functions always have to come first.

Welcome to the Julia community @mboratko! It is great to see people coming with extensive experience from other programming languages and tools. Notice that in the statement above you are assuming that the ideal world consists of object-oriented syntax `x.foo`. Consider the other case where people think first in terms of verbs and APIs, and then put the objects inside no matter their type. That is the power of functional programming. I usually don’t think what I can do with an object `x` in particular, I generalize/standardize common operations to work on any object of that “kind”, and proceed with code that looks generic like `filter(f, x)`, `map(f, x)`, … You don’t even need to know the type of the current object `x` if your code is well-designed and generic in this approach. While programming with Julia you will see that we hardly need to look up APIs because the devs already made their homework to make their types generic according to type traits. They work out of the box with functional style and there is a common set of verbs that you will get used to with time.

One of the nightmares I always had with the object-oriented paradigm was this nightmare that every type and object had a very specific, different set of verbs that I needed to type explicitly in code. That meant that my code never accepted other object types. It was never fully generic.

I do believe, however, that we need tooling for discovery of specific functions from a type/object. But don’t be surprised if someone comes up with an even nicer idea to do this in the near future. Tooling is improving with time now that the language is settling down in the 1.x era.

---

<div class="post-metadata">

**Author:** ![rapus95](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rapus95/32/3773_2.png) [@rapus95](https://discourse.julialang.org/u/rapus95)\
**Post date:** [January 9, 2020, 12:41pm UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/36 "2020-01-09T12:41:54Z")

</div>

Ah damn, I guess I should’ve posted a big fat banner, that I revived the thread 🤔  
TL;DR: I guess he’s not new anymore 😃

---

<div class="post-metadata">

**Author:** ![sashmit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sashmit/32/18791_2.png) [@sashmit](https://discourse.julialang.org/u/sashmit)\
**Post date:** [November 20, 2021, 2:24am UTC](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087/37 "2021-11-20T02:24:14Z")

</div>

It looks like 1.8 will support better discoverability via tab-complete of (x, y): [https://github.com/JuliaLang/julia/pull/38791](https://github.com/JuliaLang/julia/pull/38791)

[Previous page](https://discourse.julialang.org/t/how-to-discover-functions-which-apply-to-a-given-object/21087.md?page=1)
