Skip to content

Conversation

@Keno
Copy link
Member

@Keno Keno commented Nov 28, 2025

This implements the suggestion in #53946 (comment) and defines (s::Symbol)(x) = getproperty(x, s). In addition, we define getproperty(::Symbol, ::Symbol) to return the lens object I suggested in #53946. Together this satisfies the requirements I had for #53946 while not requiring any parser changes.

This implements the suggestion in #53946 (comment)
and defined `(s::Symbol)(x) = getproperty(x, s)`. In addition, we
defined `getproperty(::Symbol, ::Symbol)` to return the lens object
I suggested in #53946. Together this satisfies the requirements I
had for #53946 while not requiring any parser changes.
@Keno Keno added the triage This should be discussed on a triage call label Nov 28, 2025
@Keno
Copy link
Member Author

Keno commented Nov 28, 2025

I've played around with this a little bit and I like it. Examples:

julia> :x.(Ref{Int}[1, 2])
2-element Vector{Int64}:
 1
 2

julia> :x.x.(Ref{Ref{Int}}.(Ref{Int}[1, 2]))
2-element Vector{Int64}:
 1
 2

julia> map(:x, Ref{Int}[1, 2])
2-element Vector{Int64}:
 1
 2

julia> map(:x.x, Ref{Ref{Int}}.(Ref{Int}[1, 2]))
2-element Vector{Int64}:
 1
 2

curried form of `getproperty` (equivalently `Fix1(getproperty, s)`).
!!! compat "Julia 1.14"
This behavior feature at least Julia 1.14.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
This behavior feature at least Julia 1.14.
This feature requires at least Julia 1.14.

Constructs a curried accessor for the `s`.`a`.`b` property of some future struct
`s`. This essentially extends the currying-behavior of symbols into nested
hieararchies. See also `(s::Symbol)(obj)`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
hieararchies. See also `(s::Symbol)(obj)`.
hierarchies. See also `(s::Symbol)(obj)`.

@Seelengrab
Copy link
Contributor

Seelengrab commented Nov 28, 2025

julia> map(:x, Ref{Int}[1, 2])
2-element Vector{Int64}:
 1
 2

To me this seems like an extremely odd pun on what map means.

julia> map(:x.x, Ref{Ref{Int}}.(Ref{Int}[1, 2]))
2-element Vector{Int64}:
 1
 2 

Does this mean Symbols are now effectively property lenses?

To be honest, I'm not a fan. The syntax looks very subtle and easy to skip when reading code. The distinction between property access on x and creating a lens is very slim, and even more so when property names get longer.

@jonas-schulze
Copy link
Contributor

One could extend on the single-argument getproperty(syms):

julia> struct GetpropertyLens{N}
           syms::Tuple{Vararg{Symbol, N}}
       end

julia> Base.getproperty(s::Symbol) = GetpropertyLens((s,))

julia> Base.getproperty(syms::Tuple{Vararg{Symbol, N}}) where {N} = GetpropertyLens(syms)

julia> function (lens::GetpropertyLens)(strct)
           syms = getfield(lens, :syms)
           isempty(syms) && return strct
           sym = first(syms)
           return GetpropertyLens(Base.tail(syms))(Base.getproperty(strct, sym))
       end

julia> map(getproperty(:x), Ref{Int}[1, 2])
2-element Vector{Int64}:
 1
 2

julia> map(getproperty((:x, :x)), Ref{Ref{Int}}.(Ref{Int}[1, 2]))
2-element Vector{Int64}:
 1
 2

@Seelengrab, what do you think about this?

@Seelengrab
Copy link
Contributor

@jonas-schulze please see #53946 and the discussions within for proposing more variations on syntax for this feature.

@jonas-schulze
Copy link
Contributor

@jonas-schulze please see #53946 and the discussions within for proposing more variations on syntax for this feature.

I did. My subscription to that issue has brought me here. I simply meant to address your concern by an epsilon modification of what Keno did here. Mind giving feedback (or a mere 👍 / 😕 / 👎 reaction) on my question?

@Keno Keno changed the title WIP: Use (::Symbol) as curred getproperty WIP: Use (::Symbol) as curried getproperty Nov 28, 2025
@Keno
Copy link
Member Author

Keno commented Nov 28, 2025

Does this mean Symbols are now effectively property lenses?

That is the proposal, yes.

@Keno
Copy link
Member Author

Keno commented Nov 28, 2025

One could extend on the single-argument getproperty(syms):

To be clear, while I think this variant is fine, it does not meet my requirements. The whole point is that there needs to be a very short syntax for this, because i want to use it as an accessor.

@Keno
Copy link
Member Author

Keno commented Nov 28, 2025

FWIW, I do agree that it is not necessarily intuitive that Symbol has this call overload, but it does pass my general criteria in that:

  1. I don't think there's any other obvious semantics for this. If you had told me it was implemented and asked me what it did, this is what I would think it did.
  2. In the issue, @JeffBezanson said this is how things work in Clojure - I don't know the language, so I can't comment, but if so, precedent from other languages is always welcome.
  3. Syntactically, I don't have a strong preference between .x.x and :x.x, I just didn't know the latter was available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

triage This should be discussed on a triage call

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants