# \[ANN\] DotCall.jl OOP-like dot notation

**URL:** <https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402>\
**Category:** Package Announcements\
**Tags:** announcement\
**Created:** [November 8, 2024, 1:36am UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402 "2024-11-08T01:36:27Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 1:36am UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/1 "2024-11-08T01:36:27Z")

</div>

[DotCall.jl](https://github.com/jlapeyre/DotCall.jl) lets you call methods as `x.f()` rather than `f(x)`. It was registered a few weeks ago.

This is an old (2 or 3 years) package, with a new, more descriptive name. And a couple of minor fixes.

[EDIT: simplified example in originial post]

```julia
julia> using DotCall;
julia> DotCall.@dotcallify Vector (map=(v, f) -> map(f, v),);
julia> [-1,1].map(abs)
2-element Vector{Int64}:
 1
 1

```

This package is related to a lot of the discussion in [the OOP-Like Dot Notation post](https://discourse.julialang.org/t/oop-like-dot-notation-in-julia/120971). But it’s probably not the best solution if your main concern is discoverability and would like it to be applied everywhere possible.

I haven’t found time recently to explore it, for example chained calls, as much as I would like.

---

<div class="post-metadata">

**Author:** ![DanielVandH](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/danielvandh/32/31134_2.png) [@DanielVandH](https://discourse.julialang.org/u/DanielVandH)\
**Post date:** [November 8, 2024, 9:40am UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/2 "2024-11-08T09:40:21Z")

</div>

Why is `@eval` needed in your examples?

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 12:58pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/3 "2024-11-08T12:58:47Z")

</div>

Turns out it’s not (at least in Julia 1.11). I _did_ run into examples a few weeks ago that did not work until I used `@eval`. But this is not one of them. I’m a bit puzzled because it took me a while to find a solution (to whatever it was) using `@eval`. And I pulled the example from my REPL history.

I’ve edited the original post above to remove `@eval`.

`DotCall.jl` was somewhat complicated by the time it got the desired behavior. I might re-read it and add some comments. The development worked like this:

I was mentoring someone who wanted to use this oop dot call thing (I wish there were a good word for it) with a `struct`. Their solution was like this:

```julia
julia> struct A f end;
julia> a = A(() -> 1);
julia> a.f()
1

```

Except the `struct` was `mutable` and had a lot of data fields and maybe 20 functions `x`, `y`, `z`, `cx`, etc. It was a stripped-down translation of a Python class defined over 6500 LOC.

Among the disadvantages to this approach are: The runtime performance of calling methods this way was very slow. And each instance has to store at least an alias to the function.

My first attempt at `DotCall` worked ok. But calling methods was not performant (maybe because of runtime dispatch). The current version of `DotCall` has these advantanges:

- If a method and a `struct` are defined in a module, the method can be called without importing the method. For example you can call `a.x()`, without importing `x`.
- There is no runtime penalty
- TAB completion works. So you get this basic level of discoverability.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 2:38pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/4 "2024-11-08T14:38:58Z")

</div>

In case it’s not obvious, mucking with `Vector` this way is good for experimenting, but is [dangerous](https://github.com/jlapeyre/DotCall.jl/issues/7#issuecomment-2464868054).

For example, If you make a PR to say, OrdinaryDiffEq.jl, with this

```julia
DotCall.@dotcallify Vector (map=(v, f) -> map(f, v),);

```

you’ll have a (very) hard time getting it merged.

---

<div class="post-metadata">

**Author:** ![jwortmann](https://avatars.discourse-cdn.com/v4/letter/j/eada6e/32.png) [@jwortmann](https://discourse.julialang.org/u/jwortmann)\
**Post date:** [November 8, 2024, 2:39pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/5 "2024-11-08T14:39:15Z")

</div>

> [@jlapeyre](#):
>
> this oop dot call thing (I wish there were a good word for it)

I think the “official” term which looks appropriate here would be

> **[Uniform Function Call Syntax](https://en.wikipedia.org/wiki/Uniform_Function_Call_Syntax)**
>
> Uniform Function Call Syntax (UFCS) or Uniform Call Syntax (UCS) or sometimes Universal Function Call Syntax is a programming language feature in D, Nim, Rust, Koka, and Effekt that allows any function to be called using the syntax for method calls (as in object-oriented programming), by using the receiver as the first parameter and the given arguments as the remaining parameters. The same technique is used in the AviSynth scripting language under the name "OOP notation".
> UFCS is particularly us...

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 2:41pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/6 "2024-11-08T14:41:08Z")

</div>

The problem is that it’s not uniform here. It’s not uniform in c++ or Python, either.

Maybe “Nonuniform Function call Syntax”. Yeah that’s it. NUFCS — “nuffcks”

---

<div class="post-metadata">

**Author:** ![jwortmann](https://avatars.discourse-cdn.com/v4/letter/j/eada6e/32.png) [@jwortmann](https://discourse.julialang.org/u/jwortmann)\
**Post date:** [November 8, 2024, 2:52pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/7 "2024-11-08T14:52:11Z")

</div>

As far as I understand from the Wikipedia article, the “uniform” stands for that the notation `a.foo(b)` can be used for _all_ functions, i.e. not only methods which are defined in classes/objects, but also free (global) functions. For that latter case this syntax is converted to `foo(a, b)`. This is indeed not supported by C++ or Pyhton. And frankly Julia doesn’t have member methods in the OOP sense, but it looks like this syntax conversion is exactly what you do in DotCall.jl (no intention to debate your name choice).

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 3:04pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/8 "2024-11-08T15:04:14Z")

</div>

I understood “uniform” to mean all functions get this out of the box, like in Nim. Not only those that you choose.

But the discussions around C++ seem to agree with how you are interpreting UFCS:

> proposed a Uniform Calling Syntax (UCS), allowing specially annotated free functions to be called with member function notation

From the beginning, I discarded using UFCS as a term to even talk about this because I thought “everywhere, all the time” was a necessary condition. But I can see why you don’t suggest changing the package name. UFCS.jl is pretty bad.

---

<div class="post-metadata">

**Author:** ![jwortmann](https://avatars.discourse-cdn.com/v4/letter/j/eada6e/32.png) [@jwortmann](https://discourse.julialang.org/u/jwortmann)\
**Post date:** [November 8, 2024, 3:45pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/9 "2024-11-08T15:45:34Z")

</div>

> [@jlapeyre](#):
>
> I understood “uniform” to mean all functions get this out of the box, like in Nim. Not only those that you choose.

Yeah I agree it’s somewhat ambiguous. I haven’t looked too close at your package yet, but have you considered to implement it that way, i.e. the user puts only `using DotCall` at the top of their package/script and it would work automatically for all functions? That would probably be better suited to be implemented in a separate new package then, but I imagine that it would be simpler from the usage perspective. I can’t think of a good use case where you want to make this syntax possible only for _some_ functions. But if I understand your comment [[ANN] DotCall.jl OOP-like dot notation - #4 by jlapeyre](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/4) correctly, it might be bad or not possible in all cases?

* * *

As the primary advantage is the autocompletion when typing the dot, I guess the next step could be to push for support in the language server. There already seems to be a related PR at [dot methods completion by xgdgsc · Pull Request #1210 · julia-vscode/LanguageServer.jl · GitHub](https://github.com/julia-vscode/LanguageServer.jl/pull/1210) which even automatically does the syntax conversion, but it is dying a slow death without any reviews.

---

<div class="post-metadata">

**Author:** ![jlapeyre](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jlapeyre/32/4514_2.png) [@jlapeyre](https://discourse.julialang.org/u/jlapeyre)\
**Post date:** [November 8, 2024, 5:47pm UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/10 "2024-11-08T17:47:20Z")

</div>

> [@jwortmann](#):
>
> the user puts only `using DotCall` at the top of their package/script and it would work automatically for all functions?

This is not something I’d work on implementing at the moment.

- If you do this to functions outside your module it’s piracy, at least in spirit, and probably in letter.
- For example, to dotcallify `map(f, ::MyStruct)` I rewrite (if I recall correctly!) some functions dealing with properties and fields for `map`.
- I’d need logic (reliable logic) to determine where functions and types are defined to know where I can and cannot apply it.
- Currently doing dotcall for `map(f, ::AbstractVector)` causes a segfault. I’m pretty sure it’s a bug in `DotCall` that’s not hard to fix. But there will others; they could be serious as well.
- I make a choice that, for `map`, the second argument is special, not the first. I think getting a heuristic for deciding this would be difficult.
- There are some big recompilation (invalidation probably) penalites. This could perhaps be mitigated. Even if it can be, it likely would take some work. I haven’t measured how much of a problem this is in the context of a package.

I’m thinking DotCall could be useful for trying ideas, or the ergonomics of chaining method calls. Or similar things. Or maybe it would make it easier to use a particular type in a particular package. At the moment, it doesn’t seem much of a burden to use (compared to all the magic you’d have to implement to make it automatic). If people really wanted to use it in packages, then sure it would be worth considering.

I think the namespace advantage is a big one. But I don’t like the idea of importing tons of symbols willy-nilly. I’m sure many people don’t mind that `using APackage` imports function `x`. Just avoid naming other things `x`.

My guess is that if the only thing you want is discoverability and completion and things like that, it’s better to put that in the LanguageServer or similar tooling. And don’t mess with the semantics of the language itself. Of course you’d also want to implement something for the REPL as well.

OTOH, an advantage of `DotCall` is that you don’t do `x.af[TAB]` to get methods on `x` that start with `af` only to have it rewritten into your code as `afunc(x)`. This is apparently what the PR you referenced does.

EDIT: You could possibly do tricks like define a new function named `map` in your module and have it call `Base.map`. This might avoid piracy and possible long-range bugs. This would be opaque to the user.

---

<div class="post-metadata">

**Author:** ![hatmatrix](https://avatars.discourse-cdn.com/v4/letter/h/5f8ce5/32.png) [@hatmatrix](https://discourse.julialang.org/u/hatmatrix)\
**Post date:** [November 12, 2024, 7:54am UTC](https://discourse.julialang.org/t/ann-dotcall-jl-oop-like-dot-notation/122402/11 "2024-11-12T07:54:25Z")

</div>

R calls this form of OOP “[Reference Classes](http://adv-r.had.co.nz/R5.html)”
