# Properties on expressions including call arguments, constructors or array indices

**URL:** <https://discourse.julialang.org/t/properties-on-expressions-including-call-arguments-constructors-or-array-indices/52450>\
**Category:** General Usage\
**Tags:** repl\
**Created:** [December 27, 2020, 12:01pm UTC](https://discourse.julialang.org/t/properties-on-expressions-including-call-arguments-constructors-or-array-indices/52450 "2020-12-27T12:01:14Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![Floris](https://avatars.discourse-cdn.com/v4/letter/f/a3d4f5/32.png) [@Floris](https://discourse.julialang.org/u/Floris)\
**Post date:** [December 27, 2020, 12:01pm UTC](https://discourse.julialang.org/t/properties-on-expressions-including-call-arguments-constructors-or-array-indices/52450/1 "2020-12-27T12:01:14Z")

</div>

Hi there, I am new to the Julia community, but since a while I’ve been working on a package to enable _painless_ interaction with COMSOL (commercial finite element software). It relies heavily on java’s reflection API to minimize boilerplate through `getproperty()`, `setproperty()`, etc. Off-topic, but wanted to say and compliment that I am amazed how much you can do with just a few lines of generic julia code.

Currently I am trying to get TAB completion to work to traverse the rather deep COMSOL data structures, but I run into the fact that `propertynames()` only gets called on variables and not on expressions including argument calls, constructors or array indices. In the latter cases, `fieldnames()` is run on the type of the expression.  
This makes the functionallity in the use-case I imagine, less powerful. On the other hand, `getproperty()` does get hit as I expected, so the written code works fine, it is just the tab-completion to help write that code which is off.

This code shows the problem:

```julia
using REPL

struct Pet
    name
end

Base.propertynames(x::Pet) = (:surprise, fieldnames(typeof(x))...)
Base.getproperty(x::Pet, s::Symbol) = s == :surprise ? "You got it." : getfield(x, s)

# Use-cases 
propertynames(Pet("Fluffy")) # returns (:surprise, :name)

mypet = Pet("Fluffy") # tab-completion on "mypet.", works as I hoped
Pet("Fluffy") # tab-completion on "Pet("Fluffy")." only returns .name (does not even call propertynames)
kennel = [mypet] # tab-completion on "kennel[1]." only returns .name (does not even call propertynames)

mypet.surprise # returns "You got it.", works as I hoped
Pet("Fluffy").surprise # returns "You got it.", works as I hoped
kennel[1].surprise # returns "You got it.", works as I hoped

# This helps to dive in deeper:
REPL.REPLCompletions.completions("mypet.",6) # returns tuple including PropertyCompletion-s for :surprise and :name
REPL.REPLCompletions.completions("Pet(\"Fluffy\").",14) # returns tuple including a FieldCompletion for :name
REPL.REPLCompletions.completions("kennel[1].",10) # returns tuple including a FieldCompletion for :name

```

**What is the proper way to get around this and bring the tab-completions in line with the completed expressions?**

The ideas I am currently playing with are:

1. Do my stuff in a `Base.fieldnames(::Type{<:Pet})` definition and use `Base._fieldnames(Pet)` to find the “real” julia fields when needed? So basically, try to get around things.
2. Write a PR for `REPL.REPLCompletions`, that calls on `Base.propertynames(::DataType)` for types instead of `Base.fieldnames(::DataType)` and a PR for Base which just adds `propertynames(x::DataType) = fieldnames(x)` to bring it in line with the variable version.
3. Implement (and PR) some more advanced handling code in `REPL.REPLCompletions`, for instance to handle an element from a container, which seems quite natural extension to me that should lead to `propertynames(x[1])` instead of `fieldnames(typeof(x[1]))`. Using `eval()` it can even be made very general, but I can imagine some boundaries such as on evaluation time need to be imposed.

Looking at the implementation in Base and REPL, it looks like it was done as it is on purpose. But I do feel a bit of a mismatch between handling of variables and types through `propertynames()` and `fieldnames()`. I can imagine that this is done by design, so an explanation on why it needs to be as it is now, would also be very welcome.

P.S. I do realize that these tab-completions and use of data structures retrieved through an OOP-reflection can lead to OOP-style expressions that are non-idiomatic for julia such as: `Pet("Fluffy").surprise` and much worse if multiple levels pile up.  
I still want/need to experiment with these a bit, and see what would be a comfortable solution.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [December 27, 2020, 1:30pm UTC](https://discourse.julialang.org/t/properties-on-expressions-including-call-arguments-constructors-or-array-indices/52450/2 "2020-12-27T13:30:00Z")

</div>

> [@Floris](#):
>
> Currently I am trying to get TAB completion to work to traverse the rather deep COMSOL data structures, but I run into the fact that `propertynames()` only gets called on variables and not on expressions including argument calls, constructors or array indices.

The basic issue is the REPL tab completion currently doesn’t want to execute arbitrary user code. So evaluating variables and struct fields is okay, but calling `getindex` and `getproperty` may be problematic.

---

<div class="post-metadata">

**Author:** ![Floris](https://avatars.discourse-cdn.com/v4/letter/f/a3d4f5/32.png) [@Floris](https://discourse.julialang.org/u/Floris)\
**Post date:** [December 27, 2020, 11:04pm UTC](https://discourse.julialang.org/t/properties-on-expressions-including-call-arguments-constructors-or-array-indices/52450/3 "2020-12-27T23:04:07Z")

</div>

I can understand the hesitation because it seems quite involved. What are the prime reasons for not wanting to execute user code here? Is it performance or are there deeper reasons/consequences?

How would you recommend me to work around this?
