# Golang-like member functions

**URL:** https://discourse.julialang.org/t/golang-like-member-functions/65254
**Category:** Internals & Design
**Tags:** question, design
**Created:** [July 25, 2021, 7:40am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254 "2021-07-25T07:40:04Z")
**Posts on this page:** 13
**Page:** 1

<div class="post-metadata">

### Author: ![peteole](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peteole/32/209790_2.png) [@peteole](https://discourse.julialang.org/u/peteole)
#### Post date: [July 25, 2021, 7:40am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/1 "2021-07-25T07:40:04Z")

</div>

Hi, I recently found out about the notation for callables:

```julia
function (obj::MyType)(x::Int)
    return obj.mymember*x
end

```

I realized this syntax is extremely similar to the golang and rust-notation for member functions. So we don’t we just make the following possible:

```julia
function (obj::MyType) myMemberFunction(x::Int)
   return obj.mymember*x
end
myObject::MyType=getObjFromSomewhere()
y=myObject.myMemberFunction(6) # y==myObject.myMenber*6

```

I think this would fit extremely well in the language design and enable much more advances packages since it would be possible to add some OOP-patterns which may make sense at some point.  
What do you think about it?

---

<div class="post-metadata">

### Author: ![rfourquet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rfourquet/32/3610_2.png) [@rfourquet](https://discourse.julialang.org/u/rfourquet)
#### Post date: [July 25, 2021, 7:48am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/2 "2021-07-25T07:48:21Z")

</div>

What is the proposed syntax meant to do? (I don’t speak golang).

---

<div class="post-metadata">

### Author: ![peteole](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peteole/32/209790_2.png) [@peteole](https://discourse.julialang.org/u/peteole)
#### Post date: [July 25, 2021, 9:00am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/3 "2021-07-25T09:00:39Z")

</div>

I’m sorry I messed the post up a bit, now it should be clearer. The syntax is intended to define a member function on the Type MyObject. There is another discussion on how to do this today (you add an anonymous function to the struct in the constructor, looks quite messy), but I think this is a very nice to achieve this functionality.

---

<div class="post-metadata">

### Author: ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)
#### Post date: [July 25, 2021, 9:07am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/4 "2021-07-25T09:07:09Z")

</div>

Welcome! Please refer to these two recent previous discussions on this topic:

> [@Allowing the object.method(args...) syntax as an alias for method(object, args ...)](https://discourse.julialang.org/t/allowing-the-object-method-args-syntax-as-an-alias-for-method-object-args/62051):
>
> I started exploring Julia very recently and I like it. I’ve been chatting about it with colleagues. Many people coming from OOP languages (Python…) like the syntax object.method(a,b,c…). Since you can get a preview of the available methods acting on object with tab press. Would it be possible to have that in Julia (I’m assuming it’s not already there) to improve usability? Let say I define a IIR filter struct mutable struct IIRfilter state; alpha; IIRfilter(state,alpha) = 0\<=alpha\<=1 ? …

And

> [@Regarding \`getproperty\` and public vs. private APIs](https://discourse.julialang.org/t/regarding-getproperty-and-public-vs-private-apis/63059):
>
> The syntax x.f calls getproperty which is very widely used. Don’t confuse it with getfield which is the default fallback of getproperty.

Also, please be aware that julia [is not at “that” stage of development anymore](https://discourse.julialang.org/t/psa-julia-is-not-at-that-stage-of-development-anymore/44872). This change would be breaking and thus would only be considered for 2.0 at best (which is unlikely, given that this syntax already means something different and the perceived benefit from this change is not generally seen as enough of a positive change (if positive at all)).

---

<div class="post-metadata">

### Author: ![peteole](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peteole/32/209790_2.png) [@peteole](https://discourse.julialang.org/u/peteole)
#### Post date: [July 25, 2021, 10:08am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/5 "2021-07-25T10:08:06Z")

</div>

Thanks! I see a lot of intelligent people have thought about this for a long time.  
The reason why I suggested this is that I do not see why this proposal should break anything, or what should it collide with?

> [@Sukera](#):
>
> This change would be breaking

A major reason why I think it would be a good idea is (still upcoming) IDE-support as well as type stability: if you have an object and you want to know what you can “do” with that object, its easy to find out in OOP-languages: you type “myObject.” and let the IDE suggest the member functions of the object. In a purely functional approach, it’s not that easy to filter for functions you can call on that object.  
I also realized we are sometimes forced to “abuse” operator overloading to achieve things which should actually be done with member functions: for example Makie uses the “” syntax to get the value of observables, which of course is very compact, but “myObs.val()” is much clearer. I mean there is a reason why we have method names.

---

<div class="post-metadata">

### Author: ![arthy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arthy/32/7654_2.png) [@arthy](https://discourse.julialang.org/u/arthy)
#### Post date: [July 25, 2021, 12:30pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/6 "2021-07-25T12:30:15Z")

</div>

> [@peteole](#):
>
> A major reason why I think it would be a good idea is (still upcoming) IDE-support as well as type stability: if you have an object and you want to know what you can “do” with that object, its easy to find out in OOP-languages: you type “myObject.” and let the IDE suggest the member functions of the object. In a purely functional approach, it’s not that easy to filter for functions you can call on that object.  
> I also realized we are sometimes forced to “abuse” operator overloading to achieve things which should actually be done with member functions: for example Makie uses the “” syntax to get the value of observables, which of course is very compact, but “myObs.val()” is much clearer. I mean there is a reason why we have method names.

I think there’s no extra benefits in terms of IDE support or type stability if you mean syntax changes only. Because having different syntax with the same semantics is no different for compiler or tooling.  
Besides that there’s differences in tooling and IDEs for dynamic and static languages, maybe you are looking for some static languages feature thinking that this feature is OOP feature?

And we are not forced to “abuse” operator overloading, you always can define val(myObs) 🙂

---

<div class="post-metadata">

### Author: ![peteole](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peteole/32/209790_2.png) [@peteole](https://discourse.julialang.org/u/peteole)
#### Post date: [July 25, 2021, 2:39pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/7 "2021-07-25T14:39:11Z")

</div>

> [@arthy](#):
>
> Because having different syntax with the same semantics is no different for compiler or tooling.

Well, once you have written it down, there’s no difference, but your IDE (or julia itself) has more information for suggesting methods to you which can be called on an object: it knows you want to do something with exactly that object. For instance if I type “myServer.” and then press strg+space, any OOP-language-IDE will suggest the methods of a server. If I have a server object in julia and want to do something with it, I have to guess the name of the method using it and see if it really exists. Maybe I even get an error because the method looks like it could accept the “myServer” object, but does not.  
There is already in issue on GitHub for addressing this issue:

> <https://github.com/JuliaLang/julia/pull/38791>
>
> A number of calls to change the language have been justified in part by argument…s for better tab completion. It seems time to separate these issues by improving discoverability in a way that integrates with multiple dispatch. With this PR, \`?(x, y)TAB\` completes methods that can be called with \`(x, y)\`, and \`?(x, yTAB\` (without the closing \`)\`) completes methods called with \`(x, y, ...)\`. There is also limited module-scoping available (only one layer deep).
> 
> An alternative to \`?\` would be to have the cursor positioned where the function name should be supplied.
> 
> I'm happy to discuss changes to this, but depending on whether a couple of other deadlines evaporate I might not have time to make any substantive changes here for a while...so let me say at the outset that I'd be just fine with someone taking this over if desired. Or, it can sit until I get time.
> 
> Demos:
> \`\`\`julia
> julia\> InteractiveUtils.?("hello")\[TAB\]
> apropos(string) in REPL at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/REPL/src/docview.jl:727
> clipboard(x) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/clipboard.jl:60
> code\_llvm(f) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/codeview.jl:178
> code\_native(f) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/codeview.jl:199
> edit(path::AbstractString) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:195
> edit(f) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:223
> eval(x) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/InteractiveUtils.jl:3
> include(x) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/InteractiveUtils.jl:3
> less(file::AbstractString) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:256
> less(f) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:264
> report\_bug(kind) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/InteractiveUtils.jl:385
> separate\_kwargs(args...; kwargs...) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/macros.jl:7
> 
> julia\> InteractiveUtils.?("hello")\[SHIFT-TAB\] # this excludes duck-typed methods
> edit(path::AbstractString) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:195
> less(file::AbstractString) in InteractiveUtils at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/InteractiveUtils/src/editless.jl:256
> 
> julia\> ?(\[1 2; 3 4\], 1, 1)\[SHIFT-TAB\]
> LinRange(start, stop, len::Integer) in Base at range.jl:427
> StepRangeLen(ref::R, step::S, len::Integer) where {R, S} in Base at range.jl:366
> broadcast(f, x::Number...) in Base.Broadcast at broadcast.jl:824
> broadcast(f, avs::Union{Number, LinearAlgebra.Adjoint{T, var"#s828"} where var"#s828"\<:(AbstractVector{T} where T) where T}...) in LinearAlgebra at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/adjtrans.jl:281
> broadcast(f, tvs::Union{Number, LinearAlgebra.Transpose{T, var"#s828"} where var"#s828"\<:(AbstractVector{T} where T) where T}...) in LinearAlgebra at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/LinearAlgebra/src/adjtrans.jl:282
> broadcast(f::Tf, As...) where Tf in Base.Broadcast at broadcast.jl:821
> broadcast!(f::Tf, dest, As::Vararg{Any, N}) where {Tf, N} in Base.Broadcast at broadcast.jl:860
> checkbounds(A::AbstractArray, I...) in Base at abstractarray.jl:608
> circshift!(dest::AbstractArray, src, shiftamt) in Base at multidimensional.jl:1116
> clamp(x::X, lo::L, hi::H) where {X, L, H} in Base.Math at math.jl:65
> clamp!(x::AbstractArray, lo, hi) in Base.Math at math.jl:93
> copyto!(dest::AbstractArray, dstart::Integer, src) in Base at abstractarray.jl:846
> error(s::Vararg{Any, N}) where N in Base at error.jl:40
> fill(v, dims::Union{Integer, AbstractUnitRange}...) in Base at array.jl:449
> get(A::AbstractArray, i::Integer, default) in Base at abstractarray.jl:1411
> getindex(A::Array, i1::Int64, i2::Int64, I::Int64...) in Base at array.jl:788
> getindex(A::Array, i1::Integer, I::Integer...) in Base at abstractarray.jl:1167
> getindex(A::Array, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...) in Base at multidimensional.jl:637
> getindex(A::AbstractArray, I...) in Base at abstractarray.jl:1161
> isassigned(a::Array, i::Int64...) in Base at array.jl:201
> isassigned(a::AbstractArray, i::Integer...) in Base at abstractarray.jl:505
> map(f, x::Number, ys::Number...) in Base at number.jl:238
> mapreduce(f, op, a::Number) in Base at reduce.jl:419
> rand(X, d::Integer, dims::Integer...) in Random at /home/tim/src/julia-master/usr/share/julia/stdlib/v1.7/Random/src/Random.jl:283
> repeat(A::AbstractArray, counts...) in Base at abstractarraymath.jl:223
> reshape(parent::AbstractArray, dims::Int64...) in Base at reshapedarray.jl:116
> reshape(parent::AbstractArray, dims::Union{Int64, AbstractUnitRange}...) in Base at reshapedarray.jl:110
> reshape(parent::AbstractArray, dims::Union{Colon, Int64}...) in Base at reshapedarray.jl:117
> selectdim(A::AbstractArray, d::Integer, i) in Base at abstractarraymath.jl:122
> setindex!(A::Array{T, N} where N, x, i1::Int64) where T in Base at array.jl:825
> setindex!(A::Array, v, i1::Union{Integer, CartesianIndex}, I::Union{Integer, CartesianIndex}...) in Base at multidimensional.jl:639
> setindex!(A::AbstractArray, v, I...) in Base at abstractarray.jl:1258
> similar(a::AbstractArray{T, N} where N, dims::Union{Integer, AbstractUnitRange}...) where T in Base at abstractarray.jl:735
> view(A::AbstractArray, I::Vararg{Any, N}) where N in Base at subarray.jl:164
> \`\`\`
> 
> Closes #30052
> xref #38704
> xref #37993

However I am not sure how well this would work compared to the “old” OOP pattern.

---

<div class="post-metadata">

### Author: ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)
#### Post date: [July 25, 2021, 2:48pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/8 "2021-07-25T14:48:14Z")

</div>

> [@peteole](#):
>
> In a purely functional approach, it’s not that easy to filter for functions you can call on that object.

But this would only cover an extremely tiny fraction of applicable functions, maybe one or two, the vast majority (sometimes hundreds) of which are external.

Having functions/methods that are external to the types is one of the core patterns and key strengths of Julia. Switching to making methods belong to types would basically destroy the language, i fear. It would at least change it beyond recognition, and since class-based oop is an inferior paradigm, I see no significant upside.

---

<div class="post-metadata">

### Author: ![arthy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arthy/32/7654_2.png) [@arthy](https://discourse.julialang.org/u/arthy)
#### Post date: [July 25, 2021, 3:00pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/9 "2021-07-25T15:00:28Z")

</div>

> [@peteole](#):
>
> but your IDE (or julia itself) has more information for suggesting methods to you which can be called on an object: it knows you want to do something with exactly that object. For instance if I type “myServer.” and then press strg+space, any OOP-language-IDE will suggest the methods of a server. If I have a server object in julia and want to do something with it, I have to guess the name of the method using it and see if it really exists. Maybe I even get an error because the method looks like it could accept the “myServer” object, but does not.

But where the additional information comes from? It’s equivalent to `?(myServer, arts)[tab]` completion under Julia semantics. Because `myServer.method(args)` would be no different from `method(myServer, args)`, it’s a purely syntax changes and in both cases IDE knows you want to do something with exactly that object.

---

<div class="post-metadata">

### Author: ![simeonschaub](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/simeonschaub/32/216566_2.png) [@simeonschaub](https://discourse.julialang.org/u/simeonschaub)
#### Post date: [July 25, 2021, 3:18pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/10 "2021-07-25T15:18:41Z")

</div>

> [@arthy](#):
>
> Because `myServer.method(args)` would be no different from `method(myServer, args)` , it’s a purely syntax changes and in both cases IDE knows you want to do something with exactly that object.

`myServer.method(args)` already has a meaning in Julia, namely `getproperty(myServer, :method)(args)` so your proposal would be hugely breaking.

---

<div class="post-metadata">

### Author: ![arthy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/arthy/32/7654_2.png) [@arthy](https://discourse.julialang.org/u/arthy)
#### Post date: [July 25, 2021, 3:27pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/11 "2021-07-25T15:27:07Z")

</div>

I’m not proposing this change, actually I’m arguing that this change would not bring any benefits for discoverability not to mention other problems this proposal would raise

---

<div class="post-metadata">

### Author: ![peteole](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/peteole/32/209790_2.png) [@peteole](https://discourse.julialang.org/u/peteole)
#### Post date: [July 25, 2021, 5:17pm UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/12 "2021-07-25T17:17:49Z")

</div>

> [@simeonschaub](#):
>
> `myServer.method(args)` already has a meaning in Julia, namely `getproperty(myServer, :method)(args)` so your proposal would be hugely breaking.

Well I think it’s not breaking in the sense that, as long as the old meaning you described keeps working, all code will keep working since the old code would not use the new syntax. However you convinced me that it’s probably a bad idea to implement my proposal since there would need to be a way to decide whether the “existing” or “proposed” syntax is meant when you write “obj.myFunction()”, which should be possible but adds unnecessary complexity and confusion.

---

<div class="post-metadata">

### Author: ![gustaphe](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/gustaphe/32/18174_2.png) [@gustaphe](https://discourse.julialang.org/u/gustaphe)
#### Post date: [July 27, 2021, 7:30am UTC](https://discourse.julialang.org/t/golang-like-member-functions/65254/13 "2021-07-27T07:30:58Z")

</div>

> [@peteole](#):
>
> there would need to be a way to decide whether the “existing” or “proposed” syntax is meant when you write “obj.myFunction()”, which should be possible but adds unnecessary complexity and confusion

This sounds pretty close to the definition of “breaking”
